10 #include "flutter/testing/autoreleasepool_test.h"
11 #include "flutter/testing/testing.h"
21 AccessibilityBridgeMacSpy(__weak
FlutterEngine* flutter_engine,
28 void DispatchMacOSNotification(gfx::NativeViewAccessible native_node,
29 NSAccessibilityNotificationName mac_notification)
override {
38 - (std::shared_ptr<flutter::AccessibilityBridgeMac>)createAccessibilityBridgeWithEngine:
43 - (std::shared_ptr<flutter::AccessibilityBridgeMac>)createAccessibilityBridgeWithEngine:
45 return std::make_shared<flutter::testing::AccessibilityBridgeMacSpy>(
engine,
self);
55 NSString* fixtures = @(testing::GetFixturesPath());
57 initWithAssetsPath:fixtures
58 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
65 class AccessibilityBridgeMacWindowTest :
public AutoreleasePoolTest {
67 AccessibilityBridgeMacWindowTest() {
69 gWindow_ = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
70 styleMask:NSBorderlessWindowMask
71 backing:NSBackingStoreBuffered
76 NSWindow* GetWindow()
const {
return gWindow_; }
79 static NSWindow* gWindow_;
80 FML_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridgeMacWindowTest);
83 NSWindow* AccessibilityBridgeMacWindowTest::gWindow_ = nil;
86 using AccessibilityBridgeMacTest = AutoreleasePoolTest;
90 TEST_F(AccessibilityBridgeMacWindowTest, SendsAccessibilityCreateNotificationFlutterViewWindow) {
93 NSWindow* expectedTarget = GetWindow();
94 expectedTarget.contentView = viewController.view;
98 engine.semanticsEnabled = YES;
99 auto bridge = std::static_pointer_cast<AccessibilityBridgeMacSpy>(
100 viewController.accessibilityBridge.lock());
101 FlutterSemanticsNode2 root;
102 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
104 root.flags2 = &flags;
106 root.actions =
static_cast<FlutterSemanticsAction
>(0);
107 root.text_selection_base = -1;
108 root.text_selection_extent = -1;
112 root.increased_value =
"";
113 root.decreased_value =
"";
115 root.child_count = 0;
116 root.custom_accessibility_actions_count = 0;
117 root.identifier =
"";
118 bridge->AddFlutterSemanticsNodeUpdate(root);
120 bridge->CommitUpdates();
121 auto platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
125 ui::AXNode ax_node(&tree,
nullptr, 0, 0);
126 ui::AXNodeData node_data;
128 ax_node.SetData(node_data);
129 std::vector<ui::AXEventIntent> intent;
130 ui::AXEventGenerator::EventParams event_params(ui::AXEventGenerator::Event::CHILDREN_CHANGED,
131 ax::mojom::EventFrom::kNone, intent);
132 ui::AXEventGenerator::TargetedEvent targeted_event(&ax_node, event_params);
134 bridge->OnAccessibilityEvent(targeted_event);
136 ASSERT_EQ(bridge->actual_notifications.size(), 1u);
137 auto target = bridge->actual_notifications.find([NSAccessibilityCreatedNotification UTF8String]);
138 ASSERT_NE(target, bridge->actual_notifications.end());
139 EXPECT_EQ(target->second, expectedTarget);
150 TEST_F(AccessibilityBridgeMacWindowTest, NonZeroRootNodeId) {
153 NSWindow* expectedTarget = GetWindow();
154 expectedTarget.contentView = viewController.view;
158 engine.semanticsEnabled = YES;
159 auto bridge = std::static_pointer_cast<AccessibilityBridgeMacSpy>(
160 viewController.accessibilityBridge.lock());
162 FlutterSemanticsNode2 node1;
163 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
164 std::vector<int32_t> node1_children{2};
166 node1.flags2 = &flags;
168 node1.actions =
static_cast<FlutterSemanticsAction
>(0);
169 node1.text_selection_base = -1;
170 node1.text_selection_extent = -1;
171 node1.label =
"node1";
174 node1.increased_value =
"";
175 node1.decreased_value =
"";
177 node1.child_count = node1_children.size();
178 node1.children_in_traversal_order = node1_children.data();
179 node1.children_in_hit_test_order = node1_children.data();
180 node1.custom_accessibility_actions_count = 0;
181 node1.identifier =
"";
183 FlutterSemanticsNode2 node2;
185 node2.flags2 = &flags;
187 node2.actions =
static_cast<FlutterSemanticsAction
>(0);
188 node2.text_selection_base = -1;
189 node2.text_selection_extent = -1;
190 node2.label =
"node2";
193 node2.increased_value =
"";
194 node2.decreased_value =
"";
196 node2.child_count = 0;
197 node2.custom_accessibility_actions_count = 0;
198 node2.identifier =
"";
200 bridge->AddFlutterSemanticsNodeUpdate(node1);
201 bridge->AddFlutterSemanticsNodeUpdate(node2);
202 bridge->CommitUpdates();
205 auto root_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(1).lock();
206 ASSERT_TRUE(root_delegate);
207 ASSERT_EQ(root_delegate->GetChildCount(), 1);
210 auto child_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(2).lock();
211 ASSERT_TRUE(child_delegate);
212 ASSERT_EQ(child_delegate->GetChildCount(), 0);
215 auto invalid_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
216 ASSERT_FALSE(invalid_delegate);
221 TEST_F(AccessibilityBridgeMacTest, DoesNotSendAccessibilityCreateNotificationWhenHeadless) {
227 engine.semanticsEnabled = YES;
228 auto bridge = std::static_pointer_cast<AccessibilityBridgeMacSpy>(
229 viewController.accessibilityBridge.lock());
230 FlutterSemanticsNode2 root;
231 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
233 root.flags2 = &flags;
235 root.actions =
static_cast<FlutterSemanticsAction
>(0);
236 root.text_selection_base = -1;
237 root.text_selection_extent = -1;
241 root.increased_value =
"";
242 root.decreased_value =
"";
244 root.child_count = 0;
245 root.custom_accessibility_actions_count = 0;
246 root.identifier =
"";
247 bridge->AddFlutterSemanticsNodeUpdate(root);
249 bridge->CommitUpdates();
250 auto platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
254 ui::AXNode ax_node(&tree,
nullptr, 0, 0);
255 ui::AXNodeData node_data;
257 ax_node.SetData(node_data);
258 std::vector<ui::AXEventIntent> intent;
259 ui::AXEventGenerator::EventParams event_params(ui::AXEventGenerator::Event::CHILDREN_CHANGED,
260 ax::mojom::EventFrom::kNone, intent);
261 ui::AXEventGenerator::TargetedEvent targeted_event(&ax_node, event_params);
263 bridge->OnAccessibilityEvent(targeted_event);
266 EXPECT_EQ(bridge->actual_notifications.size(), 0u);
270 TEST_F(AccessibilityBridgeMacTest, DoesNotSendAccessibilityCreateNotificationWhenNoWindow) {
276 engine.semanticsEnabled = YES;
277 auto bridge = std::static_pointer_cast<AccessibilityBridgeMacSpy>(
278 viewController.accessibilityBridge.lock());
279 FlutterSemanticsNode2 root;
280 FlutterSemanticsFlags flags = FlutterSemanticsFlags{0};
282 root.flags2 = &flags;
284 root.actions =
static_cast<FlutterSemanticsAction
>(0);
285 root.text_selection_base = -1;
286 root.text_selection_extent = -1;
290 root.increased_value =
"";
291 root.decreased_value =
"";
293 root.child_count = 0;
294 root.custom_accessibility_actions_count = 0;
295 root.identifier =
"";
296 bridge->AddFlutterSemanticsNodeUpdate(root);
298 bridge->CommitUpdates();
299 auto platform_node_delegate = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock();
303 ui::AXNode ax_node(&tree,
nullptr, 0, 0);
304 ui::AXNodeData node_data;
306 ax_node.SetData(node_data);
307 std::vector<ui::AXEventIntent> intent;
308 ui::AXEventGenerator::EventParams event_params(ui::AXEventGenerator::Event::CHILDREN_CHANGED,
309 ax::mojom::EventFrom::kNone, intent);
310 ui::AXEventGenerator::TargetedEvent targeted_event(&ax_node, event_params);
312 bridge->OnAccessibilityEvent(targeted_event);
315 EXPECT_EQ(bridge->actual_notifications.size(), 0u);
std::unordered_map< std::string, gfx::NativeViewAccessible > actual_notifications
void OnAccessibilityEvent(ui::AXEventGenerator::TargetedEvent targeted_event) override
Handle accessibility events generated due to accessibility tree changes. These events are needed to b...
TEST_F(AccessibilityBridgeMacWindowTest, SendsAccessibilityCreateNotificationFlutterViewWindow)