blob: 883b71c4fc08f9476dc86bc90e705bc371fc6a4a [file] [log] [blame]
Sharon Yangfbb9ba4a2019-11-18 23:59:561// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <fuchsia/accessibility/semantics/cpp/fidl.h>
6#include <fuchsia/accessibility/semantics/cpp/fidl_test_base.h>
7#include <lib/sys/cpp/component_context.h>
8#include <lib/ui/scenic/cpp/view_token_pair.h>
9#include <zircon/types.h>
10
Sharon Yangaa2c9bd2019-11-21 17:59:2211#include "base/auto_reset.h"
Sharon Yangfbb9ba4a2019-11-18 23:59:5612#include "base/fuchsia/default_context.h"
13#include "base/fuchsia/scoped_service_binding.h"
14#include "base/fuchsia/service_directory_client.h"
15#include "base/logging.h"
16#include "base/test/bind_test_util.h"
17#include "content/public/browser/web_contents_observer.h"
18#include "fuchsia/base/frame_test_util.h"
Sharon Yangfbb9ba4a2019-11-18 23:59:5619#include "fuchsia/base/test_navigation_listener.h"
20#include "fuchsia/engine/browser/accessibility_bridge.h"
21#include "fuchsia/engine/browser/frame_impl.h"
22#include "fuchsia/engine/test/test_data.h"
23#include "fuchsia/engine/test/web_engine_browser_test.h"
24#include "net/test/embedded_test_server/embedded_test_server.h"
25#include "testing/gtest/include/gtest/gtest.h"
26
27using fuchsia::accessibility::semantics::Node;
28using fuchsia::accessibility::semantics::SemanticListener;
29using fuchsia::accessibility::semantics::SemanticsManager;
30using fuchsia::accessibility::semantics::SemanticTree;
31
32namespace {
33
34const char kPage1Path[] = "/ax1.html";
35const char kPage2Path[] = "/batching.html";
36const char kPage1Title[] = "accessibility 1";
37const char kPage2Title[] = "lots of nodes!";
38const char kButtonName[] = "a button";
39const char kNodeName[] = "last node";
40const char kParagraphName[] = "a third paragraph";
Sharon Yangaa2c9bd2019-11-21 17:59:2241const size_t kPage1NodeCount = 9;
42const size_t kPage2NodeCount = 190;
Sharon Yangfbb9ba4a2019-11-18 23:59:5643
44class FakeSemanticTree
45 : public fuchsia::accessibility::semantics::testing::SemanticTree_TestBase {
46 public:
47 FakeSemanticTree() = default;
48 ~FakeSemanticTree() override = default;
49
50 // fuchsia::accessibility::semantics::SemanticTree implementation.
51 void UpdateSemanticNodes(std::vector<Node> nodes) final {
52 for (auto& node : nodes)
53 nodes_.push_back(std::move(node));
54 }
55
56 void DeleteSemanticNodes(std::vector<uint32_t> node_ids) final {
57 for (auto id : node_ids) {
58 for (uint i = 0; i < nodes_.size(); i++) {
59 if (nodes_.at(i).node_id() == id)
60 nodes_.erase(nodes_.begin() + i);
61 }
62 }
63 }
64
65 void CommitUpdates(CommitUpdatesCallback callback) final {
66 callback();
67 if (on_commit_updates_)
Sharon Yangaa2c9bd2019-11-21 17:59:2268 on_commit_updates_.Run();
Sharon Yangfbb9ba4a2019-11-18 23:59:5669 }
70
71 void NotImplemented_(const std::string& name) final {
72 NOTIMPLEMENTED() << name;
73 }
74
75 void RunUntilNodeCountAtLeast(size_t count) {
76 DCHECK(!on_commit_updates_);
Sharon Yangfbb9ba4a2019-11-18 23:59:5677 if (nodes_.size() >= count)
78 return;
79
Sharon Yangaa2c9bd2019-11-21 17:59:2280 base::RunLoop run_loop;
81 base::AutoReset<base::RepeatingClosure> auto_reset(
82 &on_commit_updates_,
83 base::BindLambdaForTesting([this, count, &run_loop]() {
84 if (nodes_.size() >= count) {
85 run_loop.Quit();
86 }
87 }));
88 run_loop.Run();
Sharon Yangfbb9ba4a2019-11-18 23:59:5689 }
90
91 bool HasNodeWithLabel(base::StringPiece name) {
92 for (auto& node : nodes_) {
93 if (node.has_attributes() && node.attributes().has_label() &&
94 node.attributes().label() == name) {
95 return true;
96 }
97 }
98 return false;
99 }
100
101 private:
102 std::vector<Node> nodes_;
Sharon Yangaa2c9bd2019-11-21 17:59:22103 base::RepeatingClosure on_commit_updates_;
Sharon Yangfbb9ba4a2019-11-18 23:59:56104
105 DISALLOW_COPY_AND_ASSIGN(FakeSemanticTree);
106};
107
108class FakeSemanticsManager : public fuchsia::accessibility::semantics::testing::
109 SemanticsManager_TestBase {
110 public:
111 FakeSemanticsManager() : semantic_tree_binding_(&semantic_tree_) {}
112 ~FakeSemanticsManager() override = default;
113
114 bool is_view_registered() const { return view_ref_.reference.is_valid(); }
115 bool is_listener_valid() const { return static_cast<bool>(listener_); }
116 FakeSemanticTree* semantic_tree() { return &semantic_tree_; }
117
118 // Directly call the listener to simulate Fuchsia setting the semantics mode.
119 void SetSemanticsModeEnabled(bool is_enabled) {
120 listener_->OnSemanticsModeChanged(is_enabled, []() {});
121 }
122
123 // fuchsia::accessibility::semantics::SemanticsManager implementation.
124 void RegisterViewForSemantics(
125 fuchsia::ui::views::ViewRef view_ref,
126 fidl::InterfaceHandle<SemanticListener> listener,
127 fidl::InterfaceRequest<SemanticTree> semantic_tree_request) final {
128 view_ref_ = std::move(view_ref);
129 listener_ = listener.Bind();
130 semantic_tree_binding_.Bind(std::move(semantic_tree_request));
131 }
132
133 void NotImplemented_(const std::string& name) final {
134 NOTIMPLEMENTED() << name;
135 }
136
137 private:
138 fuchsia::ui::views::ViewRef view_ref_;
139 fuchsia::accessibility::semantics::SemanticListenerPtr listener_;
140 FakeSemanticTree semantic_tree_;
141 fidl::Binding<SemanticTree> semantic_tree_binding_;
142
143 DISALLOW_COPY_AND_ASSIGN(FakeSemanticsManager);
144};
145
146} // namespace
147
148class AccessibilityBridgeTest : public cr_fuchsia::WebEngineBrowserTest {
149 public:
150 AccessibilityBridgeTest() : semantics_manager_binding_(&semantics_manager_) {
151 cr_fuchsia::WebEngineBrowserTest::set_test_server_root(
152 base::FilePath(cr_fuchsia::kTestServerRoot));
153 }
154
155 ~AccessibilityBridgeTest() override = default;
156
157 void SetUpOnMainThread() override {
158 fuchsia::accessibility::semantics::SemanticsManagerPtr
159 semantics_manager_ptr;
160 semantics_manager_binding_.Bind(semantics_manager_ptr.NewRequest());
161
162 frame_ptr_ =
163 cr_fuchsia::WebEngineBrowserTest::CreateFrame(&navigation_listener_);
164 frame_impl_ = context_impl()->GetFrameImplForTest(&frame_ptr_);
165 frame_impl_->set_semantics_manager_for_test(
166 std::move(semantics_manager_ptr));
167
168 // Call CreateView to trigger creation of accessibility bridge.
169 auto view_tokens = scenic::NewViewTokenPair();
170 frame_ptr_->CreateView(std::move(view_tokens.first));
171 base::RunLoop().RunUntilIdle();
172 }
173
174 protected:
175 fuchsia::web::FramePtr frame_ptr_;
176 FrameImpl* frame_impl_;
177 FakeSemanticsManager semantics_manager_;
178 fidl::Binding<SemanticsManager> semantics_manager_binding_;
179 cr_fuchsia::TestNavigationListener navigation_listener_;
180
181 DISALLOW_COPY_AND_ASSIGN(AccessibilityBridgeTest);
182};
183
184// Test registration to the SemanticsManager and accessibility mode on
185// WebContents is set correctly.
186IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, RegisterViewRef) {
187 // Check that setup is successful.
188 EXPECT_TRUE(semantics_manager_.is_view_registered());
189 EXPECT_TRUE(semantics_manager_.is_listener_valid());
190
191 // Change the accessibility mode on the Fuchsia side and check that it is
192 // propagated correctly.
193 EXPECT_FALSE(frame_impl_->web_contents_for_test()
194 ->IsWebContentsOnlyAccessibilityModeForTesting());
195 semantics_manager_.SetSemanticsModeEnabled(true);
196 base::RunLoop().RunUntilIdle();
197 EXPECT_TRUE(frame_impl_->web_contents_for_test()
198 ->IsWebContentsOnlyAccessibilityModeForTesting());
199}
200
201IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, CorrectDataSent) {
202 fuchsia::web::NavigationControllerPtr controller;
203 frame_ptr_->GetNavigationController(controller.NewRequest());
204 ASSERT_TRUE(embedded_test_server()->Start());
205 GURL title1(embedded_test_server()->GetURL(kPage1Path));
206
207 semantics_manager_.SetSemanticsModeEnabled(true);
208 EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
209 controller.get(), fuchsia::web::LoadUrlParams(), title1.spec()));
210 navigation_listener_.RunUntilUrlAndTitleEquals(title1, kPage1Title);
211
212 // Check that the data values are correct in the FakeSemanticTree.
213 // TODO(fxb/18796): Test more fields once Chrome to Fuchsia conversions are
214 // available.
215 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
216 EXPECT_TRUE(
217 semantics_manager_.semantic_tree()->HasNodeWithLabel(kPage1Title));
218 EXPECT_TRUE(
219 semantics_manager_.semantic_tree()->HasNodeWithLabel(kButtonName));
220 EXPECT_TRUE(
221 semantics_manager_.semantic_tree()->HasNodeWithLabel(kParagraphName));
222}
223
224// Batching is performed when the number of nodes to send or delete exceeds the
225// maximum, as set on the Fuchsia side. Check that all nodes are received by the
226// Semantic Tree when batching is performed.
227IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, DataSentWithBatching) {
228 fuchsia::web::NavigationControllerPtr controller;
229 frame_ptr_->GetNavigationController(controller.NewRequest());
230 ASSERT_TRUE(embedded_test_server()->Start());
231 GURL title2(embedded_test_server()->GetURL(kPage2Path));
232
233 semantics_manager_.SetSemanticsModeEnabled(true);
234 EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
235 controller.get(), fuchsia::web::LoadUrlParams(), title2.spec()));
236 navigation_listener_.RunUntilUrlAndTitleEquals(title2, kPage2Title);
237
238 // Run until we expect more than a batch's worth of nodes to be present.
239 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage2NodeCount);
240 EXPECT_TRUE(semantics_manager_.semantic_tree()->HasNodeWithLabel(kNodeName));
241}
242
243// Check that semantics information is correctly sent when navigating from page
244// to page.
245IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, TestNavigation) {
246 fuchsia::web::NavigationControllerPtr controller;
247 frame_ptr_->GetNavigationController(controller.NewRequest());
248 ASSERT_TRUE(embedded_test_server()->Start());
249 GURL title1(embedded_test_server()->GetURL(kPage1Path));
250
251 semantics_manager_.SetSemanticsModeEnabled(true);
252 EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
253 controller.get(), fuchsia::web::LoadUrlParams(), title1.spec()));
254 navigation_listener_.RunUntilUrlAndTitleEquals(title1, kPage1Title);
255
256 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
257 EXPECT_TRUE(
258 semantics_manager_.semantic_tree()->HasNodeWithLabel(kPage1Title));
259 EXPECT_TRUE(
260 semantics_manager_.semantic_tree()->HasNodeWithLabel(kButtonName));
261 EXPECT_TRUE(
262 semantics_manager_.semantic_tree()->HasNodeWithLabel(kParagraphName));
263
264 GURL title2(embedded_test_server()->GetURL(kPage2Path));
265 EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
266 controller.get(), fuchsia::web::LoadUrlParams(), title2.spec()));
267
268 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage2NodeCount);
269 EXPECT_TRUE(semantics_manager_.semantic_tree()->HasNodeWithLabel(kNodeName));
270}