blob: 87d73b8e49e95cecbcfd78c6b56a8d0d3c78f3e0 [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 Yang3231ad92020-08-12 02:22:0833const char kOffscreenNodeName[] = "offscreen node";
Sharon Yangaa2c9bd2019-11-21 17:59:2234const size_t kPage1NodeCount = 9;
35const size_t kPage2NodeCount = 190;
Sharon Yang2caf82e2020-10-12 18:00:3536const size_t kInitialRangeValue = 51;
37const size_t kStepSize = 3;
Sharon Yangfbb9ba4a2019-11-18 23:59:5638
Sharon Yang8b548ab92019-12-20 01:52:5439fuchsia::math::PointF GetCenterOfBox(fuchsia::ui::gfx::BoundingBox box) {
40 fuchsia::math::PointF center;
41 center.x = (box.min.x + box.max.x) / 2;
42 center.y = (box.min.y + box.max.y) / 2;
43 return center;
44}
45
Sharon Yangfbb9ba4a2019-11-18 23:59:5646} // namespace
47
48class AccessibilityBridgeTest : public cr_fuchsia::WebEngineBrowserTest {
49 public:
Wez7a5f5ca2020-08-17 07:41:0850 AccessibilityBridgeTest() {
Sharon Yangfbb9ba4a2019-11-18 23:59:5651 cr_fuchsia::WebEngineBrowserTest::set_test_server_root(
52 base::FilePath(cr_fuchsia::kTestServerRoot));
53 }
54
55 ~AccessibilityBridgeTest() override = default;
56
Sharon Yangd0d86f42020-07-11 15:38:5357 AccessibilityBridgeTest(const AccessibilityBridgeTest&) = delete;
58 AccessibilityBridgeTest& operator=(const AccessibilityBridgeTest&) = delete;
59
Sharon Yang8b548ab92019-12-20 01:52:5460 void SetUp() override {
61 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
62 command_line->AppendSwitchNative(switches::kOzonePlatform,
63 switches::kHeadless);
64 command_line->AppendSwitch(switches::kHeadless);
65 cr_fuchsia::WebEngineBrowserTest::SetUp();
66 }
67
Sharon Yangfbb9ba4a2019-11-18 23:59:5668 void SetUpOnMainThread() override {
Sharon Yangfbb9ba4a2019-11-18 23:59:5669 frame_ptr_ =
70 cr_fuchsia::WebEngineBrowserTest::CreateFrame(&navigation_listener_);
71 frame_impl_ = context_impl()->GetFrameImplForTest(&frame_ptr_);
Wez7a5f5ca2020-08-17 07:41:0872 frame_impl_->set_semantics_manager_for_test(&semantics_manager_);
Sharon Yang8b548ab92019-12-20 01:52:5473 frame_ptr_->EnableHeadlessRendering();
Sharon Yangfbb9ba4a2019-11-18 23:59:5674
Wez19de8b522020-01-28 20:50:0475 semantics_manager_.WaitUntilViewRegistered();
76 ASSERT_TRUE(semantics_manager_.is_view_registered());
77 ASSERT_TRUE(semantics_manager_.is_listener_valid());
Sharon Yang1dd8b6db32020-04-10 23:10:1878
79 frame_ptr_->GetNavigationController(navigation_controller_.NewRequest());
80 ASSERT_TRUE(embedded_test_server()->Start());
81 semantics_manager_.SetSemanticsModeEnabled(true);
Sharon Yangfbb9ba4a2019-11-18 23:59:5682 }
83
84 protected:
85 fuchsia::web::FramePtr frame_ptr_;
86 FrameImpl* frame_impl_;
87 FakeSemanticsManager semantics_manager_;
Sharon Yangfbb9ba4a2019-11-18 23:59:5688 cr_fuchsia::TestNavigationListener navigation_listener_;
Sharon Yang1dd8b6db32020-04-10 23:10:1889 fuchsia::web::NavigationControllerPtr navigation_controller_;
Sharon Yangfbb9ba4a2019-11-18 23:59:5690};
91
92// Test registration to the SemanticsManager and accessibility mode on
93// WebContents is set correctly.
94IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, RegisterViewRef) {
Sharon Yangfbb9ba4a2019-11-18 23:59:5695 // Change the accessibility mode on the Fuchsia side and check that it is
96 // propagated correctly.
Wez19de8b522020-01-28 20:50:0497 ASSERT_FALSE(frame_impl_->web_contents_for_test()
Sharon Yangfbb9ba4a2019-11-18 23:59:5698 ->IsWebContentsOnlyAccessibilityModeForTesting());
99 semantics_manager_.SetSemanticsModeEnabled(true);
Wez19de8b522020-01-28 20:50:04100
101 // Spin the loop to let the FrameImpl receive the mode-change.
Sharon Yangfbb9ba4a2019-11-18 23:59:56102 base::RunLoop().RunUntilIdle();
Wez19de8b522020-01-28 20:50:04103
Sharon Yangfbb9ba4a2019-11-18 23:59:56104 EXPECT_TRUE(frame_impl_->web_contents_for_test()
105 ->IsWebContentsOnlyAccessibilityModeForTesting());
106}
107
108IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, CorrectDataSent) {
Sharon Yang1dd8b6db32020-04-10 23:10:18109 GURL page_url(embedded_test_server()->GetURL(kPage1Path));
Wez19de8b522020-01-28 20:50:04110 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
Sharon Yang1dd8b6db32020-04-10 23:10:18111 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
112 page_url.spec()));
113 navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage1Title);
Sharon Yangfbb9ba4a2019-11-18 23:59:56114
115 // Check that the data values are correct in the FakeSemanticTree.
116 // TODO(fxb/18796): Test more fields once Chrome to Fuchsia conversions are
117 // available.
118 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
119 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15120 semantics_manager_.semantic_tree()->GetNodeFromLabel(kPage1Title));
Sharon Yangfbb9ba4a2019-11-18 23:59:56121 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15122 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1));
Sharon Yangfbb9ba4a2019-11-18 23:59:56123 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15124 semantics_manager_.semantic_tree()->GetNodeFromLabel(kParagraphName));
Sharon Yangfbb9ba4a2019-11-18 23:59:56125}
126
127// Batching is performed when the number of nodes to send or delete exceeds the
128// maximum, as set on the Fuchsia side. Check that all nodes are received by the
129// Semantic Tree when batching is performed.
130IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, DataSentWithBatching) {
Sharon Yang1dd8b6db32020-04-10 23:10:18131 GURL page_url(embedded_test_server()->GetURL(kPage2Path));
Wez19de8b522020-01-28 20:50:04132 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
Sharon Yang1dd8b6db32020-04-10 23:10:18133 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
134 page_url.spec()));
135 navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage2Title);
Sharon Yangfbb9ba4a2019-11-18 23:59:56136
137 // Run until we expect more than a batch's worth of nodes to be present.
138 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage2NodeCount);
Sharon Yangfb25b4a2020-02-10 23:50:15139 EXPECT_TRUE(semantics_manager_.semantic_tree()->GetNodeFromLabel(kNodeName));
Sharon Yangfbb9ba4a2019-11-18 23:59:56140}
141
142// Check that semantics information is correctly sent when navigating from page
143// to page.
144IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, TestNavigation) {
Sharon Yang8b548ab92019-12-20 01:52:54145 GURL page_url1(embedded_test_server()->GetURL(kPage1Path));
Wez19de8b522020-01-28 20:50:04146 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
Sharon Yang1dd8b6db32020-04-10 23:10:18147 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
148 page_url1.spec()));
Sharon Yang8b548ab92019-12-20 01:52:54149 navigation_listener_.RunUntilUrlAndTitleEquals(page_url1, kPage1Title);
Sharon Yangfbb9ba4a2019-11-18 23:59:56150
151 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
152 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15153 semantics_manager_.semantic_tree()->GetNodeFromLabel(kPage1Title));
Sharon Yangfbb9ba4a2019-11-18 23:59:56154 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15155 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1));
Sharon Yangfbb9ba4a2019-11-18 23:59:56156 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15157 semantics_manager_.semantic_tree()->GetNodeFromLabel(kParagraphName));
Sharon Yangfbb9ba4a2019-11-18 23:59:56158
Sharon Yang8b548ab92019-12-20 01:52:54159 GURL page_url2(embedded_test_server()->GetURL(kPage2Path));
Wez19de8b522020-01-28 20:50:04160 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
Sharon Yang1dd8b6db32020-04-10 23:10:18161 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
162 page_url2.spec()));
Sharon Yangfbb9ba4a2019-11-18 23:59:56163
164 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage2NodeCount);
Sharon Yangca616422019-12-18 23:52:39165 EXPECT_TRUE(
Sharon Yangfb25b4a2020-02-10 23:50:15166 semantics_manager_.semantic_tree()->GetNodeFromLabel(kPage2Title));
167 EXPECT_TRUE(semantics_manager_.semantic_tree()->GetNodeFromLabel(kNodeName));
Sharon Yangca616422019-12-18 23:52:39168
169 // Check that data from the first page has been deleted successfully.
170 EXPECT_FALSE(
Sharon Yangfb25b4a2020-02-10 23:50:15171 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1));
Sharon Yangca616422019-12-18 23:52:39172 EXPECT_FALSE(
Sharon Yangfb25b4a2020-02-10 23:50:15173 semantics_manager_.semantic_tree()->GetNodeFromLabel(kParagraphName));
Sharon Yangfbb9ba4a2019-11-18 23:59:56174}
Sharon Yang8b548ab92019-12-20 01:52:54175
176// Checks that the correct node ID is returned when performing hit testing.
Wez99fac70b2020-02-07 15:26:10177// TODO(https://crbug.com/1050049): Re-enable once flake is fixed.
178IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, DISABLED_HitTest) {
Sharon Yang1dd8b6db32020-04-10 23:10:18179 GURL page_url(embedded_test_server()->GetURL(kPage1Path));
Wez19de8b522020-01-28 20:50:04180 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
Sharon Yang1dd8b6db32020-04-10 23:10:18181 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
182 page_url.spec()));
183 navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage1Title);
Sharon Yang8b548ab92019-12-20 01:52:54184
Sharon Yangd0d86f42020-07-11 15:38:53185 fuchsia::accessibility::semantics::Node* hit_test_node =
Sharon Yang8b548ab92019-12-20 01:52:54186 semantics_manager_.semantic_tree()->GetNodeFromLabel(kParagraphName);
Sharon Yangfb25b4a2020-02-10 23:50:15187 EXPECT_TRUE(hit_test_node);
Sharon Yang8b548ab92019-12-20 01:52:54188
189 fuchsia::math::PointF target_point =
190 GetCenterOfBox(hit_test_node->location());
191
192 EXPECT_EQ(hit_test_node->node_id(),
193 semantics_manager_.HitTestAtPointSync(std::move(target_point)));
194
195 // Expect hit testing to return the root when the point given is out of
196 // bounds or there is no semantic node at that position.
197 target_point.x = -1;
198 target_point.y = -1;
199 EXPECT_EQ(0u, semantics_manager_.HitTestAtPointSync(std::move(target_point)));
200 target_point.x = 1;
201 target_point.y = 1;
202 EXPECT_EQ(0u, semantics_manager_.HitTestAtPointSync(std::move(target_point)));
203}
Sharon Yang5fb4ce22020-02-08 00:45:21204
205IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, PerformDefaultAction) {
Sharon Yang1dd8b6db32020-04-10 23:10:18206 GURL page_url(embedded_test_server()->GetURL(kPage1Path));
Sharon Yang5fb4ce22020-02-08 00:45:21207 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
Sharon Yang1dd8b6db32020-04-10 23:10:18208 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
209 page_url.spec()));
210 navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage1Title);
Sharon Yang5fb4ce22020-02-08 00:45:21211 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
212
Sharon Yangd0d86f42020-07-11 15:38:53213 fuchsia::accessibility::semantics::Node* button1 =
Sharon Yang5fb4ce22020-02-08 00:45:21214 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1);
215 EXPECT_TRUE(button1);
Sharon Yangd0d86f42020-07-11 15:38:53216 fuchsia::accessibility::semantics::Node* button2 =
Sharon Yang5fb4ce22020-02-08 00:45:21217 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName2);
218 EXPECT_TRUE(button2);
Sharon Yangd0d86f42020-07-11 15:38:53219 fuchsia::accessibility::semantics::Node* button3 =
Sharon Yang5fb4ce22020-02-08 00:45:21220 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName3);
221 EXPECT_TRUE(button3);
222
223 // Perform the default action (click) on multiple buttons.
Sharon Yangd0d86f42020-07-11 15:38:53224 semantics_manager_.RequestAccessibilityAction(
225 button1->node_id(), fuchsia::accessibility::semantics::Action::DEFAULT);
226 semantics_manager_.RequestAccessibilityAction(
227 button2->node_id(), fuchsia::accessibility::semantics::Action::DEFAULT);
Sharon Yang5fb4ce22020-02-08 00:45:21228 semantics_manager_.RunUntilNumActionsHandledEquals(2);
Sharon Yang5fb4ce22020-02-08 00:45:21229}
Sharon Yang1dd8b6db32020-04-10 23:10:18230
231IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, PerformUnsupportedAction) {
232 GURL page_url(embedded_test_server()->GetURL(kPage1Path));
233 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
234 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
235 page_url.spec()));
236 navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage1Title);
237 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
238
Sharon Yangd0d86f42020-07-11 15:38:53239 fuchsia::accessibility::semantics::Node* button1 =
Sharon Yang1dd8b6db32020-04-10 23:10:18240 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName1);
241 EXPECT_TRUE(button1);
Sharon Yangd0d86f42020-07-11 15:38:53242 fuchsia::accessibility::semantics::Node* button2 =
Sharon Yang1dd8b6db32020-04-10 23:10:18243 semantics_manager_.semantic_tree()->GetNodeFromLabel(kButtonName2);
244 EXPECT_TRUE(button2);
245
246 // Perform one supported action (DEFAULT) and one non-supported action
247 // (SET_VALUE);
Sharon Yangd0d86f42020-07-11 15:38:53248 semantics_manager_.RequestAccessibilityAction(
249 button1->node_id(), fuchsia::accessibility::semantics::Action::DEFAULT);
250 semantics_manager_.RequestAccessibilityAction(
251 button2->node_id(), fuchsia::accessibility::semantics::Action::SET_VALUE);
Sharon Yang1dd8b6db32020-04-10 23:10:18252 semantics_manager_.RunUntilNumActionsHandledEquals(2);
253
254 EXPECT_EQ(1, semantics_manager_.num_actions_handled());
255 EXPECT_EQ(1, semantics_manager_.num_actions_unhandled());
256}
Sharon Yang7919fab2020-07-28 16:46:20257
258IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, Disconnect) {
259 base::RunLoop run_loop;
260 frame_ptr_.set_error_handler([&run_loop](zx_status_t status) {
261 EXPECT_EQ(ZX_ERR_INTERNAL, status);
262 run_loop.Quit();
263 });
264
265 semantics_manager_.semantic_tree()->Disconnect();
266 run_loop.Run();
267}
Sharon Yang3231ad92020-08-12 02:22:08268
Adam Ettenberger9c15a3a2020-09-01 22:10:27269IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, PerformScrollToMakeVisible) {
Sharon Yang3231ad92020-08-12 02:22:08270 constexpr int kScreenWidth = 720;
271 constexpr int kScreenHeight = 640;
272 gfx::Rect screen_bounds(kScreenWidth, kScreenHeight);
273
274 GURL page_url(embedded_test_server()->GetURL(kPage1Path));
275 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
276 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
277 page_url.spec()));
278 navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage1Title);
279 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
280
281 auto* content_view =
282 frame_impl_->web_contents_for_test()->GetContentNativeView();
283 content_view->SetBounds(screen_bounds);
284
285 // Get a node that is off the screen.
286 fuchsia::accessibility::semantics::Node* node =
287 semantics_manager_.semantic_tree()->GetNodeFromLabel(kOffscreenNodeName);
288 ASSERT_TRUE(node);
289 AccessibilityBridge* bridge = frame_impl_->accessibility_bridge_for_test();
290 ui::AXNode* ax_node = bridge->ax_tree_for_test()->GetFromId(node->node_id());
291 ASSERT_TRUE(ax_node);
292 bool is_offscreen = false;
293 bridge->ax_tree_for_test()->GetTreeBounds(ax_node, &is_offscreen);
294 EXPECT_TRUE(is_offscreen);
295
296 // Perform SHOW_ON_SCREEN on that node and check that it is on the screen.
297 base::RunLoop run_loop;
298 bridge->set_event_received_callback_for_test(run_loop.QuitClosure());
299 semantics_manager_.RequestAccessibilityAction(
300 node->node_id(),
301 fuchsia::accessibility::semantics::Action::SHOW_ON_SCREEN);
302 semantics_manager_.RunUntilNumActionsHandledEquals(1);
303 run_loop.Run();
304
305 // Initialize |is_offscreen| to false before calling GetTreeBounds as
306 // specified by the API.
307 is_offscreen = false;
308 bridge->ax_tree_for_test()->GetTreeBounds(ax_node, &is_offscreen);
309
310 EXPECT_FALSE(is_offscreen);
311}
Sharon Yang2caf82e2020-10-12 18:00:35312
313IN_PROC_BROWSER_TEST_F(AccessibilityBridgeTest, Slider) {
314 GURL page_url(embedded_test_server()->GetURL(kPage1Path));
315 ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
316 navigation_controller_.get(), fuchsia::web::LoadUrlParams(),
317 page_url.spec()));
318 navigation_listener_.RunUntilUrlAndTitleEquals(page_url, kPage1Title);
319 semantics_manager_.semantic_tree()->RunUntilNodeCountAtLeast(kPage1NodeCount);
320
321 fuchsia::accessibility::semantics::Node* node =
322 semantics_manager_.semantic_tree()->GetNodeFromRole(
323 fuchsia::accessibility::semantics::Role::SLIDER);
324 EXPECT_TRUE(node);
325 EXPECT_TRUE(node->has_states() && node->states().has_range_value());
326 EXPECT_EQ(node->states().range_value(), kInitialRangeValue);
327
328 AccessibilityBridge* bridge = frame_impl_->accessibility_bridge_for_test();
329 base::RunLoop run_loop;
330 bridge->set_event_received_callback_for_test(run_loop.QuitClosure());
331 semantics_manager_.RequestAccessibilityAction(
332 node->node_id(), fuchsia::accessibility::semantics::Action::INCREMENT);
333 semantics_manager_.RunUntilNumActionsHandledEquals(1);
334 run_loop.Run();
335
336 // Wait for the slider node to be updated, then check the value.
337 base::RunLoop run_loop2;
338 semantics_manager_.semantic_tree()->SetNodeUpdatedCallback(
339 node->node_id(), run_loop2.QuitClosure());
340 run_loop2.Run();
341
342 node = semantics_manager_.semantic_tree()->GetNodeWithId(node->node_id());
343 EXPECT_TRUE(node->has_states() && node->states().has_range_value());
344 EXPECT_EQ(node->states().range_value(), kInitialRangeValue + kStepSize);
345}