1 // Copyright 2017 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 "ui/accessibility/ax_event_generator.h"
6
7 #include "testing/gmock/include/gmock/gmock-matchers.h"
8 #include "testing/gmock/include/gmock/gmock.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/accessibility/ax_enums.mojom.h"
11 #include "ui/accessibility/ax_node.h"
12 #include "ui/accessibility/ax_serializable_tree.h"
13 #include "ui/accessibility/ax_tree_serializer.h"
14
15 namespace ui {
16
17 // Required by gmock to print TargetedEvent in a human-readable way.
PrintTo(const AXEventGenerator::TargetedEvent & event,std::ostream * os)18 void PrintTo(const AXEventGenerator::TargetedEvent& event, std::ostream* os) {
19 *os << event.event_params.event << " on " << event.node->id();
20 }
21
22 namespace {
23
24 using testing::Matches;
25 using testing::PrintToString;
26 using testing::UnorderedElementsAre;
27
28 // TODO(gilmanmh): Improve printing of test failure messages when the expected
29 // values are themselves matchers (e.g. Not(3)).
30 MATCHER_P2(HasEventAtNode,
31 expected_event_type,
32 expected_node_id,
33 std::string(negation ? "does not have" : "has") + " " +
34 PrintToString(expected_event_type) + " on " +
35 PrintToString(expected_node_id)) {
36 const auto& event = arg;
37 return Matches(expected_event_type)(event.event_params.event) &&
38 Matches(expected_node_id)(event.node->id());
39 }
40
41 } // namespace
42
TEST(AXEventGeneratorTest,LoadCompleteSameTree)43 TEST(AXEventGeneratorTest, LoadCompleteSameTree) {
44 AXTreeUpdate initial_state;
45 initial_state.root_id = 1;
46 initial_state.nodes.resize(1);
47 initial_state.nodes[0].id = 1;
48 initial_state.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
49 initial_state.has_tree_data = true;
50 AXTree tree(initial_state);
51
52 AXEventGenerator event_generator(&tree);
53 AXTreeUpdate load_complete_update = initial_state;
54 load_complete_update.tree_data.loaded = true;
55
56 ASSERT_TRUE(tree.Unserialize(load_complete_update));
57 EXPECT_THAT(event_generator, UnorderedElementsAre(HasEventAtNode(
58 AXEventGenerator::Event::LOAD_COMPLETE, 1)));
59 }
60
TEST(AXEventGeneratorTest,LoadCompleteNewTree)61 TEST(AXEventGeneratorTest, LoadCompleteNewTree) {
62 AXTreeUpdate initial_state;
63 initial_state.root_id = 1;
64 initial_state.nodes.resize(1);
65 initial_state.nodes[0].id = 1;
66 initial_state.has_tree_data = true;
67 initial_state.tree_data.loaded = true;
68 AXTree tree(initial_state);
69
70 AXEventGenerator event_generator(&tree);
71 AXTreeUpdate load_complete_update;
72 load_complete_update.root_id = 2;
73 load_complete_update.nodes.resize(1);
74 load_complete_update.nodes[0].id = 2;
75 load_complete_update.nodes[0].relative_bounds.bounds =
76 gfx::RectF(0, 0, 800, 600);
77 load_complete_update.has_tree_data = true;
78 load_complete_update.tree_data.loaded = true;
79
80 ASSERT_TRUE(tree.Unserialize(load_complete_update));
81 EXPECT_THAT(event_generator,
82 UnorderedElementsAre(
83 HasEventAtNode(AXEventGenerator::Event::LOAD_COMPLETE, 2),
84 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 2)));
85
86 // Load complete should not be emitted for sizeless roots.
87 load_complete_update.root_id = 3;
88 load_complete_update.nodes.resize(1);
89 load_complete_update.nodes[0].id = 3;
90 load_complete_update.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 0, 0);
91 load_complete_update.has_tree_data = true;
92 load_complete_update.tree_data.loaded = true;
93
94 ASSERT_TRUE(tree.Unserialize(load_complete_update));
95 EXPECT_THAT(event_generator,
96 UnorderedElementsAre(
97 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 3)));
98
99 // TODO(accessibility): http://crbug.com/888758
100 // Load complete should not be emitted for chrome-search URLs.
101 load_complete_update.root_id = 4;
102 load_complete_update.nodes.resize(1);
103 load_complete_update.nodes[0].id = 4;
104 load_complete_update.nodes[0].relative_bounds.bounds =
105 gfx::RectF(0, 0, 800, 600);
106 load_complete_update.nodes[0].AddStringAttribute(
107 ax::mojom::StringAttribute::kUrl, "chrome-search://foo");
108 load_complete_update.has_tree_data = true;
109 load_complete_update.tree_data.loaded = true;
110
111 ASSERT_TRUE(tree.Unserialize(load_complete_update));
112 EXPECT_THAT(event_generator,
113 UnorderedElementsAre(
114 HasEventAtNode(AXEventGenerator::Event::LOAD_COMPLETE, 4),
115 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 4)));
116 }
117
TEST(AXEventGeneratorTest,LoadStart)118 TEST(AXEventGeneratorTest, LoadStart) {
119 AXTreeUpdate initial_state;
120 initial_state.root_id = 1;
121 initial_state.nodes.resize(1);
122 initial_state.nodes[0].id = 1;
123 initial_state.nodes[0].relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
124 initial_state.has_tree_data = true;
125 AXTree tree(initial_state);
126
127 AXEventGenerator event_generator(&tree);
128 AXTreeUpdate load_start_update;
129 load_start_update.root_id = 2;
130 load_start_update.nodes.resize(1);
131 load_start_update.nodes[0].id = 2;
132 load_start_update.nodes[0].relative_bounds.bounds =
133 gfx::RectF(0, 0, 800, 600);
134 load_start_update.has_tree_data = true;
135 load_start_update.tree_data.loaded = false;
136
137 ASSERT_TRUE(tree.Unserialize(load_start_update));
138 EXPECT_THAT(event_generator,
139 UnorderedElementsAre(
140 HasEventAtNode(AXEventGenerator::Event::LOAD_START, 2),
141 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 2)));
142 }
143
TEST(AXEventGeneratorTest,DocumentSelectionChanged)144 TEST(AXEventGeneratorTest, DocumentSelectionChanged) {
145 AXTreeUpdate initial_state;
146 initial_state.root_id = 1;
147 initial_state.nodes.resize(1);
148 initial_state.nodes[0].id = 1;
149 initial_state.has_tree_data = true;
150 initial_state.tree_data.sel_focus_object_id = 1;
151 initial_state.tree_data.sel_focus_offset = 1;
152 AXTree tree(initial_state);
153
154 AXEventGenerator event_generator(&tree);
155 AXTreeUpdate update = initial_state;
156 update.tree_data.sel_focus_offset = 2;
157
158 ASSERT_TRUE(tree.Unserialize(update));
159 EXPECT_THAT(event_generator,
160 UnorderedElementsAre(HasEventAtNode(
161 AXEventGenerator::Event::DOCUMENT_SELECTION_CHANGED, 1)));
162 }
163
TEST(AXEventGeneratorTest,DocumentTitleChanged)164 TEST(AXEventGeneratorTest, DocumentTitleChanged) {
165 AXTreeUpdate initial_state;
166 initial_state.root_id = 1;
167 initial_state.nodes.resize(1);
168 initial_state.nodes[0].id = 1;
169 initial_state.has_tree_data = true;
170 initial_state.tree_data.title = "Before";
171 AXTree tree(initial_state);
172
173 AXEventGenerator event_generator(&tree);
174 AXTreeUpdate update = initial_state;
175 update.tree_data.title = "After";
176
177 ASSERT_TRUE(tree.Unserialize(update));
178 EXPECT_THAT(event_generator,
179 UnorderedElementsAre(HasEventAtNode(
180 AXEventGenerator::Event::DOCUMENT_TITLE_CHANGED, 1)));
181 }
182
TEST(AXEventGeneratorTest,ExpandedAndRowCount)183 TEST(AXEventGeneratorTest, ExpandedAndRowCount) {
184 AXTreeUpdate initial_state;
185 initial_state.root_id = 1;
186 initial_state.nodes.resize(4);
187 initial_state.nodes[0].id = 1;
188 initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
189 initial_state.nodes[0].child_ids.push_back(2);
190 initial_state.nodes[0].child_ids.push_back(4);
191 initial_state.nodes[1].id = 2;
192 initial_state.nodes[1].role = ax::mojom::Role::kTable;
193 initial_state.nodes[1].child_ids.push_back(3);
194 initial_state.nodes[2].id = 3;
195 initial_state.nodes[2].role = ax::mojom::Role::kRow;
196 initial_state.nodes[3].id = 4;
197 initial_state.nodes[3].role = ax::mojom::Role::kPopUpButton;
198 initial_state.nodes[3].AddState(ax::mojom::State::kExpanded);
199 AXTree tree(initial_state);
200
201 AXEventGenerator event_generator(&tree);
202 AXTreeUpdate update = initial_state;
203 update.nodes[2].AddState(ax::mojom::State::kExpanded);
204 update.nodes[3].state = 0;
205
206 ASSERT_TRUE(tree.Unserialize(update));
207 EXPECT_THAT(event_generator,
208 UnorderedElementsAre(
209 HasEventAtNode(AXEventGenerator::Event::COLLAPSED, 4),
210 HasEventAtNode(AXEventGenerator::Event::EXPANDED, 3),
211 HasEventAtNode(AXEventGenerator::Event::ROW_COUNT_CHANGED, 2),
212 HasEventAtNode(AXEventGenerator::Event::STATE_CHANGED, 3),
213 HasEventAtNode(AXEventGenerator::Event::STATE_CHANGED, 4)));
214 }
215
TEST(AXEventGeneratorTest,SelectedAndSelectedChildren)216 TEST(AXEventGeneratorTest, SelectedAndSelectedChildren) {
217 AXTreeUpdate initial_state;
218 initial_state.root_id = 1;
219 initial_state.nodes.resize(4);
220 initial_state.nodes[0].id = 1;
221 initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
222 initial_state.nodes[0].child_ids.push_back(2);
223 initial_state.nodes[0].child_ids.push_back(4);
224 initial_state.nodes[1].id = 2;
225 initial_state.nodes[1].role = ax::mojom::Role::kMenu;
226 initial_state.nodes[1].child_ids.push_back(3);
227 initial_state.nodes[2].id = 3;
228 initial_state.nodes[2].role = ax::mojom::Role::kMenuItem;
229 initial_state.nodes[3].id = 4;
230 initial_state.nodes[3].role = ax::mojom::Role::kListBoxOption;
231 initial_state.nodes[3].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
232 true);
233 AXTree tree(initial_state);
234
235 AXEventGenerator event_generator(&tree);
236 AXTreeUpdate update = initial_state;
237 update.nodes[2].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
238 update.nodes.pop_back();
239 update.nodes.emplace_back();
240 update.nodes[3].id = 4;
241 update.nodes[3].role = ax::mojom::Role::kListBoxOption;
242 update.nodes[3].AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, false);
243
244 ASSERT_TRUE(tree.Unserialize(update));
245 EXPECT_THAT(
246 event_generator,
247 UnorderedElementsAre(
248 HasEventAtNode(AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED, 2),
249 HasEventAtNode(AXEventGenerator::Event::SELECTED_CHANGED, 3),
250 HasEventAtNode(AXEventGenerator::Event::SELECTED_CHANGED, 4)));
251 }
252
TEST(AXEventGeneratorTest,StringValueChanged)253 TEST(AXEventGeneratorTest, StringValueChanged) {
254 AXTreeUpdate initial_state;
255 initial_state.root_id = 1;
256 initial_state.nodes.resize(1);
257 initial_state.nodes[0].id = 1;
258 initial_state.nodes[0].role = ax::mojom::Role::kTextField;
259 initial_state.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kValue,
260 "Before");
261 AXTree tree(initial_state);
262
263 AXEventGenerator event_generator(&tree);
264 AXTreeUpdate update = initial_state;
265 update.nodes[0].string_attributes.clear();
266 update.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kValue,
267 "After");
268
269 ASSERT_TRUE(tree.Unserialize(update));
270 EXPECT_THAT(event_generator, UnorderedElementsAre(HasEventAtNode(
271 AXEventGenerator::Event::VALUE_CHANGED, 1)));
272 }
273
TEST(AXEventGeneratorTest,FloatValueChanged)274 TEST(AXEventGeneratorTest, FloatValueChanged) {
275 AXTreeUpdate initial_state;
276 initial_state.root_id = 1;
277 initial_state.nodes.resize(1);
278 initial_state.nodes[0].id = 1;
279 initial_state.nodes[0].role = ax::mojom::Role::kSlider;
280 initial_state.nodes[0].AddFloatAttribute(
281 ax::mojom::FloatAttribute::kValueForRange, 1.0);
282 AXTree tree(initial_state);
283
284 AXEventGenerator event_generator(&tree);
285 AXTreeUpdate update = initial_state;
286 update.nodes[0].float_attributes.clear();
287 update.nodes[0].AddFloatAttribute(ax::mojom::FloatAttribute::kValueForRange,
288 2.0);
289
290 ASSERT_TRUE(tree.Unserialize(update));
291 EXPECT_THAT(event_generator, UnorderedElementsAre(HasEventAtNode(
292 AXEventGenerator::Event::VALUE_CHANGED, 1)));
293 }
294
TEST(AXEventGeneratorTest,InvalidStatusChanged)295 TEST(AXEventGeneratorTest, InvalidStatusChanged) {
296 AXTreeUpdate initial_state;
297 initial_state.root_id = 1;
298 initial_state.nodes.resize(1);
299 initial_state.nodes[0].id = 1;
300 initial_state.nodes[0].role = ax::mojom::Role::kTextField;
301 initial_state.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kValue,
302 "Text");
303 AXTree tree(initial_state);
304
305 AXEventGenerator event_generator(&tree);
306 AXTreeUpdate update = initial_state;
307 update.nodes[0].SetInvalidState(ax::mojom::InvalidState::kTrue);
308 ASSERT_TRUE(tree.Unserialize(update));
309 EXPECT_THAT(event_generator,
310 UnorderedElementsAre(HasEventAtNode(
311 AXEventGenerator::Event::INVALID_STATUS_CHANGED, 1)));
312 }
313
TEST(AXEventGeneratorTest,AddLiveRegionAttribute)314 TEST(AXEventGeneratorTest, AddLiveRegionAttribute) {
315 AXTreeUpdate initial_state;
316 initial_state.root_id = 1;
317 initial_state.nodes.resize(1);
318 initial_state.nodes[0].id = 1;
319 AXTree tree(initial_state);
320
321 AXEventGenerator event_generator(&tree);
322 AXTreeUpdate update = initial_state;
323 update.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kLiveStatus,
324 "polite");
325 ASSERT_TRUE(tree.Unserialize(update));
326 EXPECT_THAT(
327 event_generator,
328 UnorderedElementsAre(
329 HasEventAtNode(AXEventGenerator::Event::LIVE_STATUS_CHANGED, 1),
330 HasEventAtNode(AXEventGenerator::Event::LIVE_REGION_CREATED, 1)));
331
332 event_generator.ClearEvents();
333 update.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kLiveStatus,
334 "assertive");
335 ASSERT_TRUE(tree.Unserialize(update));
336 EXPECT_THAT(event_generator,
337 UnorderedElementsAre(HasEventAtNode(
338 AXEventGenerator::Event::LIVE_STATUS_CHANGED, 1)));
339
340 event_generator.ClearEvents();
341 update.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kLiveStatus,
342 "off");
343
344 ASSERT_TRUE(tree.Unserialize(update));
345 EXPECT_THAT(event_generator,
346 UnorderedElementsAre(HasEventAtNode(
347 AXEventGenerator::Event::LIVE_STATUS_CHANGED, 1)));
348 }
349
TEST(AXEventGeneratorTest,CheckedStateChanged)350 TEST(AXEventGeneratorTest, CheckedStateChanged) {
351 AXTreeUpdate initial_state;
352 initial_state.root_id = 1;
353 initial_state.nodes.resize(1);
354 initial_state.nodes[0].id = 1;
355 initial_state.nodes[0].role = ax::mojom::Role::kCheckBox;
356 AXTree tree(initial_state);
357
358 AXEventGenerator event_generator(&tree);
359 AXTreeUpdate update = initial_state;
360 update.nodes[0].SetCheckedState(ax::mojom::CheckedState::kTrue);
361 ASSERT_TRUE(tree.Unserialize(update));
362 EXPECT_THAT(event_generator,
363 UnorderedElementsAre(HasEventAtNode(
364 AXEventGenerator::Event::CHECKED_STATE_CHANGED, 1)));
365 }
366
TEST(AXEventGeneratorTest,ActiveDescendantChanged)367 TEST(AXEventGeneratorTest, ActiveDescendantChanged) {
368 AXTreeUpdate initial_state;
369 initial_state.root_id = 1;
370 initial_state.nodes.resize(3);
371 initial_state.nodes[0].id = 1;
372 initial_state.nodes[0].role = ax::mojom::Role::kListBox;
373 initial_state.nodes[0].child_ids.push_back(2);
374 initial_state.nodes[0].child_ids.push_back(3);
375 initial_state.nodes[0].AddIntAttribute(
376 ax::mojom::IntAttribute::kActivedescendantId, 2);
377 initial_state.nodes[1].id = 2;
378 initial_state.nodes[1].role = ax::mojom::Role::kListBoxOption;
379 initial_state.nodes[2].id = 3;
380 initial_state.nodes[2].role = ax::mojom::Role::kListBoxOption;
381 AXTree tree(initial_state);
382
383 AXEventGenerator event_generator(&tree);
384 AXTreeUpdate update = initial_state;
385 update.nodes[0].int_attributes.clear();
386 update.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kActivedescendantId,
387 3);
388 ASSERT_TRUE(tree.Unserialize(update));
389 EXPECT_THAT(
390 event_generator,
391 UnorderedElementsAre(
392 HasEventAtNode(AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED, 1),
393 HasEventAtNode(AXEventGenerator::Event::RELATED_NODE_CHANGED, 1)));
394 }
395
TEST(AXEventGeneratorTest,CreateAlertAndLiveRegion)396 TEST(AXEventGeneratorTest, CreateAlertAndLiveRegion) {
397 AXTreeUpdate initial_state;
398 initial_state.root_id = 1;
399 initial_state.nodes.resize(1);
400 initial_state.nodes[0].id = 1;
401 AXTree tree(initial_state);
402
403 AXEventGenerator event_generator(&tree);
404 AXTreeUpdate update = initial_state;
405 update.nodes.resize(4);
406 update.nodes[0].child_ids.push_back(2);
407 update.nodes[0].child_ids.push_back(3);
408 update.nodes[0].child_ids.push_back(4);
409
410 update.nodes[1].id = 2;
411 update.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kLiveStatus,
412 "polite");
413
414 // Blink should automatically add aria-live="assertive" to elements with role
415 // kAlert, but we should fire an alert event regardless.
416 update.nodes[2].id = 3;
417 update.nodes[2].role = ax::mojom::Role::kAlert;
418
419 // Elements with role kAlertDialog will *not* usually have a live region
420 // status, but again, we should always fire an alert event.
421 update.nodes[3].id = 4;
422 update.nodes[3].role = ax::mojom::Role::kAlertDialog;
423
424 ASSERT_TRUE(tree.Unserialize(update));
425 EXPECT_THAT(
426 event_generator,
427 UnorderedElementsAre(
428 HasEventAtNode(AXEventGenerator::Event::ALERT, 3),
429 HasEventAtNode(AXEventGenerator::Event::ALERT, 4),
430 HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 1),
431 HasEventAtNode(AXEventGenerator::Event::LIVE_REGION_CREATED, 2),
432 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 2),
433 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 3),
434 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 4)));
435 }
436
TEST(AXEventGeneratorTest,LiveRegionChanged)437 TEST(AXEventGeneratorTest, LiveRegionChanged) {
438 AXTreeUpdate initial_state;
439 initial_state.root_id = 1;
440 initial_state.nodes.resize(3);
441 initial_state.nodes[0].id = 1;
442 initial_state.nodes[0].AddStringAttribute(
443 ax::mojom::StringAttribute::kLiveStatus, "polite");
444 initial_state.nodes[0].AddStringAttribute(
445 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
446 initial_state.nodes[0].child_ids.push_back(2);
447 initial_state.nodes[0].child_ids.push_back(3);
448 initial_state.nodes[1].id = 2;
449 initial_state.nodes[1].role = ax::mojom::Role::kStaticText;
450 initial_state.nodes[1].AddStringAttribute(
451 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
452 initial_state.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kName,
453 "Before 1");
454 initial_state.nodes[2].id = 3;
455 initial_state.nodes[2].role = ax::mojom::Role::kStaticText;
456 initial_state.nodes[2].AddStringAttribute(
457 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
458 initial_state.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kName,
459 "Before 2");
460 AXTree tree(initial_state);
461
462 AXEventGenerator event_generator(&tree);
463 AXTreeUpdate update = initial_state;
464 update.nodes[1].string_attributes.clear();
465 update.nodes[1].AddStringAttribute(
466 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
467 update.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kName,
468 "After 1");
469 update.nodes[2].string_attributes.clear();
470 update.nodes[2].AddStringAttribute(
471 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
472 update.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kName,
473 "After 2");
474
475 ASSERT_TRUE(tree.Unserialize(update));
476 EXPECT_THAT(
477 event_generator,
478 UnorderedElementsAre(
479 HasEventAtNode(AXEventGenerator::Event::LIVE_REGION_CHANGED, 1),
480 HasEventAtNode(AXEventGenerator::Event::LIVE_REGION_NODE_CHANGED, 2),
481 HasEventAtNode(AXEventGenerator::Event::LIVE_REGION_NODE_CHANGED, 3),
482 HasEventAtNode(AXEventGenerator::Event::NAME_CHANGED, 2),
483 HasEventAtNode(AXEventGenerator::Event::NAME_CHANGED, 3)));
484 }
485
TEST(AXEventGeneratorTest,LiveRegionOnlyTextChanges)486 TEST(AXEventGeneratorTest, LiveRegionOnlyTextChanges) {
487 AXTreeUpdate initial_state;
488 initial_state.root_id = 1;
489 initial_state.nodes.resize(3);
490 initial_state.nodes[0].id = 1;
491 initial_state.nodes[0].AddStringAttribute(
492 ax::mojom::StringAttribute::kLiveStatus, "polite");
493 initial_state.nodes[0].AddStringAttribute(
494 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
495 initial_state.nodes[0].child_ids.push_back(2);
496 initial_state.nodes[0].child_ids.push_back(3);
497 initial_state.nodes[1].id = 2;
498 initial_state.nodes[1].role = ax::mojom::Role::kStaticText;
499 initial_state.nodes[1].AddStringAttribute(
500 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
501 initial_state.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kName,
502 "Before 1");
503 initial_state.nodes[2].id = 3;
504 initial_state.nodes[2].role = ax::mojom::Role::kStaticText;
505 initial_state.nodes[2].AddStringAttribute(
506 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
507 initial_state.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kName,
508 "Before 2");
509 AXTree tree(initial_state);
510
511 AXEventGenerator event_generator(&tree);
512 AXTreeUpdate update = initial_state;
513 update.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kDescription,
514 "Description 1");
515 update.nodes[2].SetCheckedState(ax::mojom::CheckedState::kTrue);
516
517 // Note that we do NOT expect a LIVE_REGION_CHANGED event here, because
518 // the name did not change.
519 ASSERT_TRUE(tree.Unserialize(update));
520 EXPECT_THAT(
521 event_generator,
522 UnorderedElementsAre(
523 HasEventAtNode(AXEventGenerator::Event::CHECKED_STATE_CHANGED, 3),
524 HasEventAtNode(AXEventGenerator::Event::DESCRIPTION_CHANGED, 2)));
525 }
526
TEST(AXEventGeneratorTest,BusyLiveRegionChanged)527 TEST(AXEventGeneratorTest, BusyLiveRegionChanged) {
528 AXTreeUpdate initial_state;
529 initial_state.root_id = 1;
530 initial_state.nodes.resize(3);
531 initial_state.nodes[0].id = 1;
532 initial_state.nodes[0].AddStringAttribute(
533 ax::mojom::StringAttribute::kLiveStatus, "polite");
534 initial_state.nodes[0].AddStringAttribute(
535 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
536 initial_state.nodes[0].AddBoolAttribute(ax::mojom::BoolAttribute::kBusy,
537 true);
538 initial_state.nodes[0].child_ids.push_back(2);
539 initial_state.nodes[0].child_ids.push_back(3);
540 initial_state.nodes[1].id = 2;
541 initial_state.nodes[1].role = ax::mojom::Role::kStaticText;
542 initial_state.nodes[1].AddStringAttribute(
543 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
544 initial_state.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kName,
545 "Before 1");
546 initial_state.nodes[2].id = 3;
547 initial_state.nodes[2].role = ax::mojom::Role::kStaticText;
548 initial_state.nodes[2].AddStringAttribute(
549 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
550 initial_state.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kName,
551 "Before 2");
552 AXTree tree(initial_state);
553
554 AXEventGenerator event_generator(&tree);
555 AXTreeUpdate update = initial_state;
556 update.nodes[1].string_attributes.clear();
557 update.nodes[1].AddStringAttribute(
558 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
559 update.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kName,
560 "After 1");
561 update.nodes[2].string_attributes.clear();
562 update.nodes[2].AddStringAttribute(
563 ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
564 update.nodes[2].AddStringAttribute(ax::mojom::StringAttribute::kName,
565 "After 2");
566
567 ASSERT_TRUE(tree.Unserialize(update));
568 EXPECT_THAT(event_generator,
569 UnorderedElementsAre(
570 HasEventAtNode(AXEventGenerator::Event::NAME_CHANGED, 2),
571 HasEventAtNode(AXEventGenerator::Event::NAME_CHANGED, 3)));
572 }
573
TEST(AXEventGeneratorTest,AddChild)574 TEST(AXEventGeneratorTest, AddChild) {
575 AXTreeUpdate initial_state;
576 initial_state.root_id = 1;
577 initial_state.nodes.resize(2);
578 initial_state.nodes[0].id = 1;
579 initial_state.nodes[0].child_ids.push_back(2);
580 initial_state.nodes[1].id = 2;
581 AXTree tree(initial_state);
582
583 AXEventGenerator event_generator(&tree);
584 AXTreeUpdate update = initial_state;
585 update.nodes.resize(3);
586 update.nodes[0].child_ids.push_back(3);
587 update.nodes[2].id = 3;
588
589 ASSERT_TRUE(tree.Unserialize(update));
590 EXPECT_THAT(event_generator,
591 UnorderedElementsAre(
592 HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 1),
593 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 3)));
594 }
595
TEST(AXEventGeneratorTest,RemoveChild)596 TEST(AXEventGeneratorTest, RemoveChild) {
597 AXTreeUpdate initial_state;
598 initial_state.root_id = 1;
599 initial_state.nodes.resize(3);
600 initial_state.nodes[0].id = 1;
601 initial_state.nodes[0].child_ids.push_back(2);
602 initial_state.nodes[0].child_ids.push_back(3);
603 initial_state.nodes[1].id = 2;
604 initial_state.nodes[2].id = 3;
605 AXTree tree(initial_state);
606
607 AXEventGenerator event_generator(&tree);
608 AXTreeUpdate update = initial_state;
609 update.nodes.resize(2);
610 update.nodes[0].child_ids.clear();
611 update.nodes[0].child_ids.push_back(2);
612
613 ASSERT_TRUE(tree.Unserialize(update));
614 EXPECT_THAT(event_generator,
615 UnorderedElementsAre(HasEventAtNode(
616 AXEventGenerator::Event::CHILDREN_CHANGED, 1)));
617 }
618
TEST(AXEventGeneratorTest,ReorderChildren)619 TEST(AXEventGeneratorTest, ReorderChildren) {
620 AXTreeUpdate initial_state;
621 initial_state.root_id = 1;
622 initial_state.nodes.resize(3);
623 initial_state.nodes[0].id = 1;
624 initial_state.nodes[0].child_ids.push_back(2);
625 initial_state.nodes[0].child_ids.push_back(3);
626 initial_state.nodes[1].id = 2;
627 initial_state.nodes[2].id = 3;
628 AXTree tree(initial_state);
629
630 AXEventGenerator event_generator(&tree);
631 AXTreeUpdate update = initial_state;
632 update.nodes[0].child_ids.clear();
633 update.nodes[0].child_ids.push_back(3);
634 update.nodes[0].child_ids.push_back(2);
635
636 ASSERT_TRUE(tree.Unserialize(update));
637 EXPECT_THAT(event_generator,
638 UnorderedElementsAre(HasEventAtNode(
639 AXEventGenerator::Event::CHILDREN_CHANGED, 1)));
640 }
641
TEST(AXEventGeneratorTest,ScrollHorizontalPositionChanged)642 TEST(AXEventGeneratorTest, ScrollHorizontalPositionChanged) {
643 AXTreeUpdate initial_state;
644 initial_state.root_id = 1;
645 initial_state.nodes.resize(1);
646 initial_state.nodes[0].id = 1;
647 AXTree tree(initial_state);
648
649 AXEventGenerator event_generator(&tree);
650 AXTreeUpdate update = initial_state;
651 update.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kScrollX, 10);
652 EXPECT_TRUE(tree.Unserialize(update));
653 EXPECT_THAT(
654 event_generator,
655 UnorderedElementsAre(HasEventAtNode(
656 AXEventGenerator::Event::SCROLL_HORIZONTAL_POSITION_CHANGED, 1)));
657 }
658
TEST(AXEventGeneratorTest,ScrollVerticalPositionChanged)659 TEST(AXEventGeneratorTest, ScrollVerticalPositionChanged) {
660 AXTreeUpdate initial_state;
661 initial_state.root_id = 1;
662 initial_state.nodes.resize(1);
663 initial_state.nodes[0].id = 1;
664 AXTree tree(initial_state);
665
666 AXEventGenerator event_generator(&tree);
667 AXTreeUpdate update = initial_state;
668 update.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kScrollY, 10);
669 ASSERT_TRUE(tree.Unserialize(update));
670 EXPECT_THAT(
671 event_generator,
672 UnorderedElementsAre(HasEventAtNode(
673 AXEventGenerator::Event::SCROLL_VERTICAL_POSITION_CHANGED, 1)));
674 }
675
TEST(AXEventGeneratorTest,OtherAttributeChanged)676 TEST(AXEventGeneratorTest, OtherAttributeChanged) {
677 AXTreeUpdate initial_state;
678 initial_state.root_id = 1;
679 initial_state.nodes.resize(6);
680 initial_state.nodes[0].id = 1;
681 initial_state.nodes[0].child_ids.push_back(2);
682 initial_state.nodes[0].child_ids.push_back(3);
683 initial_state.nodes[0].child_ids.push_back(4);
684 initial_state.nodes[0].child_ids.push_back(5);
685 initial_state.nodes[0].child_ids.push_back(6);
686 initial_state.nodes[1].id = 2;
687 initial_state.nodes[2].id = 3;
688 initial_state.nodes[3].id = 4;
689 initial_state.nodes[4].id = 5;
690 initial_state.nodes[5].id = 6;
691 AXTree tree(initial_state);
692
693 AXEventGenerator event_generator(&tree);
694 AXTreeUpdate update = initial_state;
695 update.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kLanguage,
696 "de");
697 update.nodes[2].AddIntAttribute(ax::mojom::IntAttribute::kAriaCellColumnIndex,
698 7);
699 update.nodes[3].AddFloatAttribute(ax::mojom::FloatAttribute::kFontSize,
700 12.0f);
701 update.nodes[4].AddBoolAttribute(ax::mojom::BoolAttribute::kModal, true);
702 std::vector<int> ids = {2};
703 update.nodes[5].AddIntListAttribute(ax::mojom::IntListAttribute::kControlsIds,
704 ids);
705 ASSERT_TRUE(tree.Unserialize(update));
706 EXPECT_THAT(
707 event_generator,
708 UnorderedElementsAre(
709 HasEventAtNode(AXEventGenerator::Event::CONTROLS_CHANGED, 6),
710 HasEventAtNode(AXEventGenerator::Event::LANGUAGE_CHANGED, 2),
711 HasEventAtNode(AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED, 3),
712 HasEventAtNode(AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED, 4),
713 HasEventAtNode(AXEventGenerator::Event::OTHER_ATTRIBUTE_CHANGED, 5),
714 HasEventAtNode(AXEventGenerator::Event::RELATED_NODE_CHANGED, 6)));
715 }
716
TEST(AXEventGeneratorTest,NameChanged)717 TEST(AXEventGeneratorTest, NameChanged) {
718 AXTreeUpdate initial_state;
719 initial_state.root_id = 1;
720 initial_state.nodes.resize(2);
721 initial_state.nodes[0].id = 1;
722 initial_state.nodes[0].child_ids.push_back(2);
723 initial_state.nodes[1].id = 2;
724 AXTree tree(initial_state);
725
726 AXEventGenerator event_generator(&tree);
727 AXTreeUpdate update = initial_state;
728 update.nodes[1].AddStringAttribute(ax::mojom::StringAttribute::kName,
729 "Hello");
730 ASSERT_TRUE(tree.Unserialize(update));
731 EXPECT_THAT(event_generator, UnorderedElementsAre(HasEventAtNode(
732 AXEventGenerator::Event::NAME_CHANGED, 2)));
733 }
734
TEST(AXEventGeneratorTest,DescriptionChanged)735 TEST(AXEventGeneratorTest, DescriptionChanged) {
736 AXTreeUpdate initial_state;
737 initial_state.root_id = 1;
738 initial_state.nodes.resize(1);
739 initial_state.nodes[0].id = 1;
740 AXTree tree(initial_state);
741
742 AXEventGenerator event_generator(&tree);
743 AXTreeUpdate update = initial_state;
744 update.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kDescription,
745 "Hello");
746 ASSERT_TRUE(tree.Unserialize(update));
747 EXPECT_THAT(event_generator,
748 UnorderedElementsAre(HasEventAtNode(
749 AXEventGenerator::Event::DESCRIPTION_CHANGED, 1)));
750 }
751
TEST(AXEventGeneratorTest,RoleChanged)752 TEST(AXEventGeneratorTest, RoleChanged) {
753 AXTreeUpdate initial_state;
754 initial_state.root_id = 1;
755 initial_state.nodes.resize(1);
756 initial_state.nodes[0].id = 1;
757 AXTree tree(initial_state);
758
759 AXEventGenerator event_generator(&tree);
760 AXTreeUpdate update = initial_state;
761 update.nodes[0].role = ax::mojom::Role::kCheckBox;
762 ASSERT_TRUE(tree.Unserialize(update));
763 EXPECT_THAT(event_generator, UnorderedElementsAre(HasEventAtNode(
764 AXEventGenerator::Event::ROLE_CHANGED, 1)));
765 }
766
TEST(AXEventGeneratorTest,MenuItemSelected)767 TEST(AXEventGeneratorTest, MenuItemSelected) {
768 AXTreeUpdate initial_state;
769 initial_state.root_id = 1;
770 initial_state.nodes.resize(3);
771 initial_state.nodes[0].id = 1;
772 initial_state.nodes[0].role = ax::mojom::Role::kMenu;
773 initial_state.nodes[0].child_ids.push_back(2);
774 initial_state.nodes[0].child_ids.push_back(3);
775 initial_state.nodes[0].AddIntAttribute(
776 ax::mojom::IntAttribute::kActivedescendantId, 2);
777 initial_state.nodes[1].id = 2;
778 initial_state.nodes[1].role = ax::mojom::Role::kMenuListOption;
779 initial_state.nodes[2].id = 3;
780 initial_state.nodes[2].role = ax::mojom::Role::kMenuListOption;
781 AXTree tree(initial_state);
782
783 AXEventGenerator event_generator(&tree);
784 AXTreeUpdate update = initial_state;
785 update.nodes[0].int_attributes.clear();
786 update.nodes[0].AddIntAttribute(ax::mojom::IntAttribute::kActivedescendantId,
787 3);
788 ASSERT_TRUE(tree.Unserialize(update));
789 EXPECT_THAT(
790 event_generator,
791 UnorderedElementsAre(
792 HasEventAtNode(AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED, 1),
793 HasEventAtNode(AXEventGenerator::Event::MENU_ITEM_SELECTED, 3),
794 HasEventAtNode(AXEventGenerator::Event::RELATED_NODE_CHANGED, 1)));
795 }
796
TEST(AXEventGeneratorTest,NodeBecomesIgnored)797 TEST(AXEventGeneratorTest, NodeBecomesIgnored) {
798 AXTreeUpdate initial_state;
799 initial_state.root_id = 1;
800 initial_state.nodes.resize(5);
801 initial_state.nodes[0].id = 1;
802 initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
803 initial_state.nodes[0].child_ids.push_back(2);
804 initial_state.nodes[1].id = 2;
805 initial_state.nodes[1].role = ax::mojom::Role::kArticle;
806 initial_state.nodes[1].child_ids.push_back(3);
807 initial_state.nodes[2].id = 3;
808 initial_state.nodes[2].role = ax::mojom::Role::kGroup;
809 initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
810 initial_state.nodes[2].child_ids.push_back(4);
811 initial_state.nodes[3].id = 4;
812 initial_state.nodes[3].role = ax::mojom::Role::kGroup;
813 initial_state.nodes[3].child_ids.push_back(5);
814 initial_state.nodes[4].id = 5;
815 initial_state.nodes[4].role = ax::mojom::Role::kStaticText;
816
817 AXTree tree(initial_state);
818
819 AXEventGenerator event_generator(&tree);
820 AXTreeUpdate update = initial_state;
821 update.nodes[3].AddState(ax::mojom::State::kIgnored);
822 ASSERT_TRUE(tree.Unserialize(update));
823 EXPECT_THAT(event_generator,
824 UnorderedElementsAre(
825 HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 2),
826 HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 4)));
827 }
828
TEST(AXEventGeneratorTest,NodeBecomesIgnored2)829 TEST(AXEventGeneratorTest, NodeBecomesIgnored2) {
830 AXTreeUpdate initial_state;
831 initial_state.root_id = 1;
832 initial_state.nodes.resize(5);
833 initial_state.nodes[0].id = 1;
834 initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
835 initial_state.nodes[0].child_ids.push_back(2);
836 initial_state.nodes[1].id = 2;
837 initial_state.nodes[1].role = ax::mojom::Role::kArticle;
838 initial_state.nodes[1].child_ids.push_back(3);
839 initial_state.nodes[2].id = 3;
840 initial_state.nodes[2].role = ax::mojom::Role::kGroup;
841 initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
842 initial_state.nodes[2].child_ids.push_back(4);
843 initial_state.nodes[3].id = 4;
844 initial_state.nodes[3].role = ax::mojom::Role::kGroup;
845 initial_state.nodes[3].child_ids.push_back(5);
846 initial_state.nodes[4].id = 5;
847 initial_state.nodes[4].role = ax::mojom::Role::kStaticText;
848
849 AXTree tree(initial_state);
850
851 AXEventGenerator event_generator(&tree);
852 AXTreeUpdate update = initial_state;
853 // Marking as ignored should fire CHILDREN_CHANGED on 2
854 update.nodes[3].AddState(ax::mojom::State::kIgnored);
855 // Remove node id 5 so it also fires CHILDREN_CHANGED on 4.
856 update.nodes.pop_back();
857 update.nodes[3].child_ids.clear();
858 ASSERT_TRUE(tree.Unserialize(update));
859 EXPECT_THAT(event_generator,
860 UnorderedElementsAre(
861 HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 2),
862 HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 4)));
863 }
864
TEST(AXEventGeneratorTest,NodeBecomesUnignored)865 TEST(AXEventGeneratorTest, NodeBecomesUnignored) {
866 AXTreeUpdate initial_state;
867 initial_state.root_id = 1;
868 initial_state.nodes.resize(5);
869 initial_state.nodes[0].id = 1;
870 initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
871 initial_state.nodes[0].child_ids.push_back(2);
872 initial_state.nodes[1].id = 2;
873 initial_state.nodes[1].role = ax::mojom::Role::kArticle;
874 initial_state.nodes[1].child_ids.push_back(3);
875 initial_state.nodes[2].id = 3;
876 initial_state.nodes[2].role = ax::mojom::Role::kGroup;
877 initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
878 initial_state.nodes[2].child_ids.push_back(4);
879 initial_state.nodes[3].id = 4;
880 initial_state.nodes[3].role = ax::mojom::Role::kGroup;
881 initial_state.nodes[3].AddState(ax::mojom::State::kIgnored);
882 initial_state.nodes[3].child_ids.push_back(5);
883 initial_state.nodes[4].id = 5;
884 initial_state.nodes[4].role = ax::mojom::Role::kStaticText;
885
886 AXTree tree(initial_state);
887
888 AXEventGenerator event_generator(&tree);
889 AXTreeUpdate update = initial_state;
890 update.nodes[3].state = 0;
891 ASSERT_TRUE(tree.Unserialize(update));
892 EXPECT_THAT(event_generator,
893 UnorderedElementsAre(
894 HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 2),
895 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 4),
896 HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 4)));
897 }
898
TEST(AXEventGeneratorTest,NodeBecomesUnignored2)899 TEST(AXEventGeneratorTest, NodeBecomesUnignored2) {
900 AXTreeUpdate initial_state;
901 initial_state.root_id = 1;
902 initial_state.nodes.resize(5);
903 initial_state.nodes[0].id = 1;
904 initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
905 initial_state.nodes[0].child_ids.push_back(2);
906 initial_state.nodes[1].id = 2;
907 initial_state.nodes[1].role = ax::mojom::Role::kArticle;
908 initial_state.nodes[1].child_ids.push_back(3);
909 initial_state.nodes[2].id = 3;
910 initial_state.nodes[2].role = ax::mojom::Role::kGroup;
911 initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
912 initial_state.nodes[2].child_ids.push_back(4);
913 initial_state.nodes[3].id = 4;
914 initial_state.nodes[3].role = ax::mojom::Role::kGroup;
915 initial_state.nodes[3].AddState(ax::mojom::State::kIgnored);
916 initial_state.nodes[3].child_ids.push_back(5);
917 initial_state.nodes[4].id = 5;
918 initial_state.nodes[4].role = ax::mojom::Role::kStaticText;
919
920 AXTree tree(initial_state);
921
922 AXEventGenerator event_generator(&tree);
923 AXTreeUpdate update = initial_state;
924 // Marking as no longer ignored should fire CHILDREN_CHANGED on 2
925 update.nodes[3].state = 0;
926 // Remove node id 5 so it also fires CHILDREN_CHANGED on 4.
927 update.nodes.pop_back();
928 update.nodes[3].child_ids.clear();
929 ASSERT_TRUE(tree.Unserialize(update));
930 EXPECT_THAT(event_generator,
931 UnorderedElementsAre(
932 HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 2),
933 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 4),
934 HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 4)));
935 }
936
TEST(AXEventGeneratorTest,SubtreeBecomesUnignored)937 TEST(AXEventGeneratorTest, SubtreeBecomesUnignored) {
938 AXTreeUpdate initial_state;
939 initial_state.root_id = 1;
940 initial_state.nodes.resize(3);
941 initial_state.nodes[0].id = 1;
942 initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
943 initial_state.nodes[0].child_ids.push_back(2);
944 initial_state.nodes[1].id = 2;
945 initial_state.nodes[1].role = ax::mojom::Role::kArticle;
946 initial_state.nodes[1].AddState(ax::mojom::State::kIgnored);
947 initial_state.nodes[1].child_ids.push_back(3);
948 initial_state.nodes[2].id = 3;
949 initial_state.nodes[2].role = ax::mojom::Role::kGroup;
950 initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
951
952 AXTree tree(initial_state);
953
954 AXEventGenerator event_generator(&tree);
955 AXTreeUpdate update = initial_state;
956 update.nodes[1].RemoveState(ax::mojom::State::kIgnored);
957 update.nodes[2].RemoveState(ax::mojom::State::kIgnored);
958 ASSERT_TRUE(tree.Unserialize(update));
959 EXPECT_THAT(event_generator,
960 UnorderedElementsAre(
961 HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 1),
962 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 2),
963 HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 2),
964 HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 3)));
965 }
966
TEST(AXEventGeneratorTest,TwoNodesSwapIgnored)967 TEST(AXEventGeneratorTest, TwoNodesSwapIgnored) {
968 AXTreeUpdate initial_state;
969 initial_state.root_id = 1;
970 initial_state.nodes.resize(3);
971 initial_state.nodes[0].id = 1;
972 initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
973 initial_state.nodes[0].child_ids.push_back(2);
974 initial_state.nodes[1].id = 2;
975 initial_state.nodes[1].role = ax::mojom::Role::kArticle;
976 initial_state.nodes[1].child_ids.push_back(3);
977 initial_state.nodes[2].id = 3;
978 initial_state.nodes[2].role = ax::mojom::Role::kGroup;
979 initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
980
981 AXTree tree(initial_state);
982
983 AXEventGenerator event_generator(&tree);
984 AXTreeUpdate update = initial_state;
985 update.nodes[1].AddState(ax::mojom::State::kIgnored);
986 update.nodes[2].RemoveState(ax::mojom::State::kIgnored);
987 ASSERT_TRUE(tree.Unserialize(update));
988 EXPECT_THAT(event_generator,
989 UnorderedElementsAre(
990 HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 1),
991 HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 2),
992 HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 3),
993 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 3)));
994 }
995
TEST(AXEventGeneratorTest,TwoNodesSwapIgnored2)996 TEST(AXEventGeneratorTest, TwoNodesSwapIgnored2) {
997 AXTreeUpdate initial_state;
998 initial_state.root_id = 1;
999 initial_state.nodes.resize(3);
1000 initial_state.nodes[0].id = 1;
1001 initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
1002 initial_state.nodes[0].child_ids.push_back(2);
1003 initial_state.nodes[1].id = 2;
1004 initial_state.nodes[1].role = ax::mojom::Role::kArticle;
1005 initial_state.nodes[1].AddState(ax::mojom::State::kIgnored);
1006 initial_state.nodes[1].child_ids.push_back(3);
1007 initial_state.nodes[2].id = 3;
1008 initial_state.nodes[2].role = ax::mojom::Role::kGroup;
1009
1010 AXTree tree(initial_state);
1011
1012 AXEventGenerator event_generator(&tree);
1013 AXTreeUpdate update = initial_state;
1014 update.nodes[1].RemoveState(ax::mojom::State::kIgnored);
1015 update.nodes[2].AddState(ax::mojom::State::kIgnored);
1016 ASSERT_TRUE(tree.Unserialize(update));
1017 EXPECT_THAT(event_generator,
1018 UnorderedElementsAre(
1019 HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 1),
1020 HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 2),
1021 HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 3),
1022 HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 2)));
1023 }
1024
TEST(AXEventGeneratorTest,ActiveDescendantChangeOnDescendant)1025 TEST(AXEventGeneratorTest, ActiveDescendantChangeOnDescendant) {
1026 AXTreeUpdate initial_state;
1027 initial_state.root_id = 1;
1028 initial_state.nodes.resize(5);
1029 initial_state.nodes[0].id = 1;
1030 initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
1031 initial_state.nodes[0].child_ids.push_back(2);
1032 initial_state.nodes[1].id = 2;
1033 initial_state.nodes[1].role = ax::mojom::Role::kGenericContainer;
1034 initial_state.nodes[1].child_ids.push_back(3);
1035 initial_state.nodes[2].id = 3;
1036 initial_state.nodes[2].role = ax::mojom::Role::kGroup;
1037 initial_state.nodes[2].AddIntAttribute(
1038 ax::mojom::IntAttribute::kActivedescendantId, 4);
1039 initial_state.nodes[2].child_ids.push_back(4);
1040 initial_state.nodes[2].child_ids.push_back(5);
1041 initial_state.nodes[3].id = 4;
1042 initial_state.nodes[3].role = ax::mojom::Role::kGroup;
1043 initial_state.nodes[4].id = 5;
1044 initial_state.nodes[4].role = ax::mojom::Role::kGroup;
1045
1046 AXTree tree(initial_state);
1047
1048 AXEventGenerator event_generator(&tree);
1049 initial_state.nodes[2].RemoveIntAttribute(
1050 ax::mojom::IntAttribute::kActivedescendantId);
1051 initial_state.nodes[2].AddIntAttribute(
1052 ax::mojom::IntAttribute::kActivedescendantId, 5);
1053 AXTreeUpdate update = initial_state;
1054 update.node_id_to_clear = 2;
1055 ASSERT_TRUE(tree.Unserialize(update));
1056 EXPECT_THAT(
1057 event_generator,
1058 UnorderedElementsAre(
1059 HasEventAtNode(AXEventGenerator::Event::ACTIVE_DESCENDANT_CHANGED, 3),
1060 HasEventAtNode(AXEventGenerator::Event::RELATED_NODE_CHANGED, 3)));
1061 }
1062
TEST(AXEventGeneratorTest,ImageAnnotationChanged)1063 TEST(AXEventGeneratorTest, ImageAnnotationChanged) {
1064 AXTreeUpdate initial_state;
1065 initial_state.root_id = 1;
1066 initial_state.nodes.resize(1);
1067 initial_state.nodes[0].id = 1;
1068 AXTree tree(initial_state);
1069
1070 AXEventGenerator event_generator(&tree);
1071 AXTreeUpdate update = initial_state;
1072 update.nodes[0].AddStringAttribute(
1073 ax::mojom::StringAttribute::kImageAnnotation, "Hello");
1074 ASSERT_TRUE(tree.Unserialize(update));
1075 EXPECT_THAT(event_generator,
1076 UnorderedElementsAre(HasEventAtNode(
1077 AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED, 1)));
1078 }
1079
TEST(AXEventGeneratorTest,ImageAnnotationStatusChanged)1080 TEST(AXEventGeneratorTest, ImageAnnotationStatusChanged) {
1081 AXTreeUpdate initial_state;
1082 initial_state.root_id = 1;
1083 initial_state.nodes.resize(1);
1084 initial_state.nodes[0].id = 1;
1085 AXTree tree(initial_state);
1086
1087 AXEventGenerator event_generator(&tree);
1088 AXTreeUpdate update = initial_state;
1089 update.nodes[0].SetImageAnnotationStatus(
1090 ax::mojom::ImageAnnotationStatus::kAnnotationSucceeded);
1091
1092 ASSERT_TRUE(tree.Unserialize(update));
1093 EXPECT_THAT(event_generator,
1094 UnorderedElementsAre(HasEventAtNode(
1095 AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED, 1)));
1096 }
1097
TEST(AXEventGeneratorTest,StringPropertyChanges)1098 TEST(AXEventGeneratorTest, StringPropertyChanges) {
1099 AXTreeUpdate initial_state;
1100 initial_state.root_id = 1;
1101 initial_state.nodes.resize(1);
1102 initial_state.nodes[0].id = 1;
1103
1104 struct {
1105 ax::mojom::StringAttribute id;
1106 std::string old_value;
1107 std::string new_value;
1108 } attributes[] = {
1109 {ax::mojom::StringAttribute::kAccessKey, "a", "b"},
1110 {ax::mojom::StringAttribute::kClassName, "a", "b"},
1111 {ax::mojom::StringAttribute::kKeyShortcuts, "a", "b"},
1112 {ax::mojom::StringAttribute::kLanguage, "a", "b"},
1113 {ax::mojom::StringAttribute::kPlaceholder, "a", "b"},
1114 };
1115 for (auto&& attrib : attributes) {
1116 initial_state.nodes.push_back({});
1117 initial_state.nodes.back().id = initial_state.nodes.size();
1118 initial_state.nodes.back().AddStringAttribute(attrib.id, attrib.old_value);
1119 initial_state.nodes[0].child_ids.push_back(initial_state.nodes.size());
1120 }
1121
1122 AXTree tree(initial_state);
1123
1124 AXEventGenerator event_generator(&tree);
1125 int index = 1;
1126 for (auto&& attrib : attributes) {
1127 initial_state.nodes[index++].AddStringAttribute(attrib.id,
1128 attrib.new_value);
1129 }
1130
1131 AXTreeUpdate update = initial_state;
1132 EXPECT_TRUE(tree.Unserialize(update));
1133 EXPECT_THAT(
1134 event_generator,
1135 UnorderedElementsAre(
1136 HasEventAtNode(AXEventGenerator::Event::ACCESS_KEY_CHANGED, 2),
1137 HasEventAtNode(AXEventGenerator::Event::CLASS_NAME_CHANGED, 3),
1138 HasEventAtNode(AXEventGenerator::Event::KEY_SHORTCUTS_CHANGED, 4),
1139 HasEventAtNode(AXEventGenerator::Event::LANGUAGE_CHANGED, 5),
1140 HasEventAtNode(AXEventGenerator::Event::PLACEHOLDER_CHANGED, 6)));
1141 }
1142
TEST(AXEventGeneratorTest,IntPropertyChanges)1143 TEST(AXEventGeneratorTest, IntPropertyChanges) {
1144 AXTreeUpdate initial_state;
1145 initial_state.root_id = 1;
1146 initial_state.nodes.resize(1);
1147 initial_state.nodes[0].id = 1;
1148
1149 struct {
1150 ax::mojom::IntAttribute id;
1151 int old_value;
1152 int new_value;
1153 } attributes[] = {
1154 {ax::mojom::IntAttribute::kHierarchicalLevel, 1, 2},
1155 {ax::mojom::IntAttribute::kPosInSet, 1, 2},
1156 {ax::mojom::IntAttribute::kSetSize, 1, 2},
1157 };
1158 for (auto&& attrib : attributes) {
1159 initial_state.nodes.push_back({});
1160 initial_state.nodes.back().id = initial_state.nodes.size();
1161 initial_state.nodes.back().AddIntAttribute(attrib.id, attrib.old_value);
1162 initial_state.nodes[0].child_ids.push_back(initial_state.nodes.size());
1163 }
1164
1165 AXTree tree(initial_state);
1166
1167 AXEventGenerator event_generator(&tree);
1168 int index = 1;
1169 for (auto&& attrib : attributes)
1170 initial_state.nodes[index++].AddIntAttribute(attrib.id, attrib.new_value);
1171
1172 AXTreeUpdate update = initial_state;
1173 EXPECT_TRUE(tree.Unserialize(update));
1174 EXPECT_THAT(
1175 event_generator,
1176 UnorderedElementsAre(
1177 HasEventAtNode(AXEventGenerator::Event::HIERARCHICAL_LEVEL_CHANGED,
1178 2),
1179 HasEventAtNode(AXEventGenerator::Event::POSITION_IN_SET_CHANGED, 3),
1180 HasEventAtNode(AXEventGenerator::Event::SET_SIZE_CHANGED, 4)));
1181 }
1182
TEST(AXEventGeneratorTest,IntListPropertyChanges)1183 TEST(AXEventGeneratorTest, IntListPropertyChanges) {
1184 AXTreeUpdate initial_state;
1185 initial_state.root_id = 1;
1186 initial_state.nodes.resize(1);
1187 initial_state.nodes[0].id = 1;
1188
1189 struct {
1190 ax::mojom::IntListAttribute id;
1191 std::vector<int> old_value;
1192 std::vector<int> new_value;
1193 } attributes[] = {
1194 {ax::mojom::IntListAttribute::kDescribedbyIds, {1}, {2}},
1195 {ax::mojom::IntListAttribute::kFlowtoIds, {1}, {2}},
1196 {ax::mojom::IntListAttribute::kLabelledbyIds, {1}, {2}},
1197 };
1198 for (auto&& attrib : attributes) {
1199 initial_state.nodes.push_back({});
1200 initial_state.nodes.back().id = initial_state.nodes.size();
1201 initial_state.nodes.back().AddIntListAttribute(attrib.id, attrib.old_value);
1202 initial_state.nodes[0].child_ids.push_back(initial_state.nodes.size());
1203 }
1204
1205 AXTree tree(initial_state);
1206
1207 AXEventGenerator event_generator(&tree);
1208 int index = 1;
1209 for (auto&& attrib : attributes) {
1210 initial_state.nodes[index++].AddIntListAttribute(attrib.id,
1211 attrib.new_value);
1212 }
1213
1214 AXTreeUpdate update = initial_state;
1215 EXPECT_TRUE(tree.Unserialize(update));
1216 EXPECT_THAT(
1217 event_generator,
1218 UnorderedElementsAre(
1219 HasEventAtNode(AXEventGenerator::Event::DESCRIBED_BY_CHANGED, 2),
1220 HasEventAtNode(AXEventGenerator::Event::FLOW_FROM_CHANGED, 1),
1221 HasEventAtNode(AXEventGenerator::Event::FLOW_FROM_CHANGED, 2),
1222 HasEventAtNode(AXEventGenerator::Event::FLOW_TO_CHANGED, 3),
1223 HasEventAtNode(AXEventGenerator::Event::LABELED_BY_CHANGED, 4),
1224 HasEventAtNode(AXEventGenerator::Event::RELATED_NODE_CHANGED, 2),
1225 HasEventAtNode(AXEventGenerator::Event::RELATED_NODE_CHANGED, 3),
1226 HasEventAtNode(AXEventGenerator::Event::RELATED_NODE_CHANGED, 4)));
1227 }
1228
TEST(AXEventGeneratorTest,AriaBusyChanged)1229 TEST(AXEventGeneratorTest, AriaBusyChanged) {
1230 AXTreeUpdate initial_state;
1231 initial_state.root_id = 1;
1232 initial_state.nodes.resize(1);
1233 initial_state.nodes[0].id = 1;
1234 AXTree tree(initial_state);
1235 initial_state.nodes[0].AddBoolAttribute(ax::mojom::BoolAttribute::kBusy,
1236 true);
1237
1238 AXEventGenerator event_generator(&tree);
1239 AXTreeUpdate update = initial_state;
1240 update.nodes[0].AddBoolAttribute(ax::mojom::BoolAttribute::kBusy, false);
1241
1242 ASSERT_TRUE(tree.Unserialize(update));
1243 EXPECT_THAT(
1244 event_generator,
1245 UnorderedElementsAre(
1246 HasEventAtNode(AXEventGenerator::Event::BUSY_CHANGED, 1),
1247 HasEventAtNode(AXEventGenerator::Event::LAYOUT_INVALIDATED, 1)));
1248 }
1249
TEST(AXEventGeneratorTest,MultiselectableStateChanged)1250 TEST(AXEventGeneratorTest, MultiselectableStateChanged) {
1251 AXTreeUpdate initial_state;
1252 initial_state.root_id = 1;
1253 initial_state.nodes.resize(1);
1254 initial_state.nodes[0].id = 1;
1255 initial_state.nodes[0].role = ax::mojom::Role::kGrid;
1256
1257 AXTree tree(initial_state);
1258 AXEventGenerator event_generator(&tree);
1259 AXTreeUpdate update = initial_state;
1260
1261 update.nodes[0].AddState(ax::mojom::State::kMultiselectable);
1262 EXPECT_TRUE(tree.Unserialize(update));
1263 EXPECT_THAT(
1264 event_generator,
1265 UnorderedElementsAre(
1266 HasEventAtNode(AXEventGenerator::Event::MULTISELECTABLE_STATE_CHANGED,
1267 1),
1268 HasEventAtNode(AXEventGenerator::Event::STATE_CHANGED, 1)));
1269 }
1270
TEST(AXEventGeneratorTest,RequiredStateChanged)1271 TEST(AXEventGeneratorTest, RequiredStateChanged) {
1272 AXTreeUpdate initial_state;
1273 initial_state.root_id = 1;
1274 initial_state.nodes.resize(1);
1275 initial_state.nodes[0].id = 1;
1276 initial_state.nodes[0].role = ax::mojom::Role::kTextField;
1277
1278 AXTree tree(initial_state);
1279 AXEventGenerator event_generator(&tree);
1280 AXTreeUpdate update = initial_state;
1281
1282 update.nodes[0].AddState(ax::mojom::State::kRequired);
1283 EXPECT_TRUE(tree.Unserialize(update));
1284 EXPECT_THAT(
1285 event_generator,
1286 UnorderedElementsAre(
1287 HasEventAtNode(AXEventGenerator::Event::REQUIRED_STATE_CHANGED, 1),
1288 HasEventAtNode(AXEventGenerator::Event::STATE_CHANGED, 1)));
1289 }
1290
TEST(AXEventGeneratorTest,FlowToChanged)1291 TEST(AXEventGeneratorTest, FlowToChanged) {
1292 AXTreeUpdate initial_state;
1293 initial_state.root_id = 1;
1294 initial_state.nodes.resize(6);
1295 initial_state.nodes[0].id = 1;
1296 initial_state.nodes[0].role = ax::mojom::Role::kGenericContainer;
1297 initial_state.nodes[0].child_ids.assign({2, 3, 4, 5, 6});
1298 initial_state.nodes[1].id = 2;
1299 initial_state.nodes[1].role = ax::mojom::Role::kGenericContainer;
1300 initial_state.nodes[1].AddIntListAttribute(
1301 ax::mojom::IntListAttribute::kFlowtoIds, {3, 4});
1302 initial_state.nodes[2].id = 3;
1303 initial_state.nodes[2].role = ax::mojom::Role::kGenericContainer;
1304 initial_state.nodes[3].id = 4;
1305 initial_state.nodes[3].role = ax::mojom::Role::kGenericContainer;
1306 initial_state.nodes[4].id = 5;
1307 initial_state.nodes[4].role = ax::mojom::Role::kGenericContainer;
1308 initial_state.nodes[5].id = 6;
1309 initial_state.nodes[5].role = ax::mojom::Role::kGenericContainer;
1310
1311 AXTree tree(initial_state);
1312
1313 AXEventGenerator event_generator(&tree);
1314 AXTreeUpdate update = initial_state;
1315 update.nodes[1].AddIntListAttribute(ax::mojom::IntListAttribute::kFlowtoIds,
1316 {4, 5, 6});
1317
1318 EXPECT_TRUE(tree.Unserialize(update));
1319 EXPECT_THAT(
1320 event_generator,
1321 UnorderedElementsAre(
1322 HasEventAtNode(AXEventGenerator::Event::FLOW_FROM_CHANGED, 3),
1323 HasEventAtNode(AXEventGenerator::Event::FLOW_FROM_CHANGED, 5),
1324 HasEventAtNode(AXEventGenerator::Event::FLOW_FROM_CHANGED, 6),
1325 HasEventAtNode(AXEventGenerator::Event::FLOW_TO_CHANGED, 2),
1326 HasEventAtNode(AXEventGenerator::Event::RELATED_NODE_CHANGED, 2)));
1327 }
1328
TEST(AXEventGeneratorTest,ControlsChanged)1329 TEST(AXEventGeneratorTest, ControlsChanged) {
1330 AXTreeUpdate initial_state;
1331 initial_state.root_id = 1;
1332 initial_state.nodes.resize(2);
1333 initial_state.nodes[0].id = 1;
1334 initial_state.nodes[0].child_ids.push_back(2);
1335 initial_state.nodes[1].id = 2;
1336
1337 AXTree tree(initial_state);
1338 AXEventGenerator event_generator(&tree);
1339 AXTreeUpdate update = initial_state;
1340
1341 std::vector<int> ids = {2};
1342 update.nodes[0].AddIntListAttribute(ax::mojom::IntListAttribute::kControlsIds,
1343 ids);
1344 EXPECT_TRUE(tree.Unserialize(update));
1345 EXPECT_THAT(
1346 event_generator,
1347 UnorderedElementsAre(
1348 HasEventAtNode(AXEventGenerator::Event::CONTROLS_CHANGED, 1),
1349 HasEventAtNode(AXEventGenerator::Event::RELATED_NODE_CHANGED, 1)));
1350 }
1351
TEST(AXEventGeneratorTest,AtomicChanged)1352 TEST(AXEventGeneratorTest, AtomicChanged) {
1353 AXTreeUpdate initial_state;
1354 initial_state.root_id = 1;
1355 initial_state.nodes.resize(1);
1356 initial_state.nodes[0].id = 1;
1357
1358 AXTree tree(initial_state);
1359 AXEventGenerator event_generator(&tree);
1360 AXTreeUpdate update = initial_state;
1361
1362 update.nodes[0].AddBoolAttribute(ax::mojom::BoolAttribute::kLiveAtomic, true);
1363 EXPECT_TRUE(tree.Unserialize(update));
1364 EXPECT_THAT(event_generator,
1365 UnorderedElementsAre(
1366 HasEventAtNode(AXEventGenerator::Event::ATOMIC_CHANGED, 1)));
1367 }
1368
TEST(AXEventGeneratorTest,DropeffectChanged)1369 TEST(AXEventGeneratorTest, DropeffectChanged) {
1370 AXTreeUpdate initial_state;
1371 initial_state.root_id = 1;
1372 initial_state.nodes.resize(1);
1373 initial_state.nodes[0].id = 1;
1374
1375 AXTree tree(initial_state);
1376 AXEventGenerator event_generator(&tree);
1377 AXTreeUpdate update = initial_state;
1378
1379 update.nodes[0].AddDropeffect(ax::mojom::Dropeffect::kCopy);
1380 EXPECT_TRUE(tree.Unserialize(update));
1381 EXPECT_THAT(event_generator,
1382 UnorderedElementsAre(HasEventAtNode(
1383 AXEventGenerator::Event::DROPEFFECT_CHANGED, 1)));
1384 }
1385
TEST(AXEventGeneratorTest,GrabbedChanged)1386 TEST(AXEventGeneratorTest, GrabbedChanged) {
1387 AXTreeUpdate initial_state;
1388 initial_state.root_id = 1;
1389 initial_state.nodes.resize(1);
1390 initial_state.nodes[0].id = 1;
1391
1392 AXTree tree(initial_state);
1393 AXEventGenerator event_generator(&tree);
1394 AXTreeUpdate update = initial_state;
1395
1396 update.nodes[0].AddBoolAttribute(ax::mojom::BoolAttribute::kGrabbed, true);
1397 EXPECT_TRUE(tree.Unserialize(update));
1398 EXPECT_THAT(event_generator,
1399 UnorderedElementsAre(
1400 HasEventAtNode(AXEventGenerator::Event::GRABBED_CHANGED, 1)));
1401 }
1402
TEST(AXEventGeneratorTest,HasPopupChanged)1403 TEST(AXEventGeneratorTest, HasPopupChanged) {
1404 AXTreeUpdate initial_state;
1405 initial_state.root_id = 1;
1406 initial_state.nodes.resize(1);
1407 initial_state.nodes[0].id = 1;
1408
1409 AXTree tree(initial_state);
1410 AXEventGenerator event_generator(&tree);
1411 AXTreeUpdate update = initial_state;
1412
1413 update.nodes[0].SetHasPopup(ax::mojom::HasPopup::kTrue);
1414 EXPECT_TRUE(tree.Unserialize(update));
1415 EXPECT_THAT(event_generator,
1416 UnorderedElementsAre(HasEventAtNode(
1417 AXEventGenerator::Event::HASPOPUP_CHANGED, 1)));
1418 }
1419
TEST(AXEventGeneratorTest,LiveRelevantChanged)1420 TEST(AXEventGeneratorTest, LiveRelevantChanged) {
1421 AXTreeUpdate initial_state;
1422 initial_state.root_id = 1;
1423 initial_state.nodes.resize(1);
1424 initial_state.nodes[0].id = 1;
1425
1426 AXTree tree(initial_state);
1427 AXEventGenerator event_generator(&tree);
1428 AXTreeUpdate update = initial_state;
1429
1430 update.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kLiveRelevant,
1431 "all");
1432 EXPECT_TRUE(tree.Unserialize(update));
1433 EXPECT_THAT(event_generator,
1434 UnorderedElementsAre(HasEventAtNode(
1435 AXEventGenerator::Event::LIVE_RELEVANT_CHANGED, 1)));
1436 }
1437
TEST(AXEventGeneratorTest,MultilineStateChanged)1438 TEST(AXEventGeneratorTest, MultilineStateChanged) {
1439 AXTreeUpdate initial_state;
1440 initial_state.root_id = 1;
1441 initial_state.nodes.resize(1);
1442 initial_state.nodes[0].id = 1;
1443
1444 AXTree tree(initial_state);
1445 AXEventGenerator event_generator(&tree);
1446 AXTreeUpdate update = initial_state;
1447
1448 update.nodes[0].AddState(ax::mojom::State::kMultiline);
1449 EXPECT_TRUE(tree.Unserialize(update));
1450 EXPECT_THAT(
1451 event_generator,
1452 UnorderedElementsAre(
1453 HasEventAtNode(AXEventGenerator::Event::MULTILINE_STATE_CHANGED, 1),
1454 HasEventAtNode(AXEventGenerator::Event::STATE_CHANGED, 1)));
1455 }
1456
1457 } // namespace ui
1458