blob: e78b3304f20b8368412819fc45db9c332de7f3a2 [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>
Sharon Yang8b548ab92019-12-20 01:52:546#include <lib/ui/scenic/cpp/view_ref_pair.h>
Sharon Yangfbb9ba4a2019-11-18 23:59:567#include <zircon/types.h>
8
Peter Kasting919ce652020-05-07 10:22:369#include "content/public/test/browser_test.h"
Sharon Yangfbb9ba4a2019-11-18 23:59:5610#include "fuchsia/base/frame_test_util.h"
Sharon Yangfbb9ba4a2019-11-18 23:59:5611#include "fuchsia/base/test_navigation_listener.h"
12#include "fuchsia/engine/browser/accessibility_bridge.h"
Sharon Yangd0d86f42020-07-11 15:38:5313#include "fuchsia/engine/browser/fake_semantics_manager.h"
Sharon Yangfbb9ba4a2019-11-18 23:59:5614#include "fuchsia/engine/browser/frame_impl.h"
15#include "fuchsia/engine/test/test_data.h"
16#include "fuchsia/engine/test/web_engine_browser_test.h"
17#include "net/test/embedded_test_server/embedded_test_server.h"
18#include "testing/gtest/include/gtest/gtest.h"
Sharon Yang8b548ab92019-12-20 01:52:5419#include "ui/gfx/switches.h"
20#include "ui/ozone/public/ozone_switches.h"
Sharon Yangfbb9ba4a2019-11-18 23:59:5621
Sharon Yangfbb9ba4a2019-11-18 23:59:5622namespace {
23
24const char kPage1Path[] = "/ax1.html";
25const char kPage2Path[] = "/batching.html";
26const char kPage1Title[] = "accessibility 1";
27const char kPage2Title[] = "lots of nodes!";
Sharon Yang5fb4ce22020-02-08 00:45:2128const char kButtonName1[] = "a button";
29const char kButtonName2[] = "another button";
30const char kButtonName3[] = "button 3";
Sharon Yangfbb9ba4a2019-11-18 23:59:5631const char kNodeName[] = "last node";
32const char kParagraphName[] = "a third paragraph";
Sharon Yangaa2c9bd2019-11-21 17:59:2233const size_t kPage1NodeCount = 9;
34const size_t kPage2NodeCount = 190;
Sharon Yangfbb9ba4a2019-11-18 23:59:5635
Sharon Yangfbb9ba4a2019-11-18 23:59:5636
Sharon Yang8b548ab92019-12-20 01:52:5437fuchsia::math::PointF GetCenterOfBox(fuchsia::ui::gfx::BoundingBox box) {
38 fuchsia::math::PointF center;
39 center.x = (box.min.x + box.max.x) / 2;
40 center.y = (box.min.y + box.max.y) / 2;
41 return center;
42}
43
Sharon Yangfbb9ba4a2019-11-18 23:59:5644} // namespace
45
46class AccessibilityBridgeTest : public cr_fuchsia::WebEngineBrowserTest {
47 public:
48 AccessibilityBridgeTest() : semantics_manager_binding_(&semantics_manager_) {
49 cr_fuchsia::WebEngineBrowserTest::set_test_server_root(
50 base::FilePath(cr_fuchsia::kTestServerRoot));
51 }
52
53 ~AccessibilityBridgeTest() override = default;
54
Sharon Yangd0d86f42020-07-11 15:38:5355 AccessibilityBridgeTest(const AccessibilityBridgeTest&) = delete;
56 AccessibilityBridgeTest& operator=(const AccessibilityBridgeTest&) = delete;
57
Sharon Yang8b548ab92019-12-20 01:52:5458 void SetUp() override {
59 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
60 command_line->AppendSwitchNative(switches::kOzonePlatform,
61 switches::kHeadless);
62 command_line->AppendSwitch(switches::kHeadless);
63 cr_fuchsia::WebEngineBrowserTest::SetUp();
64 }
65
Sharon Yangfbb9ba4a2019-11-18 23:59:5666 void SetUpOnMainThread() override {
67 fuchsia::accessibility::semantics::SemanticsManagerPtr
68 semantics_manager_ptr;
69 semantics_manager_binding_.Bind(semantics_manager_ptr.NewRequest());
70
71 frame_ptr_ =
72 cr_fuchsia::WebEngineBrowserTest::CreateFrame(&navigation_listener_);
73 frame_impl_ = context_impl()->GetFrameImplForTest(&frame_ptr_);
74 frame_impl_->set_semantics_manager_for_test(
75 std::move(semantics_manager_ptr));
Sharon Yang8b548ab92019-12-20 01:52:5476 frame_ptr_->EnableHeadlessRendering();
Sharon Yangfbb9ba4a2019-11-18 23:59:5677
Wez19de8b522020-01-28 20:50:0478 semantics_manager_.WaitUntilViewRegistered();
79 ASSERT_TRUE(semantics_manager_.is_view_registered());
80 ASSERT_TRUE(semantics_manager_.is_listener_valid());
Sharon Yang1dd8b6db32020-04-10 23:10:1881
82 frame_ptr_->GetNavigationController(navigation_controller_.NewRequest());
83 ASSERT_TRUE(embedded_test_server()->Start());
84 semantics_manager_.SetSemanticsModeEnabled(true);
Sharon Yangfbb9ba4a2019-11-18 23:59:5685 }
86
87 protected:
88 fuchsia::web::FramePtr frame_ptr_;
89 FrameImpl* frame_impl_;
90 FakeSemanticsManager semantics_manager_;
Sharon Yangd0d86f42020-07-11 15:38:5391 fidl::Binding<fuchsia::accessibility::semantics::SemanticsManager>
92 semantics_manager_binding_;
Sharon Yangfbb9ba4a2019-11-18 23:59:5693 cr_fuchsia::TestNavigationListener navigation_listener_;
Sharon Yang1dd8b6db32020-04-10 23:10:1894 fuchsia::web::NavigationControllerPtr navigation_controller_;
Sharon Yangfbb9ba4a2019-11-18 23:59:5695};
96
97// Test registration to the SemanticsManager and accessibility mode on
98// WebContents is set correctly.
99IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, RegisterViewRef) {
Sharon Yangfbb9ba4a2019-11-18 23:59:56100 // Change the accessibility mode on the Fuchsia side and check that it is
101 // propagated correctly.
Wez19de8b522020-01-28 20:50:04102 ASSERT_FALSE(frame_impl_->web_contents_for_test()
Sharon Yangfbb9ba4a2019-11-18 23:59:56103 ->IsWebContentsOnlyAccessibilityModeForTesting());
104 semantics_manager_.SetSemanticsModeEnabled(true);
Wez19de8b522020-01-28 20:50:04105
106 // Spin the loop to let the FrameImpl receive the mode-change.
Sharon Yangfbb9ba4a2019-11-18 23:59:56107 base::RunLoop().RunUntilIdle();
Wez19de8b522020-01-28 20:50:04108
Sharon Yangfbb9ba4a2019-11-18 23:59:56109 EXPECT_TRUE(frame_impl_->web_contents_for_test()
110 ->IsWebContentsOnlyAccessibilityModeForTesting());
111}
112
113IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, CorrectDataSent) {
Sharon Yang1dd8b6db32020-04-10 23:10:18114 GURL page_url(embedded_test_server()->GetURL(kPage1Path));
Wez19de8b522020-01-28 20:50:04115 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
Sharon Yang1dd8b6db32020-04-10 23:10:18116 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
117 page_url.spec()));
118 navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage1Title);
Sharon Yangfbb9ba4a2019-11-18 23:59:56119
120 // Check that the data values are correct in the FakeSemanticTree.
121 // TODO(fxb/18796): Test more fields once Chrome to Fuchsia conversions are
122 // available.
123 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
124 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15125 semantics_manager_.semantic_tree()->GetNodeFromLabel(kPage1Title));
Sharon Yangfbb9ba4a2019-11-18 23:59:56126 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15127 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1));
Sharon Yangfbb9ba4a2019-11-18 23:59:56128 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15129 semantics_manager_.semantic_tree()->GetNodeFromLabel(kParagraphName));
Sharon Yangfbb9ba4a2019-11-18 23:59:56130}
131
132// Batching is performed when the number of nodes to send or delete exceeds the
133// maximum, as set on the Fuchsia side. Check that all nodes are received by the
134// Semantic Tree when batching is performed.
135IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, DataSentWithBatching) {
Sharon Yang1dd8b6db32020-04-10 23:10:18136 GURL page_url(embedded_test_server()->GetURL(kPage2Path));
Wez19de8b522020-01-28 20:50:04137 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
Sharon Yang1dd8b6db32020-04-10 23:10:18138 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
139 page_url.spec()));
140 navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage2Title);
Sharon Yangfbb9ba4a2019-11-18 23:59:56141
142 // Run until we expect more than a batch's worth of nodes to be present.
143 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage2NodeCount);
Sharon Yangfb25b4a2020-02-10 23:50:15144 EXPECT_TRUE(semantics_manager_.semantic_tree()->GetNodeFromLabel(kNodeName));
Sharon Yangfbb9ba4a2019-11-18 23:59:56145}
146
147// Check that semantics information is correctly sent when navigating from page
148// to page.
149IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, TestNavigation) {
Sharon Yang8b548ab92019-12-20 01:52:54150 GURL page_url1(embedded_test_server()->GetURL(kPage1Path));
Wez19de8b522020-01-28 20:50:04151 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
Sharon Yang1dd8b6db32020-04-10 23:10:18152 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
153 page_url1.spec()));
Sharon Yang8b548ab92019-12-20 01:52:54154 navigation_listener_.RunUntilUrlAndTitleEquals(page_url1, kPage1Title);
Sharon Yangfbb9ba4a2019-11-18 23:59:56155
156 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
157 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15158 semantics_manager_.semantic_tree()->GetNodeFromLabel(kPage1Title));
Sharon Yangfbb9ba4a2019-11-18 23:59:56159 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15160 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1));
Sharon Yangfbb9ba4a2019-11-18 23:59:56161 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15162 semantics_manager_.semantic_tree()->GetNodeFromLabel(kParagraphName));
Sharon Yangfbb9ba4a2019-11-18 23:59:56163
Sharon Yang8b548ab92019-12-20 01:52:54164 GURL page_url2(embedded_test_server()->GetURL(kPage2Path));
Wez19de8b522020-01-28 20:50:04165 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
Sharon Yang1dd8b6db32020-04-10 23:10:18166 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
167 page_url2.spec()));
Sharon Yangfbb9ba4a2019-11-18 23:59:56168
169 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage2NodeCount);
Sharon Yangca616422019-12-18 23:52:39170 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15171 semantics_manager_.semantic_tree()->GetNodeFromLabel(kPage2Title));
172 EXPECT_TRUE(semantics_manager_.semantic_tree()->GetNodeFromLabel(kNodeName));
Sharon Yangca616422019-12-18 23:52:39173
174 // Check that data from the first page has been deleted successfully.
175 EXPECT_FALSE(
Sharon Yangfb25b4a2020-02-10 23:50:15176 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1));
Sharon Yangca616422019-12-18 23:52:39177 EXPECT_FALSE(
Sharon Yangfb25b4a2020-02-10 23:50:15178 semantics_manager_.semantic_tree()->GetNodeFromLabel(kParagraphName));
Sharon Yangfbb9ba4a2019-11-18 23:59:56179}
Sharon Yang8b548ab92019-12-20 01:52:54180
181// Checks that the correct node ID is returned when performing hit testing.
Wez99fac70b2020-02-07 15:26:10182// TODO(https://crbug.com/1050049): Re-enable once flake is fixed.
183IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, DISABLED_HitTest) {
Sharon Yang1dd8b6db32020-04-10 23:10:18184 GURL page_url(embedded_test_server()->GetURL(kPage1Path));
Wez19de8b522020-01-28 20:50:04185 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
Sharon Yang1dd8b6db32020-04-10 23:10:18186 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
187 page_url.spec()));
188 navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage1Title);
Sharon Yang8b548ab92019-12-20 01:52:54189
Sharon Yangd0d86f42020-07-11 15:38:53190 fuchsia::accessibility::semantics::Node* hit_test_node =
Sharon Yang8b548ab92019-12-20 01:52:54191 semantics_manager_.semantic_tree()->GetNodeFromLabel(kParagraphName);
Sharon Yangfb25b4a2020-02-10 23:50:15192 EXPECT_TRUE(hit_test_node);
Sharon Yang8b548ab92019-12-20 01:52:54193
194 fuchsia::math::PointF target_point =
195 GetCenterOfBox(hit_test_node->location());
196
197 EXPECT_EQ(hit_test_node->node_id(),
198 semantics_manager_.HitTestAtPointSync(std::move(target_point)));
199
200 // Expect hit testing to return the root when the point given is out of
201 // bounds or there is no semantic node at that position.
202 target_point.x = -1;
203 target_point.y = -1;
204 EXPECT_EQ(0u, semantics_manager_.HitTestAtPointSync(std::move(target_point)));
205 target_point.x = 1;
206 target_point.y = 1;
207 EXPECT_EQ(0u, semantics_manager_.HitTestAtPointSync(std::move(target_point)));
208}
Sharon Yang5fb4ce22020-02-08 00:45:21209
210IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, PerformDefaultAction) {
Sharon Yang1dd8b6db32020-04-10 23:10:18211 GURL page_url(embedded_test_server()->GetURL(kPage1Path));
Sharon Yang5fb4ce22020-02-08 00:45:21212 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
Sharon Yang1dd8b6db32020-04-10 23:10:18213 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
214 page_url.spec()));
215 navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage1Title);
Sharon Yang5fb4ce22020-02-08 00:45:21216 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
217
Sharon Yangd0d86f42020-07-11 15:38:53218 fuchsia::accessibility::semantics::Node* button1 =
Sharon Yang5fb4ce22020-02-08 00:45:21219 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1);
220 EXPECT_TRUE(button1);
Sharon Yangd0d86f42020-07-11 15:38:53221 fuchsia::accessibility::semantics::Node* button2 =
Sharon Yang5fb4ce22020-02-08 00:45:21222 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName2);
223 EXPECT_TRUE(button2);
Sharon Yangd0d86f42020-07-11 15:38:53224 fuchsia::accessibility::semantics::Node* button3 =
Sharon Yang5fb4ce22020-02-08 00:45:21225 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName3);
226 EXPECT_TRUE(button3);
227
228 // Perform the default action (click) on multiple buttons.
Sharon Yangd0d86f42020-07-11 15:38:53229 semantics_manager_.RequestAccessibilityAction(
230 button1->node_id(), fuchsia::accessibility::semantics::Action::DEFAULT);
231 semantics_manager_.RequestAccessibilityAction(
232 button2->node_id(), fuchsia::accessibility::semantics::Action::DEFAULT);
Sharon Yang5fb4ce22020-02-08 00:45:21233 semantics_manager_.RunUntilNumActionsHandledEquals(2);
234
235 // Handle the case that actions are still in flight when AccessibilityBridge
236 // gets torn down. The corresponding callbacks should still be run.
237 frame_impl_->set_handle_actions_for_test(false);
Sharon Yangd0d86f42020-07-11 15:38:53238 semantics_manager_.RequestAccessibilityAction(
239 button3->node_id(), fuchsia::accessibility::semantics::Action::DEFAULT);
Sharon Yang5fb4ce22020-02-08 00:45:21240 frame_ptr_.Unbind();
241 base::RunLoop().RunUntilIdle();
242 EXPECT_EQ(2, semantics_manager_.num_actions_handled());
243 EXPECT_EQ(1, semantics_manager_.num_actions_unhandled());
244}
Sharon Yang1dd8b6db32020-04-10 23:10:18245
246IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, PerformUnsupportedAction) {
247 GURL page_url(embedded_test_server()->GetURL(kPage1Path));
248 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
249 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
250 page_url.spec()));
251 navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage1Title);
252 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
253
Sharon Yangd0d86f42020-07-11 15:38:53254 fuchsia::accessibility::semantics::Node* button1 =
Sharon Yang1dd8b6db32020-04-10 23:10:18255 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1);
256 EXPECT_TRUE(button1);
Sharon Yangd0d86f42020-07-11 15:38:53257 fuchsia::accessibility::semantics::Node* button2 =
Sharon Yang1dd8b6db32020-04-10 23:10:18258 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName2);
259 EXPECT_TRUE(button2);
260
261 // Perform one supported action (DEFAULT) and one non-supported action
262 // (SET_VALUE);
Sharon Yangd0d86f42020-07-11 15:38:53263 semantics_manager_.RequestAccessibilityAction(
264 button1->node_id(), fuchsia::accessibility::semantics::Action::DEFAULT);
265 semantics_manager_.RequestAccessibilityAction(
266 button2->node_id(), fuchsia::accessibility::semantics::Action::SET_VALUE);
Sharon Yang1dd8b6db32020-04-10 23:10:18267 semantics_manager_.RunUntilNumActionsHandledEquals(2);
268
269 EXPECT_EQ(1, semantics_manager_.num_actions_handled());
270 EXPECT_EQ(1, semantics_manager_.num_actions_unhandled());
271}