4 #include "flutter/testing/testing.h"
16 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
17 #include "flutter/third_party/accessibility/ax/ax_action_data.h"
24 NSString* fixtures = @(testing::GetFixturesPath());
26 initWithAssetsPath:fixtures
27 ICUDataPath:[fixtures stringByAppendingString:
@"/icudtl.dat"]];
35 engine.semanticsEnabled = YES;
36 auto bridge = viewController.accessibilityBridge.lock();
38 FlutterSemanticsNode2 root;
39 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
43 root.actions =
static_cast<FlutterSemanticsAction
>(0);
44 root.text_selection_base = -1;
45 root.text_selection_extent = -1;
46 root.label =
"accessibility";
49 root.increased_value =
"";
50 root.decreased_value =
"";
53 root.custom_accessibility_actions_count = 0;
55 bridge->AddFlutterSemanticsNodeUpdate(root);
57 bridge->CommitUpdates();
59 auto root_platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
61 NSAccessibilityElement* native_accessibility =
62 root_platform_node_delegate->GetNativeViewAccessible();
63 std::string value = [native_accessibility.accessibilityValue UTF8String];
64 EXPECT_TRUE(value ==
"accessibility");
65 EXPECT_EQ(native_accessibility.accessibilityRole, NSAccessibilityStaticTextRole);
66 EXPECT_EQ([native_accessibility.accessibilityChildren count], 0u);
67 [engine shutDownEngine];
73 engine.semanticsEnabled = YES;
74 auto bridge = viewController.accessibilityBridge.lock();
76 FlutterSemanticsNode2 root;
77 FlutterSemanticsFlags flags = FlutterSemanticsFlags{.is_text_field =
true, .is_read_only =
true};
81 root.actions =
static_cast<FlutterSemanticsAction
>(0);
82 root.text_selection_base = 1;
83 root.text_selection_extent = 3;
87 root.value =
"selectable text";
88 root.increased_value =
"";
89 root.decreased_value =
"";
92 root.custom_accessibility_actions_count = 0;
94 bridge->AddFlutterSemanticsNodeUpdate(root);
96 bridge->CommitUpdates();
98 auto root_platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
100 NSAccessibilityElement* native_accessibility =
101 root_platform_node_delegate->GetNativeViewAccessible();
102 std::string value = [native_accessibility.accessibilityValue UTF8String];
103 EXPECT_EQ(value,
"selectable text");
104 EXPECT_EQ(native_accessibility.accessibilityRole, NSAccessibilityStaticTextRole);
105 EXPECT_EQ([native_accessibility.accessibilityChildren count], 0u);
106 NSRange selection = native_accessibility.accessibilitySelectedTextRange;
107 EXPECT_EQ(selection.location, 1u);
108 EXPECT_EQ(selection.length, 2u);
109 std::string selected_text = [native_accessibility.accessibilitySelectedText UTF8String];
110 EXPECT_EQ(selected_text,
"el");
116 engine.semanticsEnabled = YES;
117 auto bridge = viewController.accessibilityBridge.lock();
119 FlutterSemanticsNode2 root;
120 FlutterSemanticsFlags flags = FlutterSemanticsFlags{.is_text_field =
true, .is_read_only =
true};
122 root.flags2 = &flags;
124 root.actions =
static_cast<FlutterSemanticsAction
>(0);
125 root.text_selection_base = -1;
126 root.text_selection_extent = -1;
130 root.value =
"selectable text";
131 root.increased_value =
"";
132 root.decreased_value =
"";
134 root.child_count = 0;
135 root.custom_accessibility_actions_count = 0;
136 root.identifier =
"";
137 bridge->AddFlutterSemanticsNodeUpdate(root);
139 bridge->CommitUpdates();
141 auto root_platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
143 NSAccessibilityElement* native_accessibility =
144 root_platform_node_delegate->GetNativeViewAccessible();
145 NSRange selection = native_accessibility.accessibilitySelectedTextRange;
146 EXPECT_TRUE(selection.location == NSNotFound);
147 EXPECT_EQ(selection.length, 0u);
158 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
159 styleMask:NSBorderlessWindowMask
160 backing:NSBackingStoreBuffered
162 window.contentView = viewController.view;
164 engine.semanticsEnabled = YES;
165 auto bridge = viewController.accessibilityBridge.lock();
167 FlutterSemanticsNode2 root;
168 FlutterSemanticsFlags flags = FlutterSemanticsFlags{};
169 root.flags2 = &flags;
174 root.increased_value =
"";
175 root.decreased_value =
"";
177 root.child_count = 1;
178 int32_t children[] = {1};
179 root.children_in_traversal_order = children;
180 root.custom_accessibility_actions_count = 0;
181 root.identifier =
"";
182 bridge->AddFlutterSemanticsNodeUpdate(root);
184 FlutterSemanticsNode2 child1;
185 FlutterSemanticsFlags child_flags = FlutterSemanticsFlags{};
186 child1.flags2 = &child_flags;
188 child1.label =
"child 1";
191 child1.increased_value =
"";
192 child1.decreased_value =
"";
194 child1.child_count = 0;
195 child1.custom_accessibility_actions_count = 0;
196 child1.identifier =
"";
197 bridge->AddFlutterSemanticsNodeUpdate(child1);
199 bridge->CommitUpdates();
201 auto root_platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
204 FlutterSemanticsAction called_action;
207 engine.embedderAPI.DispatchSemanticsAction = MOCK_ENGINE_PROC(
208 DispatchSemanticsAction,
209 ([&called_id, &called_action](
auto engine, uint64_t
id, FlutterSemanticsAction action,
210 const uint8_t* data,
size_t data_length) {
212 called_action = action;
217 ui::AXActionData action_data;
218 action_data.action = ax::mojom::Action::kDoDefault;
219 root_platform_node_delegate->AccessibilityPerformAction(action_data);
221 EXPECT_EQ(called_action, FlutterSemanticsAction::kFlutterSemanticsActionTap);
222 EXPECT_EQ(called_id, 1u);
224 [engine setViewController:nil];
225 [engine shutDownEngine];
233 [viewController loadView];
237 engine.textInputPlugin.string =
@"textfield";
239 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
240 styleMask:NSBorderlessWindowMask
241 backing:NSBackingStoreBuffered
243 window.contentView = viewController.view;
244 engine.semanticsEnabled = YES;
246 auto bridge = viewController.accessibilityBridge.lock();
248 FlutterSemanticsNode2 root;
249 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
250 FlutterSemanticsFlags child_flags = FlutterSemanticsFlags{.is_text_field =
true};
252 root.flags2 = &flags;
254 root.actions =
static_cast<FlutterSemanticsAction
>(0);
258 root.increased_value =
"";
259 root.decreased_value =
"";
261 root.child_count = 1;
262 int32_t children[] = {1};
263 root.children_in_traversal_order = children;
264 root.custom_accessibility_actions_count = 0;
265 root.identifier =
"";
266 root.rect = {0, 0, 100, 100};
267 root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
268 bridge->AddFlutterSemanticsNodeUpdate(root);
270 double rectSize = 50;
271 double transformFactor = 0.5;
273 FlutterSemanticsNode2 child1;
275 child1.flags2 = &child_flags;
277 child1.actions =
static_cast<FlutterSemanticsAction
>(0);
280 child1.value =
"textfield";
281 child1.increased_value =
"";
282 child1.decreased_value =
"";
284 child1.text_selection_base = -1;
285 child1.text_selection_extent = -1;
286 child1.child_count = 0;
287 child1.custom_accessibility_actions_count = 0;
288 child1.identifier =
"";
289 child1.rect = {0, 0, rectSize, rectSize};
290 child1.transform = {transformFactor, 0, 0, 0, transformFactor, 0, 0, 0, 1};
291 bridge->AddFlutterSemanticsNodeUpdate(child1);
293 bridge->CommitUpdates();
295 auto child_platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
297 id native_accessibility = child_platform_node_delegate->GetNativeViewAccessible();
298 EXPECT_EQ([native_accessibility isKindOfClass:[
FlutterTextField class]], YES);
301 NSView* view = viewController.flutterView;
302 CGRect scaledBounds = [view convertRectToBacking:view.bounds];
303 CGSize scaledSize = scaledBounds.size;
304 double pixelRatio = view.bounds.size.width == 0 ? 1 : scaledSize.width / view.bounds.size.width;
306 double expectedFrameSize = rectSize * transformFactor / pixelRatio;
307 EXPECT_EQ(NSEqualRects(native_text_field.frame, NSMakeRect(0, 600 - expectedFrameSize,
308 expectedFrameSize, expectedFrameSize)),
311 [native_text_field startEditing];
312 EXPECT_EQ([native_text_field.stringValue isEqualToString:
@"textfield"], YES);
318 [viewController loadView];
321 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
322 styleMask:NSBorderlessWindowMask
323 backing:NSBackingStoreBuffered
325 window.contentView = viewController.view;
326 engine.semanticsEnabled = YES;
328 auto bridge = viewController.accessibilityBridge.lock();
330 FlutterSemanticsNode2 root;
332 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
333 root.flags2 = &flags;
335 root.actions =
static_cast<FlutterSemanticsAction
>(0);
339 root.increased_value =
"";
340 root.decreased_value =
"";
342 root.child_count = 1;
343 int32_t children[] = {1};
344 root.children_in_traversal_order = children;
345 root.custom_accessibility_actions_count = 0;
346 root.identifier =
"";
347 root.rect = {0, 0, 100, 100};
348 root.transform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
349 bridge->AddFlutterSemanticsNodeUpdate(root);
351 double rectSize = 50;
352 double transformFactor = 0.5;
354 FlutterSemanticsNode2 child1;
355 FlutterSemanticsFlags child_flags = FlutterSemanticsFlags{0};
356 child1.flags2 = &child_flags;
359 child1.actions =
static_cast<FlutterSemanticsAction
>(0);
362 child1.value =
"textfield";
363 child1.increased_value =
"";
364 child1.decreased_value =
"";
366 child1.text_selection_base = -1;
367 child1.text_selection_extent = -1;
368 child1.child_count = 0;
369 child1.custom_accessibility_actions_count = 0;
370 child1.identifier =
"";
371 child1.rect = {0, 0, rectSize, rectSize};
372 child1.transform = {transformFactor, 0, 0, 0, transformFactor, 0, 0, 0, 1};
373 bridge->AddFlutterSemanticsNodeUpdate(child1);
375 bridge->CommitUpdates();
377 auto child_platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
379 id native_accessibility = child_platform_node_delegate->GetNativeViewAccessible();
380 EXPECT_TRUE([[native_accessibility className] isEqualToString:
@"AXPlatformNodeCocoa"]);
384 FlutterSemanticsFlags child_flags_updated_1 = FlutterSemanticsFlags{.is_text_field =
true};
385 child1.flags2 = &child_flags_updated_1;
386 bridge->AddFlutterSemanticsNodeUpdate(child1);
387 bridge->CommitUpdates();
389 native_accessibility = child_platform_node_delegate->GetNativeViewAccessible();
392 FlutterSemanticsFlags child_flags_updated_2 = FlutterSemanticsFlags{.is_text_field =
false};
393 child1.flags2 = &child_flags_updated_2;
394 bridge->AddFlutterSemanticsNodeUpdate(child1);
395 bridge->CommitUpdates();
397 native_accessibility = child_platform_node_delegate->GetNativeViewAccessible();
398 EXPECT_TRUE([[native_accessibility className] isEqualToString:
@"AXPlatformNodeCocoa"]);
TEST(FlutterAppDelegateTest, DoesNotCallDelegatesWithoutHandler)