5#import <OCMock/OCMock.h>
6#import <XCTest/XCTest.h>
41@property(nonatomic, strong) UIView*
view;
47 if (
self = [super init]) {
59- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
60 viewIdentifier:(int64_t)viewId
61 arguments:(
id _Nullable)
args {
69class MockDelegate :
public PlatformView::Delegate {
71 void OnPlatformViewCreated(std::unique_ptr<Surface>
surface)
override {}
72 void OnPlatformViewDestroyed()
override {}
73 void OnPlatformViewScheduleFrame()
override {}
74 void OnPlatformViewAddView(int64_t
view_id,
75 const ViewportMetrics& viewport_metrics,
76 AddViewCallback
callback)
override {}
77 void OnPlatformViewRemoveView(int64_t
view_id, RemoveViewCallback
callback)
override {}
78 void OnPlatformViewSendViewFocusEvent(
const ViewFocusEvent& event)
override {};
79 void OnPlatformViewSetNextFrameCallback(
const fml::closure& closure)
override {}
80 void OnPlatformViewSetViewportMetrics(int64_t
view_id,
const ViewportMetrics& metrics)
override {}
82 void OnPlatformViewDispatchPlatformMessage(std::unique_ptr<PlatformMessage>
message)
override {}
83 void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet)
override {
85 void OnPlatformViewDispatchSemanticsAction(int64_t
view_id,
89 void OnPlatformViewSetSemanticsEnabled(
bool enabled)
override {}
90 void OnPlatformViewSetAccessibilityFeatures(int32_t flags)
override {}
91 void OnPlatformViewRegisterTexture(std::shared_ptr<Texture>
texture)
override {}
92 void OnPlatformViewUnregisterTexture(int64_t
texture_id)
override {}
93 void OnPlatformViewMarkTextureFrameAvailable(int64_t
texture_id)
override {}
95 void LoadDartDeferredLibrary(intptr_t loading_unit_id,
96 std::unique_ptr<const fml::Mapping> snapshot_data,
97 std::unique_ptr<const fml::Mapping> snapshot_instructions)
override {
99 void LoadDartDeferredLibraryError(intptr_t loading_unit_id,
100 const std::string error_message,
101 bool transient)
override {}
102 void UpdateAssetResolverByType(std::unique_ptr<flutter::AssetResolver> updated_asset_resolver,
108class MockIosDelegate :
public AccessibilityBridge::IosDelegate {
110 bool IsFlutterViewControllerPresentingModalViewController(
112 return result_IsFlutterViewControllerPresentingModalViewController_;
115 void PostAccessibilityNotification(UIAccessibilityNotifications notification,
116 id argument)
override {
117 if (on_PostAccessibilityNotification_) {
118 on_PostAccessibilityNotification_(notification, argument);
121 std::function<void(UIAccessibilityNotifications,
id)> on_PostAccessibilityNotification_;
122 bool result_IsFlutterViewControllerPresentingModalViewController_ =
false;
129 auto thread = std::make_unique<fml::Thread>(
name);
130 auto runner = thread->GetTaskRunner();
141 flutter::MockDelegate mock_delegate;
142 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
148 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
150 mock_delegate.settings_.enable_impeller
156 std::make_shared<fml::SyncSwitch>());
158 std::make_unique<flutter::AccessibilityBridge>(nil,
161 XCTAssertTrue(bridge.get());
164- (void)testUpdateSemanticsEmpty {
165 flutter::MockDelegate mock_delegate;
166 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
172 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
174 mock_delegate.settings_.enable_impeller
180 std::make_shared<fml::SyncSwitch>());
181 id mockFlutterView = OCMClassMock([
FlutterView class]);
183 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
184 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg isNil]]);
186 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
191 bridge->UpdateSemantics(nodes, actions);
192 OCMVerifyAll(mockFlutterView);
195- (void)testUpdateSemanticsOneNode {
196 flutter::MockDelegate mock_delegate;
197 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
203 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
205 mock_delegate.settings_.enable_impeller
211 std::make_shared<fml::SyncSwitch>());
212 id mockFlutterView = OCMClassMock([
FlutterView class]);
214 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
215 std::string label =
"some label";
217 __block
auto bridge =
218 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
222 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg checkWithBlock:^BOOL(NSArray* value) {
223 if ([value count] != 1) {
227 SemanticsObject* object = container.semanticsObject;
228 return object.uid == kRootNodeId &&
229 object.bridge.get() == bridge.get() &&
230 object.node.label == label;
237 semantics_node.
label = label;
238 nodes[kRootNodeId] = semantics_node;
240 bridge->UpdateSemantics(nodes, actions);
241 OCMVerifyAll(mockFlutterView);
244- (void)testIsVoiceOverRunning {
245 flutter::MockDelegate mock_delegate;
246 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
252 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
254 mock_delegate.settings_.enable_impeller
260 std::make_shared<fml::SyncSwitch>());
261 id mockFlutterView = OCMClassMock([
FlutterView class]);
263 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
264 OCMStub([mockFlutterViewController isVoiceOverRunning]).andReturn(YES);
266 __block
auto bridge =
267 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
271 XCTAssertTrue(bridge->isVoiceOverRunning());
274- (void)testSemanticsDeallocated {
276 flutter::MockDelegate mock_delegate;
277 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
286 flutterPlatformViewsController.
taskRunner = thread_task_runner;
287 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
289 mock_delegate.settings_.enable_impeller
292 flutterPlatformViewsController,
295 std::make_shared<fml::SyncSwitch>());
296 id mockFlutterView = OCMClassMock([
FlutterView class]);
298 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
299 std::string label =
"some label";
300 flutterPlatformViewsController.
flutterView = mockFlutterView;
303 [flutterPlatformViewsController
305 withId:@"MockFlutterPlatformView"
309 [flutterPlatformViewsController
313 @"viewType" : @"MockFlutterPlatformView"
317 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
318 mockFlutterViewController,
320 flutterPlatformViewsController);
324 semantics_node.
id = 2;
326 semantics_node.
label = label;
327 nodes[kRootNodeId] = semantics_node;
329 bridge->UpdateSemantics(nodes, actions);
331 [flutterPlatformViewsController
reset];
336- (void)testSemanticsDeallocatedWithoutLoadingView {
341 flutter::MockDelegate mock_delegate;
342 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
351 flutterPlatformViewsController.
taskRunner = thread_task_runner;
352 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
354 mock_delegate.settings_.enable_impeller
357 flutterPlatformViewsController,
360 std::make_shared<fml::SyncSwitch>());
363 [flutterPlatformViewsController
365 withId:@"MockFlutterPlatformView"
369 [flutterPlatformViewsController
373 @"viewType" : @"MockFlutterPlatformView"
377 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
378 flutterViewController,
380 flutterPlatformViewsController);
383 [flutterPlatformViewsController
reset];
387 XCTAssertNil(flutterViewController.viewIfLoaded);
388 [flutterViewController deregisterNotifications];
391- (void)testReplacedSemanticsDoesNotCleanupChildren {
392 flutter::MockDelegate mock_delegate;
393 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
402 flutterPlatformViewsController.
taskRunner = thread_task_runner;
403 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
405 mock_delegate.settings_.enable_impeller
408 flutterPlatformViewsController,
411 std::make_shared<fml::SyncSwitch>());
417 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
418 std::string label =
"some label";
419 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
420 mockFlutterViewController,
422 flutterPlatformViewsController);
427 parent.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
428 parent.
label =
"label";
429 parent.
value =
"value";
430 parent.
hint =
"hint";
434 node.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
435 node.
label =
"label";
436 node.
value =
"value";
445 child.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
446 child.
label =
"label";
447 child.
value =
"value";
456 bridge->UpdateSemantics(nodes, actions);
462 new_node.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
465 new_node.
label =
"label";
466 new_node.
value =
"value";
467 new_node.
hint =
"hint";
473 new_nodes[1] = new_node;
474 bridge->UpdateSemantics(new_nodes, actions);
478 id rootContainer = flutterView.accessibilityElements[0];
479 XCTAssertTrue([rootContainer accessibilityElementCount] ==
481 id scrollableContainer = [rootContainer accessibilityElementAtIndex:1];
482 XCTAssertTrue([scrollableContainer accessibilityElementCount] ==
484 id child = [scrollableContainer accessibilityElementAtIndex:1];
486 XCTAssertNotNil([child accessibilityContainer]);
489- (void)testScrollableSemanticsDeallocated {
490 flutter::MockDelegate mock_delegate;
491 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
500 flutterPlatformViewsController.
taskRunner = thread_task_runner;
501 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
503 mock_delegate.settings_.enable_impeller
506 flutterPlatformViewsController,
509 std::make_shared<fml::SyncSwitch>());
515 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
516 std::string label =
"some label";
518 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
519 mockFlutterViewController,
521 flutterPlatformViewsController);
526 parent.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
527 parent.
label =
"label";
528 parent.
value =
"value";
529 parent.
hint =
"hint";
535 node.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
536 node.
label =
"label";
537 node.
value =
"value";
546 bridge->UpdateSemantics(nodes, actions);
547 XCTAssertTrue([flutterView.subviews count] == 1);
549 XCTAssertTrue([flutterView.subviews[0].accessibilityLabel isEqualToString:
@"label"]);
555 new_parent.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
556 new_parent.
label =
"label";
557 new_parent.
value =
"value";
558 new_parent.
hint =
"hint";
559 new_nodes[0] = new_parent;
560 bridge->UpdateSemantics(new_nodes, actions);
562 XCTAssertTrue([flutterView.subviews count] == 0);
565- (void)testBridgeReplacesSemanticsNode {
566 flutter::MockDelegate mock_delegate;
567 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
576 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
578 mock_delegate.settings_.enable_impeller
581 flutterPlatformViewsController,
584 std::make_shared<fml::SyncSwitch>());
590 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
591 std::string label =
"some label";
593 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
594 mockFlutterViewController,
596 flutterPlatformViewsController);
601 parent.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
602 parent.
label =
"label";
603 parent.
value =
"value";
604 parent.
hint =
"hint";
610 node.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
611 node.
label =
"label";
612 node.
value =
"value";
621 bridge->UpdateSemantics(nodes, actions);
622 XCTAssertTrue([flutterView.subviews count] == 1);
624 XCTAssertTrue([flutterView.subviews[0].accessibilityLabel isEqualToString:
@"label"]);
630 new_node.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
631 new_node.
label =
"label";
632 new_node.
value =
"value";
633 new_node.
hint =
"hint";
636 new_nodes[1] = new_node;
637 bridge->UpdateSemantics(new_nodes, actions);
639 XCTAssertTrue([flutterView.subviews count] == 0);
642- (void)testAnnouncesRouteChanges {
643 flutter::MockDelegate mock_delegate;
644 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
650 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
652 mock_delegate.settings_.enable_impeller
658 std::make_shared<fml::SyncSwitch>());
659 id mockFlutterView = OCMClassMock([
FlutterView class]);
661 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
663 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
664 [[NSMutableArray alloc] init];
665 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
666 ios_delegate->on_PostAccessibilityNotification_ =
667 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
668 [accessibility_notifications addObject:@{
669 @"notification" : @(notification),
670 @"argument" : argument ? argument : [NSNull null],
673 __block
auto bridge =
674 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
677 std::move(ios_delegate));
684 node1.
label =
"node1";
688 nodes[node1.
id] = node1;
691 node2.
label =
"node2";
692 nodes[node2.
id] = node2;
696 node3.
label =
"node3";
697 nodes[node3.
id] = node3;
703 nodes[root_node.
id] = root_node;
704 bridge->UpdateSemantics(nodes, actions);
706 XCTAssertEqual([accessibility_notifications count], 1ul);
707 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node3");
708 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
709 UIAccessibilityScreenChangedNotification);
712- (void)testRadioButtonIsNotSwitchButton {
713 flutter::MockDelegate mock_delegate;
714 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
720 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
722 mock_delegate.settings_.enable_impeller
728 std::make_shared<fml::SyncSwitch>());
734 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
735 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
736 __block
auto bridge =
737 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
740 std::move(ios_delegate));
750 nodes[root_node.
id] = root_node;
751 bridge->UpdateSemantics(nodes, actions);
756 XCTAssertTrue((rootNode.accessibilityTraits & UIAccessibilityTraitButton) > 0);
757 XCTAssertNil(rootNode.accessibilityValue);
760- (void)testSemanticObjectWithNoAccessibilityFlagNotMarkedAsResponsiveToUserInteraction {
761 flutter::MockDelegate mock_delegate;
762 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
768 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
770 mock_delegate.settings_.enable_impeller
776 std::make_shared<fml::SyncSwitch>());
782 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
783 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
784 __block
auto bridge =
785 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
788 std::move(ios_delegate));
796 nodes[root_node.
id] = root_node;
797 bridge->UpdateSemantics(nodes, actions);
802 XCTAssertFalse(rootNode.accessibilityRespondsToUserInteraction);
805- (void)testSemanticObjectWithAccessibilityFlagsMarkedAsResponsiveToUserInteraction {
806 flutter::MockDelegate mock_delegate;
807 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
813 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
815 mock_delegate.settings_.enable_impeller
821 std::make_shared<fml::SyncSwitch>());
827 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
828 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
829 __block
auto bridge =
830 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
833 std::move(ios_delegate));
842 nodes[root_node.
id] = root_node;
843 bridge->UpdateSemantics(nodes, actions);
848 XCTAssertTrue(rootNode.accessibilityRespondsToUserInteraction);
853- (void)testLabeledParentAndChildNotInteractive {
854 flutter::MockDelegate mock_delegate;
855 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
864 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
866 mock_delegate.settings_.enable_impeller
869 flutterPlatformViewsController,
872 std::make_shared<fml::SyncSwitch>());
878 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
881 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
882 mockFlutterViewController,
884 flutterPlatformViewsController);
890 parent.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
891 parent.
label =
"parent_label";
895 node.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
896 node.
label =
"child_label";
903 bridge->UpdateSemantics(nodes, actions);
909 XCTAssertTrue([parentNode.accessibilityLabel isEqualToString:
@"parent_label"]);
910 XCTAssertTrue([childNode.accessibilityLabel isEqualToString:
@"child_label"]);
911 XCTAssertFalse(parentNode.accessibilityRespondsToUserInteraction);
912 XCTAssertFalse(childNode.accessibilityRespondsToUserInteraction);
916- (void)testLayoutChangeWithNonAccessibilityElement {
917 flutter::MockDelegate mock_delegate;
918 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
924 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
926 mock_delegate.settings_.enable_impeller
932 std::make_shared<fml::SyncSwitch>());
933 id mockFlutterView = OCMClassMock([
FlutterView class]);
935 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
937 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
938 [[NSMutableArray alloc] init];
939 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
940 ios_delegate->on_PostAccessibilityNotification_ =
941 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
942 [accessibility_notifications addObject:@{
943 @"notification" : @(notification),
944 @"argument" : argument ? argument : [NSNull null],
947 __block
auto bridge =
948 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
951 std::move(ios_delegate));
958 node1.
label =
"node1";
961 nodes[node1.
id] = node1;
964 node2.
label =
"node2";
965 nodes[node2.
id] = node2;
968 node3.
label =
"node3";
969 nodes[node3.
id] = node3;
972 root_node.
label =
"root";
975 nodes[root_node.
id] = root_node;
976 bridge->UpdateSemantics(nodes, actions);
979 bridge->AccessibilityObjectDidBecomeFocused(1);
991 new_nodes[new_node1.
id] = new_node1;
992 bridge->UpdateSemantics(new_nodes, new_actions);
994 XCTAssertEqual([accessibility_notifications count], 1ul);
995 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
997 XCTAssertEqual([focusObject uid], 2);
998 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
999 UIAccessibilityLayoutChangedNotification);
1002- (void)testLayoutChangeDoesCallNativeAccessibility {
1003 flutter::MockDelegate mock_delegate;
1004 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1009 thread_task_runner);
1010 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1012 mock_delegate.settings_.enable_impeller
1018 std::make_shared<fml::SyncSwitch>());
1019 id mockFlutterView = OCMClassMock([
FlutterView class]);
1021 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1023 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1024 [[NSMutableArray alloc] init];
1025 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1026 ios_delegate->on_PostAccessibilityNotification_ =
1027 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1028 [accessibility_notifications addObject:@{
1029 @"notification" : @(notification),
1030 @"argument" : argument ? argument : [NSNull null],
1033 __block
auto bridge =
1034 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1037 std::move(ios_delegate));
1044 node1.
label =
"node1";
1045 nodes[node1.
id] = node1;
1048 root_node.
label =
"root";
1052 nodes[root_node.
id] = root_node;
1053 bridge->UpdateSemantics(nodes, actions);
1056 bridge->AccessibilityObjectDidBecomeFocused(0);
1064 new_root_node.
label =
"root";
1066 new_nodes[new_root_node.
id] = new_root_node;
1067 bridge->UpdateSemantics(new_nodes, new_actions);
1069 XCTAssertEqual([accessibility_notifications count], 1ul);
1070 id focusObject = accessibility_notifications[0][@"argument"];
1074 XCTAssertEqualObjects(focusObject, [NSNull null]);
1075 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1076 UIAccessibilityLayoutChangedNotification);
1079- (void)testLayoutChangeDoesCallNativeAccessibilityWhenFocusChanged {
1080 flutter::MockDelegate mock_delegate;
1081 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1086 thread_task_runner);
1087 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1089 mock_delegate.settings_.enable_impeller
1095 std::make_shared<fml::SyncSwitch>());
1096 id mockFlutterView = OCMClassMock([
FlutterView class]);
1098 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1100 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1101 [[NSMutableArray alloc] init];
1102 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1103 ios_delegate->on_PostAccessibilityNotification_ =
1104 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1105 [accessibility_notifications addObject:@{
1106 @"notification" : @(notification),
1107 @"argument" : argument ? argument : [NSNull null],
1110 __block
auto bridge =
1111 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1114 std::move(ios_delegate));
1121 node1.
label =
"node1";
1122 nodes[node1.
id] = node1;
1125 root_node.
label =
"root";
1129 nodes[root_node.
id] = root_node;
1130 bridge->UpdateSemantics(nodes, actions);
1133 bridge->AccessibilityObjectDidBecomeFocused(1);
1141 new_root_node.
label =
"root";
1143 new_nodes[new_root_node.
id] = new_root_node;
1144 bridge->UpdateSemantics(new_nodes, new_actions);
1146 XCTAssertEqual([accessibility_notifications count], 1ul);
1147 SemanticsObject* focusObject2 = accessibility_notifications[0][@"argument"];
1151 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1152 UIAccessibilityLayoutChangedNotification);
1155- (void)testScrollableSemanticsContainerReturnsCorrectChildren {
1156 flutter::MockDelegate mock_delegate;
1157 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1162 thread_task_runner);
1163 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1165 mock_delegate.settings_.enable_impeller
1171 std::make_shared<fml::SyncSwitch>());
1172 id mockFlutterView = OCMClassMock([
FlutterView class]);
1174 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1176 OCMExpect([mockFlutterView
1177 setAccessibilityElements:[OCMArg checkWithBlock:^BOOL(NSArray* value) {
1178 if ([value count] != 1) {
1181 SemanticsObjectContainer* container = value[0];
1182 SemanticsObject* object = container.semanticsObject;
1183 FlutterScrollableSemanticsObject* scrollable =
1184 (FlutterScrollableSemanticsObject*)object.children[0];
1185 id nativeScrollable = scrollable.nativeAccessibility;
1186 SemanticsObjectContainer* scrollableContainer = [nativeScrollable accessibilityContainer];
1187 return [scrollableContainer indexOfAccessibilityElement:nativeScrollable] == 1;
1189 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1190 __block
auto bridge =
1191 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1194 std::move(ios_delegate));
1201 node1.
label =
"node1";
1203 nodes[node1.
id] = node1;
1206 root_node.
label =
"root";
1209 nodes[root_node.
id] = root_node;
1210 bridge->UpdateSemantics(nodes, actions);
1211 OCMVerifyAll(mockFlutterView);
1214- (void)testAnnouncesRouteChangesAndLayoutChangeInOneUpdate {
1215 flutter::MockDelegate mock_delegate;
1216 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1221 thread_task_runner);
1222 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1224 mock_delegate.settings_.enable_impeller
1230 std::make_shared<fml::SyncSwitch>());
1231 id mockFlutterView = OCMClassMock([
FlutterView class]);
1233 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1235 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1236 [[NSMutableArray alloc] init];
1237 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1238 ios_delegate->on_PostAccessibilityNotification_ =
1239 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1240 [accessibility_notifications addObject:@{
1241 @"notification" : @(notification),
1242 @"argument" : argument ? argument : [NSNull null],
1245 __block
auto bridge =
1246 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1249 std::move(ios_delegate));
1256 node1.
label =
"node1";
1259 nodes[node1.
id] = node1;
1262 node3.
label =
"node3";
1263 nodes[node3.
id] = node3;
1266 root_node.
label =
"root";
1269 nodes[root_node.
id] = root_node;
1270 bridge->UpdateSemantics(nodes, actions);
1272 XCTAssertEqual([accessibility_notifications count], 1ul);
1273 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node1");
1274 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1275 UIAccessibilityScreenChangedNotification);
1278 bridge->AccessibilityObjectDidBecomeFocused(0);
1284 new_node1.
label =
"new_node1";
1289 new_nodes[new_node1.
id] = new_node1;
1292 new_node2.
label =
"new_node2";
1295 new_nodes[new_node2.
id] = new_node2;
1298 new_root_node.
label =
"root";
1301 new_nodes[new_root_node.
id] = new_root_node;
1302 bridge->UpdateSemantics(new_nodes, actions);
1303 XCTAssertEqual([accessibility_notifications count], 3ul);
1304 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1305 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1306 UIAccessibilityScreenChangedNotification);
1307 SemanticsObject* focusObject = accessibility_notifications[2][@"argument"];
1308 XCTAssertEqual([focusObject uid], 0);
1309 XCTAssertEqual([accessibility_notifications[2][
@"notification"] unsignedIntValue],
1310 UIAccessibilityLayoutChangedNotification);
1313- (void)testAnnouncesRouteChangesWhenAddAdditionalRoute {
1314 flutter::MockDelegate mock_delegate;
1315 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1320 thread_task_runner);
1321 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1323 mock_delegate.settings_.enable_impeller
1329 std::make_shared<fml::SyncSwitch>());
1330 id mockFlutterView = OCMClassMock([
FlutterView class]);
1332 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1334 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1335 [[NSMutableArray alloc] init];
1336 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1337 ios_delegate->on_PostAccessibilityNotification_ =
1338 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1339 [accessibility_notifications addObject:@{
1340 @"notification" : @(notification),
1341 @"argument" : argument ? argument : [NSNull null],
1344 __block
auto bridge =
1345 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1348 std::move(ios_delegate));
1355 node1.
label =
"node1";
1358 nodes[node1.
id] = node1;
1364 nodes[root_node.
id] = root_node;
1365 bridge->UpdateSemantics(nodes, actions);
1367 XCTAssertEqual([accessibility_notifications count], 1ul);
1368 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node1");
1369 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1370 UIAccessibilityScreenChangedNotification);
1376 new_node1.
label =
"new_node1";
1381 new_nodes[new_node1.
id] = new_node1;
1384 new_node2.
label =
"new_node2";
1387 new_nodes[new_node2.
id] = new_node2;
1393 new_nodes[new_root_node.
id] = new_root_node;
1394 bridge->UpdateSemantics(new_nodes, actions);
1395 XCTAssertEqual([accessibility_notifications count], 2ul);
1396 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1397 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1398 UIAccessibilityScreenChangedNotification);
1401- (void)testAnnouncesRouteChangesRemoveRouteInMiddle {
1402 flutter::MockDelegate mock_delegate;
1403 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1408 thread_task_runner);
1409 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1411 mock_delegate.settings_.enable_impeller
1417 std::make_shared<fml::SyncSwitch>());
1418 id mockFlutterView = OCMClassMock([
FlutterView class]);
1420 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1422 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1423 [[NSMutableArray alloc] init];
1424 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1425 ios_delegate->on_PostAccessibilityNotification_ =
1426 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1427 [accessibility_notifications addObject:@{
1428 @"notification" : @(notification),
1429 @"argument" : argument ? argument : [NSNull null],
1432 __block
auto bridge =
1433 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1436 std::move(ios_delegate));
1443 node1.
label =
"node1";
1448 nodes[node1.
id] = node1;
1451 node2.
label =
"node2";
1454 nodes[node2.
id] = node2;
1460 nodes[root_node.
id] = root_node;
1461 bridge->UpdateSemantics(nodes, actions);
1463 XCTAssertEqual([accessibility_notifications count], 1ul);
1464 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node2");
1465 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1466 UIAccessibilityScreenChangedNotification);
1472 new_node1.
label =
"new_node1";
1475 new_nodes[new_node1.
id] = new_node1;
1478 new_node2.
label =
"new_node2";
1481 new_nodes[new_node2.
id] = new_node2;
1487 new_nodes[new_root_node.
id] = new_root_node;
1488 bridge->UpdateSemantics(new_nodes, actions);
1489 XCTAssertEqual([accessibility_notifications count], 2ul);
1490 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1491 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1492 UIAccessibilityScreenChangedNotification);
1495- (void)testHandleEvent {
1496 flutter::MockDelegate mock_delegate;
1497 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1502 thread_task_runner);
1503 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1505 mock_delegate.settings_.enable_impeller
1511 std::make_shared<fml::SyncSwitch>());
1512 id mockFlutterView = OCMClassMock([
FlutterView class]);
1514 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1516 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1517 [[NSMutableArray alloc] init];
1518 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1519 ios_delegate->on_PostAccessibilityNotification_ =
1520 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1521 [accessibility_notifications addObject:@{
1522 @"notification" : @(notification),
1523 @"argument" : argument ? argument : [NSNull null],
1526 __block
auto bridge =
1527 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1530 std::move(ios_delegate));
1532 NSDictionary<NSString*, id>* annotatedEvent = @{
@"type" :
@"focus",
@"nodeId" : @123};
1534 bridge->HandleEvent(annotatedEvent);
1536 XCTAssertEqual([accessibility_notifications count], 1ul);
1537 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1538 UIAccessibilityLayoutChangedNotification);
1541- (void)testAccessibilityObjectDidBecomeFocused {
1542 flutter::MockDelegate mock_delegate;
1543 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
1544 auto thread_task_runner = thread->GetTaskRunner();
1549 thread_task_runner);
1550 id messenger = OCMProtocolMock(
@protocol(FlutterBinaryMessenger));
1554 OCMStub([flutterViewController
engine]).andReturn(
engine);
1555 OCMStub([
engine binaryMessenger]).andReturn(messenger);
1557 OCMStub([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
1558 binaryMessageHandler:[OCMArg any]])
1559 .andReturn(connection);
1561 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1563 mock_delegate.settings_.enable_impeller
1569 std::make_shared<fml::SyncSwitch>());
1571 thread_task_runner->PostTask([&] {
1572 platform_view->SetOwnerViewController(flutterViewController);
1574 std::make_unique<flutter::AccessibilityBridge>(nil,
1577 XCTAssertTrue(bridge.get());
1578 OCMVerify([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
1579 binaryMessageHandler:[OCMArg isNotNil]]);
1581 bridge->AccessibilityObjectDidBecomeFocused(123);
1583 NSDictionary<NSString*, id>* annotatedEvent = @{
@"type" :
@"didGainFocus",
@"nodeId" : @123};
1586 OCMVerify([messenger sendOnChannel:
@"flutter/accessibility" message:encodedMessage]);
1591 [engine stopMocking];
1594- (void)testAnnouncesRouteChangesWhenNoNamesRoute {
1595 flutter::MockDelegate mock_delegate;
1596 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1601 thread_task_runner);
1602 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1604 mock_delegate.settings_.enable_impeller
1610 std::make_shared<fml::SyncSwitch>());
1611 id mockFlutterView = OCMClassMock([
FlutterView class]);
1613 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1615 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1616 [[NSMutableArray alloc] init];
1617 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1618 ios_delegate->on_PostAccessibilityNotification_ =
1619 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1620 [accessibility_notifications addObject:@{
1621 @"notification" : @(notification),
1622 @"argument" : argument ? argument : [NSNull null],
1625 __block
auto bridge =
1626 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1629 std::move(ios_delegate));
1636 node1.
label =
"node1";
1641 nodes[node1.
id] = node1;
1644 node2.
label =
"node2";
1645 nodes[node2.
id] = node2;
1648 node3.
label =
"node3";
1649 nodes[node3.
id] = node3;
1654 nodes[root_node.
id] = root_node;
1655 bridge->UpdateSemantics(nodes, actions);
1658 XCTAssertEqual([accessibility_notifications count], 1ul);
1659 id focusObject = accessibility_notifications[0][@"argument"];
1660 XCTAssertTrue([focusObject isKindOfClass:[NSString class]]);
1661 XCTAssertEqualObjects(focusObject,
@"node1");
1662 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1663 UIAccessibilityScreenChangedNotification);
1666- (void)testAnnouncesLayoutChangeWithNilIfLastFocusIsRemoved {
1667 flutter::MockDelegate mock_delegate;
1668 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1673 thread_task_runner);
1674 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1676 mock_delegate.settings_.enable_impeller
1682 std::make_shared<fml::SyncSwitch>());
1684 id mockFlutterView = OCMClassMock([
FlutterView class]);
1685 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1687 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1688 [[NSMutableArray alloc] init];
1689 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1690 ios_delegate->on_PostAccessibilityNotification_ =
1691 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1692 [accessibility_notifications addObject:@{
1693 @"notification" : @(notification),
1694 @"argument" : argument ? argument : [NSNull null],
1697 __block
auto bridge =
1698 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1701 std::move(ios_delegate));
1708 route_node.
label =
"route";
1709 first_update[route_node.
id] = route_node;
1712 root_node.
label =
"root";
1715 first_update[root_node.
id] = root_node;
1716 bridge->UpdateSemantics(first_update, actions);
1718 XCTAssertEqual([accessibility_notifications count], 0ul);
1720 bridge->AccessibilityObjectDidBecomeFocused(1);
1726 new_root_node.
label =
"root";
1727 second_update[root_node.
id] = new_root_node;
1728 bridge->UpdateSemantics(second_update, actions);
1729 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
1731 XCTAssertEqual([focusObject uid], 0);
1732 XCTAssertEqualObjects([focusObject accessibilityLabel],
@"root");
1733 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1734 UIAccessibilityLayoutChangedNotification);
1737- (void)testAnnouncesLayoutChangeWithTheSameItemFocused {
1738 flutter::MockDelegate mock_delegate;
1739 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1744 thread_task_runner);
1745 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1747 mock_delegate.settings_.enable_impeller
1753 std::make_shared<fml::SyncSwitch>());
1755 id mockFlutterView = OCMClassMock([
FlutterView class]);
1756 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1758 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1759 [[NSMutableArray alloc] init];
1760 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1761 ios_delegate->on_PostAccessibilityNotification_ =
1762 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1763 [accessibility_notifications addObject:@{
1764 @"notification" : @(notification),
1765 @"argument" : argument ? argument : [NSNull null],
1768 __block
auto bridge =
1769 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1772 std::move(ios_delegate));
1779 node_one.
label =
"route1";
1780 first_update[node_one.
id] = node_one;
1783 node_two.
label =
"route2";
1784 first_update[node_two.
id] = node_two;
1787 root_node.
label =
"root";
1790 first_update[root_node.
id] = root_node;
1791 bridge->UpdateSemantics(first_update, actions);
1793 XCTAssertEqual([accessibility_notifications count], 0ul);
1795 bridge->AccessibilityObjectDidBecomeFocused(1);
1801 new_root_node.
label =
"root";
1804 second_update[root_node.
id] = new_root_node;
1805 bridge->UpdateSemantics(second_update, actions);
1806 id focusObject = accessibility_notifications[0][@"argument"];
1809 XCTAssertEqualObjects(focusObject, [NSNull null]);
1810 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1811 UIAccessibilityLayoutChangedNotification);
1814- (void)testAnnouncesLayoutChangeWhenFocusMovedOutside {
1815 flutter::MockDelegate mock_delegate;
1816 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1821 thread_task_runner);
1822 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1824 mock_delegate.settings_.enable_impeller
1830 std::make_shared<fml::SyncSwitch>());
1832 id mockFlutterView = OCMClassMock([
FlutterView class]);
1833 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1835 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1836 [[NSMutableArray alloc] init];
1837 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1838 ios_delegate->on_PostAccessibilityNotification_ =
1839 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1840 [accessibility_notifications addObject:@{
1841 @"notification" : @(notification),
1842 @"argument" : argument ? argument : [NSNull null],
1845 __block
auto bridge =
1846 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1849 std::move(ios_delegate));
1856 node_one.
label =
"route1";
1857 first_update[node_one.
id] = node_one;
1860 node_two.
label =
"route2";
1861 first_update[node_two.
id] = node_two;
1864 root_node.
label =
"root";
1867 first_update[root_node.
id] = root_node;
1868 bridge->UpdateSemantics(first_update, actions);
1870 XCTAssertEqual([accessibility_notifications count], 0ul);
1872 bridge->AccessibilityObjectDidBecomeFocused(1);
1874 bridge->AccessibilityObjectDidLoseFocus(1);
1880 new_root_node.
label =
"root";
1883 second_update[root_node.
id] = new_root_node;
1884 bridge->UpdateSemantics(second_update, actions);
1885 NSNull* focusObject = accessibility_notifications[0][@"argument"];
1888 XCTAssertEqual(focusObject, [NSNull null]);
1889 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1890 UIAccessibilityLayoutChangedNotification);
1893- (void)testAnnouncesScrollChangeWithLastFocused {
1894 flutter::MockDelegate mock_delegate;
1895 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1900 thread_task_runner);
1901 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1903 mock_delegate.settings_.enable_impeller
1909 std::make_shared<fml::SyncSwitch>());
1911 id mockFlutterView = OCMClassMock([
FlutterView class]);
1912 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1914 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1915 [[NSMutableArray alloc] init];
1916 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1917 ios_delegate->on_PostAccessibilityNotification_ =
1918 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1919 [accessibility_notifications addObject:@{
1920 @"notification" : @(notification),
1921 @"argument" : argument ? argument : [NSNull null],
1924 __block
auto bridge =
1925 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1928 std::move(ios_delegate));
1935 node_one.
label =
"route1";
1937 first_update[node_one.
id] = node_one;
1940 root_node.
label =
"root";
1943 first_update[root_node.
id] = root_node;
1944 bridge->UpdateSemantics(first_update, actions);
1947 [accessibility_notifications removeAllObjects];
1950 bridge->AccessibilityObjectDidBecomeFocused(1);
1955 new_node_one.
id = 1;
1956 new_node_one.
label =
"route1";
1958 second_update[new_node_one.
id] = new_node_one;
1959 bridge->UpdateSemantics(second_update, actions);
1960 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
1963 XCTAssertEqual([focusObject uid], 1);
1964 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1965 UIAccessibilityPageScrolledNotification);
1968- (void)testAnnouncesScrollChangeDoesCallNativeAccessibility {
1969 flutter::MockDelegate mock_delegate;
1970 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1975 thread_task_runner);
1976 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1978 mock_delegate.settings_.enable_impeller
1984 std::make_shared<fml::SyncSwitch>());
1986 id mockFlutterView = OCMClassMock([
FlutterView class]);
1987 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1989 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1990 [[NSMutableArray alloc] init];
1991 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1992 ios_delegate->on_PostAccessibilityNotification_ =
1993 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1994 [accessibility_notifications addObject:@{
1995 @"notification" : @(notification),
1996 @"argument" : argument ? argument : [NSNull null],
1999 __block
auto bridge =
2000 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2003 std::move(ios_delegate));
2010 node_one.
label =
"route1";
2013 first_update[node_one.
id] = node_one;
2016 root_node.
label =
"root";
2019 first_update[root_node.
id] = root_node;
2020 bridge->UpdateSemantics(first_update, actions);
2023 [accessibility_notifications removeAllObjects];
2026 bridge->AccessibilityObjectDidBecomeFocused(1);
2031 new_node_one.
id = 1;
2032 new_node_one.
label =
"route1";
2035 second_update[new_node_one.
id] = new_node_one;
2036 bridge->UpdateSemantics(second_update, actions);
2037 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
2041 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
2042 UIAccessibilityPageScrolledNotification);
2045- (void)testAnnouncesIgnoresRouteChangesWhenModal {
2046 flutter::MockDelegate mock_delegate;
2047 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
2052 thread_task_runner);
2053 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2055 mock_delegate.settings_.enable_impeller
2061 std::make_shared<fml::SyncSwitch>());
2062 id mockFlutterView = OCMClassMock([
FlutterView class]);
2064 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
2065 std::string label =
"some label";
2067 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2068 [[NSMutableArray alloc] init];
2069 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2070 ios_delegate->on_PostAccessibilityNotification_ =
2071 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2072 [accessibility_notifications addObject:@{
2073 @"notification" : @(notification),
2074 @"argument" : argument ? argument : [NSNull null],
2077 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2078 __block
auto bridge =
2079 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2082 std::move(ios_delegate));
2091 route_node.
label =
"route";
2092 nodes[route_node.
id] = route_node;
2095 root_node.
label = label;
2098 nodes[root_node.
id] = root_node;
2099 bridge->UpdateSemantics(nodes, actions);
2101 XCTAssertEqual([accessibility_notifications count], 0ul);
2104- (void)testAnnouncesIgnoresLayoutChangeWhenModal {
2105 flutter::MockDelegate mock_delegate;
2106 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
2111 thread_task_runner);
2112 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2114 mock_delegate.settings_.enable_impeller
2120 std::make_shared<fml::SyncSwitch>());
2121 id mockFlutterView = OCMClassMock([
FlutterView class]);
2123 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
2125 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2126 [[NSMutableArray alloc] init];
2127 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2128 ios_delegate->on_PostAccessibilityNotification_ =
2129 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2130 [accessibility_notifications addObject:@{
2131 @"notification" : @(notification),
2132 @"argument" : argument ? argument : [NSNull null],
2135 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2136 __block
auto bridge =
2137 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2140 std::move(ios_delegate));
2147 child_node.
label =
"child_node";
2148 nodes[child_node.
id] = child_node;
2151 root_node.
label =
"root";
2154 nodes[root_node.
id] = root_node;
2155 bridge->UpdateSemantics(nodes, actions);
2161 new_root_node.
label =
"root";
2162 new_nodes[new_root_node.
id] = new_root_node;
2163 bridge->UpdateSemantics(new_nodes, actions);
2165 XCTAssertEqual([accessibility_notifications count], 0ul);
2168- (void)testAnnouncesIgnoresScrollChangeWhenModal {
2169 flutter::MockDelegate mock_delegate;
2170 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
2175 thread_task_runner);
2176 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2178 mock_delegate.settings_.enable_impeller
2184 std::make_shared<fml::SyncSwitch>());
2185 id mockFlutterView = OCMClassMock([
FlutterView class]);
2187 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
2189 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2190 [[NSMutableArray alloc] init];
2191 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2192 ios_delegate->on_PostAccessibilityNotification_ =
2193 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2194 [accessibility_notifications addObject:@{
2195 @"notification" : @(notification),
2196 @"argument" : argument ? argument : [NSNull null],
2199 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2200 __block
auto bridge =
2201 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2204 std::move(ios_delegate));
2211 root_node.
label =
"root";
2213 nodes[root_node.
id] = root_node;
2214 bridge->UpdateSemantics(nodes, actions);
2220 new_root_node.
label =
"root";
2222 new_nodes[new_root_node.
id] = new_root_node;
2223 bridge->UpdateSemantics(new_nodes, actions);
2225 XCTAssertEqual([accessibility_notifications count], 0ul);
2228- (void)testAccessibilityMessageAfterDeletion {
2229 flutter::MockDelegate mock_delegate;
2230 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2231 auto thread_task_runner = thread->GetTaskRunner();
2236 thread_task_runner);
2237 id messenger = OCMProtocolMock(
@protocol(FlutterBinaryMessenger));
2241 OCMStub([flutterViewController
engine]).andReturn(
engine);
2242 OCMStub([
engine binaryMessenger]).andReturn(messenger);
2244 OCMStub([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
2245 binaryMessageHandler:[OCMArg any]])
2246 .andReturn(connection);
2248 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2250 mock_delegate.settings_.enable_impeller
2256 std::make_shared<fml::SyncSwitch>());
2258 thread_task_runner->PostTask([&] {
2259 platform_view->SetOwnerViewController(flutterViewController);
2261 std::make_unique<flutter::AccessibilityBridge>(nil,
2264 XCTAssertTrue(bridge.get());
2265 OCMVerify([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
2266 binaryMessageHandler:[OCMArg isNotNil]]);
2271 OCMVerify([messenger cleanUpConnection:connection]);
2272 [engine stopMocking];
2275- (void)testFlutterSemanticsScrollViewManagedObjectLifecycleCorrectly {
2276 flutter::MockDelegate mock_delegate;
2277 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
2282 thread_task_runner);
2283 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2285 mock_delegate.settings_.enable_impeller
2291 std::make_shared<fml::SyncSwitch>());
2292 id mockFlutterView = OCMClassMock([
FlutterView class]);
2294 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
2296 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2297 __block
auto bridge =
2298 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2301 std::move(ios_delegate));
2310 XCTAssertTrue(flutterSemanticsScrollView);
2313 XCTAssertFalse([flutterSemanticsScrollView isAccessibilityElement]);
2316- (void)testPlatformViewDestructorDoesNotCallSemanticsAPIs {
2317 class TestDelegate :
public flutter::MockDelegate {
2319 void OnPlatformViewSetSemanticsEnabled(
bool enabled)
override { set_semantics_enabled_calls++; }
2320 int set_semantics_enabled_calls = 0;
2323 TestDelegate test_delegate;
2324 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2325 auto thread_task_runner = thread->GetTaskRunner();
2330 thread_task_runner);
2333 thread_task_runner->PostTask([&] {
2334 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2336 test_delegate.settings_.enable_impeller
2342 std::make_shared<fml::SyncSwitch>());
2347 flutterPlatformViewsController.
taskRunner = thread_task_runner;
2349 OCMStub([mockFlutterViewController platformViewsController])
2350 .andReturn(flutterPlatformViewsController);
2351 platform_view->SetOwnerViewController(mockFlutterViewController);
2354 XCTAssertNotEqual(test_delegate.set_semantics_enabled_calls, 0);
2357 test_delegate.set_semantics_enabled_calls = 0;
2359 XCTAssertEqual(test_delegate.set_semantics_enabled_calls, 0);
2366- (void)testResetsAccessibilityElementsOnHotRestart {
2367 flutter::MockDelegate mock_delegate;
2368 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2369 auto thread_task_runner = thread->GetTaskRunner();
2374 thread_task_runner);
2375 id mockFlutterView = OCMClassMock([
FlutterView class]);
2377 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
2380 thread_task_runner->PostTask([&] {
2381 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2383 mock_delegate.settings_.enable_impeller
2389 std::make_shared<fml::SyncSwitch>());
2391 platform_view->SetOwnerViewController(mockFlutterViewController);
2395 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg isNil]]);
2397 OCMVerifyAll(mockFlutterView);
2404- (void)testWeakViewController {
2405 flutter::MockDelegate mock_delegate;
2406 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
2411 thread_task_runner);
2412 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2414 mock_delegate.settings_.enable_impeller
2420 std::make_shared<fml::SyncSwitch>());
2422 std::unique_ptr<flutter::AccessibilityBridge> bridge;
2424 id mockFlutterView = OCMClassMock([
FlutterView class]);
2426 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
2427 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
2429 bridge = std::make_unique<flutter::AccessibilityBridge>(
2430 mockFlutterViewController,
2433 XCTAssertTrue(bridge.get());
2434 XCTAssertNotNil(bridge->view());
2436 XCTAssertNil(bridge->view());
int64_t FlutterBinaryMessengerConnection
void(^ FlutterResult)(id _Nullable result)
constexpr int32_t kRootNodeId
static __weak MockPlatformView * gMockPlatformView
AssetResolverType
Identifies the type of AssetResolver an instance is.
A Mapping like NonOwnedMapping, but uses Free as its release proc.
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
G_BEGIN_DECLS GBytes * message
G_BEGIN_DECLS FlutterViewId view_id
FlutterDesktopBinaryReply callback
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
constexpr int kHorizontalScrollSemanticsActions
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
std::unordered_map< int32_t, CustomAccessibilityAction > CustomAccessibilityActionUpdates
std::function< void()> closure
instancetype sharedInstance()
SemanticsCheckState isChecked
SemanticsTristate isEnabled
bool isInMutuallyExclusiveGroup
bool hasImplicitScrolling
std::vector< int32_t > childrenInHitTestOrder
std::vector< int32_t > childrenInTraversalOrder