5#import <OCMock/OCMock.h>
6#import <XCTest/XCTest.h>
27@interface SemanticsObject (Test)
28- (
id)_accessibilityHitTest:(CGPoint)point withEvent:(UIEvent*)event;
50@property(nonatomic, strong) UIView*
view;
56 if (
self = [super init]) {
68- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
69 viewIdentifier:(int64_t)viewId
70 arguments:(
id _Nullable)
args {
78class MockDelegate :
public PlatformView::Delegate {
80 void OnPlatformViewCreated(std::unique_ptr<Surface>
surface)
override {}
81 void OnPlatformViewDestroyed()
override {}
82 void OnPlatformViewScheduleFrame()
override {}
83 void OnPlatformViewAddView(int64_t
view_id,
84 const ViewportMetrics& viewport_metrics,
85 AddViewCallback
callback)
override {}
86 void OnPlatformViewRemoveView(int64_t
view_id, RemoveViewCallback
callback)
override {}
87 void OnPlatformViewSendViewFocusEvent(
const ViewFocusEvent& event)
override {};
88 void OnPlatformViewSetNextFrameCallback(
const fml::closure& closure)
override {}
89 void OnPlatformViewSetViewportMetrics(int64_t
view_id,
const ViewportMetrics& metrics)
override {}
91 void OnPlatformViewDispatchPlatformMessage(std::unique_ptr<PlatformMessage>
message)
override {}
92 void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet)
override {
95 return {.has_platform_view =
false};
97 void OnPlatformViewDispatchSemanticsAction(int64_t
view_id,
101 void OnPlatformViewSetSemanticsEnabled(
bool enabled)
override {}
102 void OnPlatformViewSetAccessibilityFeatures(int32_t flags)
override {}
103 void OnPlatformViewRegisterTexture(std::shared_ptr<Texture>
texture)
override {}
104 void OnPlatformViewUnregisterTexture(int64_t
texture_id)
override {}
105 void OnPlatformViewMarkTextureFrameAvailable(int64_t
texture_id)
override {}
107 void LoadDartDeferredLibrary(intptr_t loading_unit_id,
108 std::unique_ptr<const fml::Mapping> snapshot_data,
109 std::unique_ptr<const fml::Mapping> snapshot_instructions)
override {
111 void LoadDartDeferredLibraryError(intptr_t loading_unit_id,
112 const std::string error_message,
113 bool transient)
override {}
114 void UpdateAssetResolverByType(std::unique_ptr<flutter::AssetResolver> updated_asset_resolver,
116 std::shared_ptr<fml::BasicTaskRunner> OnPlatformViewGetShutdownSafeIOTaskRunner()
const override {
123class MockIosDelegate :
public AccessibilityBridge::IosDelegate {
125 bool IsFlutterViewControllerPresentingModalViewController(
127 return result_IsFlutterViewControllerPresentingModalViewController_;
130 void PostAccessibilityNotification(UIAccessibilityNotifications notification,
131 id argument)
override {
132 if (on_PostAccessibilityNotification_) {
133 on_PostAccessibilityNotification_(notification, argument);
136 std::function<void(UIAccessibilityNotifications,
id)> on_PostAccessibilityNotification_;
137 bool result_IsFlutterViewControllerPresentingModalViewController_ =
false;
144 auto thread = std::make_unique<fml::Thread>(
name);
145 auto runner = thread->GetTaskRunner();
156 flutter::MockDelegate mock_delegate;
157 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
163 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
165 mock_delegate.settings_.enable_impeller
170 std::make_shared<fml::SyncSwitch>());
172 std::make_unique<flutter::AccessibilityBridge>(nil,
175 XCTAssertTrue(bridge.get());
178- (void)testUpdateSemanticsEmpty {
179 flutter::MockDelegate mock_delegate;
180 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
186 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
188 mock_delegate.settings_.enable_impeller
193 std::make_shared<fml::SyncSwitch>());
194 id mockFlutterView = OCMClassMock([
FlutterView class]);
196 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
197 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg isNil]]);
199 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
204 bridge->UpdateSemantics(nodes, actions);
205 OCMVerifyAll(mockFlutterView);
208- (void)testUpdateSemanticsOneNode {
209 flutter::MockDelegate mock_delegate;
210 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
216 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
218 mock_delegate.settings_.enable_impeller
223 std::make_shared<fml::SyncSwitch>());
224 id mockFlutterView = OCMClassMock([
FlutterView class]);
226 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
227 std::string label =
"some label";
229 __block
auto bridge =
230 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
234 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg checkWithBlock:^BOOL(NSArray* value) {
235 if ([value count] != 1) {
239 SemanticsObject* object = container.semanticsObject;
240 return object.uid == kRootNodeId &&
241 object.bridge == bridge.get() && object.node.label == label;
248 semantics_node.
label = label;
249 nodes[kRootNodeId] = semantics_node;
251 bridge->UpdateSemantics(nodes, actions);
252 OCMVerifyAll(mockFlutterView);
255- (void)testIsVoiceOverRunning {
256 flutter::MockDelegate mock_delegate;
257 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
263 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
265 mock_delegate.settings_.enable_impeller
270 std::make_shared<fml::SyncSwitch>());
271 id mockFlutterView = OCMClassMock([
FlutterView class]);
273 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
274 OCMStub([mockFlutterViewController isVoiceOverRunning]).andReturn(YES);
276 __block
auto bridge =
277 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
281 XCTAssertTrue(bridge->isVoiceOverRunning());
284- (void)testSemanticsDeallocated {
286 flutter::MockDelegate mock_delegate;
287 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
298 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
300 mock_delegate.settings_.enable_impeller
303 flutterPlatformViewsController,
305 std::make_shared<fml::SyncSwitch>());
306 id mockFlutterView = OCMClassMock([
FlutterView class]);
308 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
309 std::string label =
"some label";
310 flutterPlatformViewsController.
flutterView = mockFlutterView;
313 [flutterPlatformViewsController
315 withId:@"MockFlutterPlatformView"
319 [flutterPlatformViewsController
323 @"viewType" : @"MockFlutterPlatformView"
327 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
328 mockFlutterViewController,
330 flutterPlatformViewsController);
334 semantics_node.
id = 2;
336 semantics_node.
label = label;
337 nodes[kRootNodeId] = semantics_node;
339 bridge->UpdateSemantics(nodes, actions);
341 [flutterPlatformViewsController
reset];
346- (void)testSemanticsDeallocatedWithoutLoadingView {
351 flutter::MockDelegate mock_delegate;
352 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
363 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
365 mock_delegate.settings_.enable_impeller
368 flutterPlatformViewsController,
370 std::make_shared<fml::SyncSwitch>());
373 [flutterPlatformViewsController
375 withId:@"MockFlutterPlatformView"
379 [flutterPlatformViewsController
383 @"viewType" : @"MockFlutterPlatformView"
387 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
388 flutterViewController,
390 flutterPlatformViewsController);
393 [flutterPlatformViewsController
reset];
397 XCTAssertNil(flutterViewController.viewIfLoaded);
398 [flutterViewController deregisterNotifications];
401- (void)testReplacedSemanticsDoesNotCleanupChildren {
402 flutter::MockDelegate mock_delegate;
403 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
414 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
416 mock_delegate.settings_.enable_impeller
419 flutterPlatformViewsController,
421 std::make_shared<fml::SyncSwitch>());
427 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
428 std::string label =
"some label";
429 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
430 mockFlutterViewController,
432 flutterPlatformViewsController);
437 parent.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
438 parent.
label =
"label";
439 parent.
value =
"value";
440 parent.
hint =
"hint";
444 node.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
445 node.
label =
"label";
446 node.
value =
"value";
455 child.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
456 child.
label =
"label";
457 child.
value =
"value";
466 bridge->UpdateSemantics(nodes, actions);
472 new_node.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
475 new_node.
label =
"label";
476 new_node.
value =
"value";
477 new_node.
hint =
"hint";
483 new_nodes[1] = new_node;
484 bridge->UpdateSemantics(new_nodes, actions);
488 id rootContainer = flutterView.accessibilityElements[0];
489 XCTAssertTrue([rootContainer accessibilityElementCount] ==
491 id scrollableContainer = [rootContainer accessibilityElementAtIndex:1];
492 XCTAssertTrue([scrollableContainer accessibilityElementCount] ==
494 id child = [scrollableContainer accessibilityElementAtIndex:1];
496 XCTAssertNotNil([child accessibilityContainer]);
499- (void)testScrollableSemanticsDeallocated {
500 flutter::MockDelegate mock_delegate;
501 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
512 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
514 mock_delegate.settings_.enable_impeller
517 flutterPlatformViewsController,
519 std::make_shared<fml::SyncSwitch>());
525 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
526 std::string label =
"some label";
528 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
529 mockFlutterViewController,
531 flutterPlatformViewsController);
536 parent.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
537 parent.
label =
"label";
538 parent.
value =
"value";
539 parent.
hint =
"hint";
545 node.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
546 node.
label =
"label";
547 node.
value =
"value";
556 bridge->UpdateSemantics(nodes, actions);
557 XCTAssertTrue([flutterView.subviews count] == 1);
559 XCTAssertTrue([flutterView.subviews[0].accessibilityLabel isEqualToString:
@"label"]);
565 new_parent.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
566 new_parent.
label =
"label";
567 new_parent.
value =
"value";
568 new_parent.
hint =
"hint";
569 new_nodes[0] = new_parent;
570 bridge->UpdateSemantics(new_nodes, actions);
572 XCTAssertTrue([flutterView.subviews count] == 0);
575- (void)testBridgeReplacesSemanticsNode {
576 flutter::MockDelegate mock_delegate;
577 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
586 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
588 mock_delegate.settings_.enable_impeller
591 flutterPlatformViewsController,
593 std::make_shared<fml::SyncSwitch>());
599 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
600 std::string label =
"some label";
602 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
603 mockFlutterViewController,
605 flutterPlatformViewsController);
610 parent.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
611 parent.
label =
"label";
612 parent.
value =
"value";
613 parent.
hint =
"hint";
619 node.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
620 node.
label =
"label";
621 node.
value =
"value";
630 bridge->UpdateSemantics(nodes, actions);
631 XCTAssertTrue([flutterView.subviews count] == 1);
633 XCTAssertTrue([flutterView.subviews[0].accessibilityLabel isEqualToString:
@"label"]);
639 new_node.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
640 new_node.
label =
"label";
641 new_node.
value =
"value";
642 new_node.
hint =
"hint";
645 new_nodes[1] = new_node;
646 bridge->UpdateSemantics(new_nodes, actions);
648 XCTAssertTrue([flutterView.subviews count] == 0);
651- (void)testAnnouncesRouteChanges {
652 flutter::MockDelegate mock_delegate;
653 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
659 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
661 mock_delegate.settings_.enable_impeller
666 std::make_shared<fml::SyncSwitch>());
667 id mockFlutterView = OCMClassMock([
FlutterView class]);
669 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
671 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
672 [[NSMutableArray alloc] init];
673 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
674 ios_delegate->on_PostAccessibilityNotification_ =
675 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
676 [accessibility_notifications addObject:@{
677 @"notification" : @(notification),
678 @"argument" : argument ? argument : [NSNull null],
681 __block
auto bridge =
682 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
685 std::move(ios_delegate));
692 node1.
label =
"node1";
696 nodes[node1.
id] = node1;
699 node2.
label =
"node2";
700 nodes[node2.
id] = node2;
704 node3.
label =
"node3";
705 nodes[node3.
id] = node3;
711 nodes[root_node.
id] = root_node;
712 bridge->UpdateSemantics(nodes, actions);
714 XCTAssertEqual([accessibility_notifications count], 1ul);
715 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node3");
716 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
717 UIAccessibilityScreenChangedNotification);
720- (void)testRadioButtonIsNotSwitchButton {
721 flutter::MockDelegate mock_delegate;
722 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
728 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
730 mock_delegate.settings_.enable_impeller
735 std::make_shared<fml::SyncSwitch>());
741 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
742 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
743 __block
auto bridge =
744 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
747 std::move(ios_delegate));
757 nodes[root_node.
id] = root_node;
758 bridge->UpdateSemantics(nodes, actions);
763 XCTAssertTrue((rootNode.accessibilityTraits & UIAccessibilityTraitButton) > 0);
764 XCTAssertNil(rootNode.accessibilityValue);
767- (void)testSemanticObjectWithNoAccessibilityFlagNotMarkedAsResponsiveToUserInteraction {
768 flutter::MockDelegate mock_delegate;
769 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
775 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
777 mock_delegate.settings_.enable_impeller
782 std::make_shared<fml::SyncSwitch>());
788 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
789 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
790 __block
auto bridge =
791 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
794 std::move(ios_delegate));
802 nodes[root_node.
id] = root_node;
803 bridge->UpdateSemantics(nodes, actions);
808 XCTAssertFalse(rootNode.accessibilityRespondsToUserInteraction);
811- (void)testSemanticObjectWithAccessibilityFlagsMarkedAsResponsiveToUserInteraction {
812 flutter::MockDelegate mock_delegate;
813 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
819 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
821 mock_delegate.settings_.enable_impeller
826 std::make_shared<fml::SyncSwitch>());
832 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
833 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
834 __block
auto bridge =
835 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
838 std::move(ios_delegate));
847 nodes[root_node.
id] = root_node;
848 bridge->UpdateSemantics(nodes, actions);
853 XCTAssertTrue(rootNode.accessibilityRespondsToUserInteraction);
858- (void)testLabeledParentAndChildNotInteractive {
859 flutter::MockDelegate mock_delegate;
860 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
869 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
871 mock_delegate.settings_.enable_impeller
874 flutterPlatformViewsController,
876 std::make_shared<fml::SyncSwitch>());
882 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
885 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
886 mockFlutterViewController,
888 flutterPlatformViewsController);
894 parent.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
895 parent.
label =
"parent_label";
899 node.
rect = SkRect::MakeXYWH(0, 0, 100, 200);
900 node.
label =
"child_label";
907 bridge->UpdateSemantics(nodes, actions);
913 XCTAssertTrue([parentNode.accessibilityLabel isEqualToString:
@"parent_label"]);
914 XCTAssertTrue([childNode.accessibilityLabel isEqualToString:
@"child_label"]);
915 XCTAssertFalse(parentNode.accessibilityRespondsToUserInteraction);
916 XCTAssertFalse(childNode.accessibilityRespondsToUserInteraction);
920- (void)testLayoutChangeWithNonAccessibilityElement {
921 flutter::MockDelegate mock_delegate;
922 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
928 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
930 mock_delegate.settings_.enable_impeller
935 std::make_shared<fml::SyncSwitch>());
936 id mockFlutterView = OCMClassMock([
FlutterView class]);
938 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
940 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
941 [[NSMutableArray alloc] init];
942 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
943 ios_delegate->on_PostAccessibilityNotification_ =
944 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
945 [accessibility_notifications addObject:@{
946 @"notification" : @(notification),
947 @"argument" : argument ? argument : [NSNull null],
950 __block
auto bridge =
951 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
954 std::move(ios_delegate));
961 node1.
label =
"node1";
964 nodes[node1.
id] = node1;
967 node2.
label =
"node2";
968 nodes[node2.
id] = node2;
971 node3.
label =
"node3";
972 nodes[node3.
id] = node3;
975 root_node.
label =
"root";
978 nodes[root_node.
id] = root_node;
979 bridge->UpdateSemantics(nodes, actions);
982 bridge->AccessibilityObjectDidBecomeFocused(1);
994 new_nodes[new_node1.
id] = new_node1;
995 bridge->UpdateSemantics(new_nodes, new_actions);
997 XCTAssertEqual([accessibility_notifications count], 1ul);
998 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
1000 XCTAssertEqual([focusObject uid], 2);
1001 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1002 UIAccessibilityLayoutChangedNotification);
1005- (void)testLayoutChangeDoesCallNativeAccessibility {
1006 flutter::MockDelegate mock_delegate;
1007 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1012 thread_task_runner);
1013 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1015 mock_delegate.settings_.enable_impeller
1020 std::make_shared<fml::SyncSwitch>());
1021 id mockFlutterView = OCMClassMock([
FlutterView class]);
1023 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1025 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1026 [[NSMutableArray alloc] init];
1027 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1028 ios_delegate->on_PostAccessibilityNotification_ =
1029 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1030 [accessibility_notifications addObject:@{
1031 @"notification" : @(notification),
1032 @"argument" : argument ? argument : [NSNull null],
1035 __block
auto bridge =
1036 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1039 std::move(ios_delegate));
1046 node1.
label =
"node1";
1047 nodes[node1.
id] = node1;
1050 root_node.
label =
"root";
1054 nodes[root_node.
id] = root_node;
1055 bridge->UpdateSemantics(nodes, actions);
1058 bridge->AccessibilityObjectDidBecomeFocused(0);
1066 new_root_node.
label =
"root";
1068 new_nodes[new_root_node.
id] = new_root_node;
1069 bridge->UpdateSemantics(new_nodes, new_actions);
1071 XCTAssertEqual([accessibility_notifications count], 1ul);
1072 id focusObject = accessibility_notifications[0][@"argument"];
1076 XCTAssertEqualObjects(focusObject, [NSNull null]);
1077 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1078 UIAccessibilityLayoutChangedNotification);
1081- (void)testLayoutChangeDoesCallNativeAccessibilityWhenFocusChanged {
1082 flutter::MockDelegate mock_delegate;
1083 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1088 thread_task_runner);
1089 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1091 mock_delegate.settings_.enable_impeller
1096 std::make_shared<fml::SyncSwitch>());
1097 id mockFlutterView = OCMClassMock([
FlutterView class]);
1099 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1101 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1102 [[NSMutableArray alloc] init];
1103 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1104 ios_delegate->on_PostAccessibilityNotification_ =
1105 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1106 [accessibility_notifications addObject:@{
1107 @"notification" : @(notification),
1108 @"argument" : argument ? argument : [NSNull null],
1111 __block
auto bridge =
1112 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1115 std::move(ios_delegate));
1122 node1.
label =
"node1";
1123 nodes[node1.
id] = node1;
1126 root_node.
label =
"root";
1130 nodes[root_node.
id] = root_node;
1131 bridge->UpdateSemantics(nodes, actions);
1134 bridge->AccessibilityObjectDidBecomeFocused(1);
1142 new_root_node.
label =
"root";
1144 new_nodes[new_root_node.
id] = new_root_node;
1145 bridge->UpdateSemantics(new_nodes, new_actions);
1147 XCTAssertEqual([accessibility_notifications count], 1ul);
1148 SemanticsObject* focusObject2 = accessibility_notifications[0][@"argument"];
1152 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1153 UIAccessibilityLayoutChangedNotification);
1156- (void)testScrollableSemanticsContainerReturnsCorrectChildren {
1157 flutter::MockDelegate mock_delegate;
1158 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1163 thread_task_runner);
1164 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1166 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
1229 std::make_shared<fml::SyncSwitch>());
1230 id mockFlutterView = OCMClassMock([
FlutterView class]);
1232 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1234 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1235 [[NSMutableArray alloc] init];
1236 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1237 ios_delegate->on_PostAccessibilityNotification_ =
1238 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1239 [accessibility_notifications addObject:@{
1240 @"notification" : @(notification),
1241 @"argument" : argument ? argument : [NSNull null],
1244 __block
auto bridge =
1245 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1248 std::move(ios_delegate));
1255 node1.
label =
"node1";
1258 nodes[node1.
id] = node1;
1261 node3.
label =
"node3";
1262 nodes[node3.
id] = node3;
1265 root_node.
label =
"root";
1268 nodes[root_node.
id] = root_node;
1269 bridge->UpdateSemantics(nodes, actions);
1271 XCTAssertEqual([accessibility_notifications count], 1ul);
1272 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node1");
1273 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1274 UIAccessibilityScreenChangedNotification);
1277 bridge->AccessibilityObjectDidBecomeFocused(0);
1283 new_node1.
label =
"new_node1";
1288 new_nodes[new_node1.
id] = new_node1;
1291 new_node2.
label =
"new_node2";
1294 new_nodes[new_node2.
id] = new_node2;
1297 new_root_node.
label =
"root";
1300 new_nodes[new_root_node.
id] = new_root_node;
1301 bridge->UpdateSemantics(new_nodes, actions);
1302 XCTAssertEqual([accessibility_notifications count], 3ul);
1303 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1304 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1305 UIAccessibilityScreenChangedNotification);
1306 SemanticsObject* focusObject = accessibility_notifications[2][@"argument"];
1307 XCTAssertEqual([focusObject uid], 0);
1308 XCTAssertEqual([accessibility_notifications[2][
@"notification"] unsignedIntValue],
1309 UIAccessibilityLayoutChangedNotification);
1312- (void)testAnnouncesRouteChangesWhenAddAdditionalRoute {
1313 flutter::MockDelegate mock_delegate;
1314 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1319 thread_task_runner);
1320 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1322 mock_delegate.settings_.enable_impeller
1327 std::make_shared<fml::SyncSwitch>());
1328 id mockFlutterView = OCMClassMock([
FlutterView class]);
1330 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1332 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1333 [[NSMutableArray alloc] init];
1334 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1335 ios_delegate->on_PostAccessibilityNotification_ =
1336 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1337 [accessibility_notifications addObject:@{
1338 @"notification" : @(notification),
1339 @"argument" : argument ? argument : [NSNull null],
1342 __block
auto bridge =
1343 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1346 std::move(ios_delegate));
1353 node1.
label =
"node1";
1356 nodes[node1.
id] = node1;
1362 nodes[root_node.
id] = root_node;
1363 bridge->UpdateSemantics(nodes, actions);
1365 XCTAssertEqual([accessibility_notifications count], 1ul);
1366 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node1");
1367 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1368 UIAccessibilityScreenChangedNotification);
1374 new_node1.
label =
"new_node1";
1379 new_nodes[new_node1.
id] = new_node1;
1382 new_node2.
label =
"new_node2";
1385 new_nodes[new_node2.
id] = new_node2;
1391 new_nodes[new_root_node.
id] = new_root_node;
1392 bridge->UpdateSemantics(new_nodes, actions);
1393 XCTAssertEqual([accessibility_notifications count], 2ul);
1394 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1395 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1396 UIAccessibilityScreenChangedNotification);
1399- (void)testAnnouncesRouteChangesRemoveRouteInMiddle {
1400 flutter::MockDelegate mock_delegate;
1401 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1406 thread_task_runner);
1407 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1409 mock_delegate.settings_.enable_impeller
1414 std::make_shared<fml::SyncSwitch>());
1415 id mockFlutterView = OCMClassMock([
FlutterView class]);
1417 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1419 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1420 [[NSMutableArray alloc] init];
1421 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1422 ios_delegate->on_PostAccessibilityNotification_ =
1423 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1424 [accessibility_notifications addObject:@{
1425 @"notification" : @(notification),
1426 @"argument" : argument ? argument : [NSNull null],
1429 __block
auto bridge =
1430 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1433 std::move(ios_delegate));
1440 node1.
label =
"node1";
1445 nodes[node1.
id] = node1;
1448 node2.
label =
"node2";
1451 nodes[node2.
id] = node2;
1457 nodes[root_node.
id] = root_node;
1458 bridge->UpdateSemantics(nodes, actions);
1460 XCTAssertEqual([accessibility_notifications count], 1ul);
1461 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node2");
1462 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1463 UIAccessibilityScreenChangedNotification);
1469 new_node1.
label =
"new_node1";
1472 new_nodes[new_node1.
id] = new_node1;
1475 new_node2.
label =
"new_node2";
1478 new_nodes[new_node2.
id] = new_node2;
1484 new_nodes[new_root_node.
id] = new_root_node;
1485 bridge->UpdateSemantics(new_nodes, actions);
1486 XCTAssertEqual([accessibility_notifications count], 2ul);
1487 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1488 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1489 UIAccessibilityScreenChangedNotification);
1492- (void)testHandleEvent {
1493 flutter::MockDelegate mock_delegate;
1494 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1499 thread_task_runner);
1500 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1502 mock_delegate.settings_.enable_impeller
1507 std::make_shared<fml::SyncSwitch>());
1508 id mockFlutterView = OCMClassMock([
FlutterView class]);
1510 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1512 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1513 [[NSMutableArray alloc] init];
1514 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1515 ios_delegate->on_PostAccessibilityNotification_ =
1516 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1517 [accessibility_notifications addObject:@{
1518 @"notification" : @(notification),
1519 @"argument" : argument ? argument : [NSNull null],
1522 __block
auto bridge =
1523 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1526 std::move(ios_delegate));
1528 NSDictionary<NSString*, id>* annotatedEvent = @{
@"type" :
@"focus",
@"nodeId" : @123};
1530 bridge->HandleEvent(annotatedEvent);
1532 XCTAssertEqual([accessibility_notifications count], 1ul);
1533 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1534 UIAccessibilityLayoutChangedNotification);
1537- (void)testAccessibilityObjectDidBecomeFocused {
1538 flutter::MockDelegate mock_delegate;
1539 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
1540 auto thread_task_runner = thread->GetTaskRunner();
1545 thread_task_runner);
1546 id messenger = OCMProtocolMock(
@protocol(FlutterBinaryMessenger));
1550 OCMStub([flutterViewController
engine]).andReturn(
engine);
1551 OCMStub([
engine binaryMessenger]).andReturn(messenger);
1553 OCMStub([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
1554 binaryMessageHandler:[OCMArg any]])
1555 .andReturn(connection);
1557 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1559 mock_delegate.settings_.enable_impeller
1564 std::make_shared<fml::SyncSwitch>());
1566 thread_task_runner->PostTask([&] {
1567 platform_view->SetOwnerViewController(flutterViewController);
1569 std::make_unique<flutter::AccessibilityBridge>(nil,
1572 XCTAssertTrue(bridge.get());
1573 OCMVerify([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
1574 binaryMessageHandler:[OCMArg isNotNil]]);
1576 bridge->AccessibilityObjectDidBecomeFocused(123);
1578 NSDictionary<NSString*, id>* annotatedEvent = @{
@"type" :
@"didGainFocus",
@"nodeId" : @123};
1581 OCMVerify([messenger sendOnChannel:
@"flutter/accessibility" message:encodedMessage]);
1586 [engine stopMocking];
1589- (void)testAnnouncesRouteChangesWhenNoNamesRoute {
1590 flutter::MockDelegate mock_delegate;
1591 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1596 thread_task_runner);
1597 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1599 mock_delegate.settings_.enable_impeller
1604 std::make_shared<fml::SyncSwitch>());
1605 id mockFlutterView = OCMClassMock([
FlutterView class]);
1607 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1609 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1610 [[NSMutableArray alloc] init];
1611 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1612 ios_delegate->on_PostAccessibilityNotification_ =
1613 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1614 [accessibility_notifications addObject:@{
1615 @"notification" : @(notification),
1616 @"argument" : argument ? argument : [NSNull null],
1619 __block
auto bridge =
1620 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1623 std::move(ios_delegate));
1630 node1.
label =
"node1";
1635 nodes[node1.
id] = node1;
1638 node2.
label =
"node2";
1639 nodes[node2.
id] = node2;
1642 node3.
label =
"node3";
1643 nodes[node3.
id] = node3;
1648 nodes[root_node.
id] = root_node;
1649 bridge->UpdateSemantics(nodes, actions);
1652 XCTAssertEqual([accessibility_notifications count], 1ul);
1653 id focusObject = accessibility_notifications[0][@"argument"];
1654 XCTAssertTrue([focusObject isKindOfClass:[NSString class]]);
1655 XCTAssertEqualObjects(focusObject,
@"node1");
1656 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1657 UIAccessibilityScreenChangedNotification);
1660- (void)testAnnouncesLayoutChangeWithNilIfLastFocusIsRemoved {
1661 flutter::MockDelegate mock_delegate;
1662 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1667 thread_task_runner);
1668 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1670 mock_delegate.settings_.enable_impeller
1675 std::make_shared<fml::SyncSwitch>());
1677 id mockFlutterView = OCMClassMock([
FlutterView class]);
1678 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1680 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1681 [[NSMutableArray alloc] init];
1682 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1683 ios_delegate->on_PostAccessibilityNotification_ =
1684 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1685 [accessibility_notifications addObject:@{
1686 @"notification" : @(notification),
1687 @"argument" : argument ? argument : [NSNull null],
1690 __block
auto bridge =
1691 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1694 std::move(ios_delegate));
1701 route_node.
label =
"route";
1702 first_update[route_node.
id] = route_node;
1705 root_node.
label =
"root";
1708 first_update[root_node.
id] = root_node;
1709 bridge->UpdateSemantics(first_update, actions);
1711 XCTAssertEqual([accessibility_notifications count], 0ul);
1713 bridge->AccessibilityObjectDidBecomeFocused(1);
1719 new_root_node.
label =
"root";
1720 second_update[root_node.
id] = new_root_node;
1721 bridge->UpdateSemantics(second_update, actions);
1722 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
1724 XCTAssertEqual([focusObject uid], 0);
1725 XCTAssertEqualObjects([focusObject accessibilityLabel],
@"root");
1726 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1727 UIAccessibilityLayoutChangedNotification);
1730- (void)testAnnouncesLayoutChangeWithTheSameItemFocused {
1731 flutter::MockDelegate mock_delegate;
1732 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1737 thread_task_runner);
1738 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1740 mock_delegate.settings_.enable_impeller
1745 std::make_shared<fml::SyncSwitch>());
1747 id mockFlutterView = OCMClassMock([
FlutterView class]);
1748 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1750 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1751 [[NSMutableArray alloc] init];
1752 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1753 ios_delegate->on_PostAccessibilityNotification_ =
1754 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1755 [accessibility_notifications addObject:@{
1756 @"notification" : @(notification),
1757 @"argument" : argument ? argument : [NSNull null],
1760 __block
auto bridge =
1761 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1764 std::move(ios_delegate));
1771 node_one.
label =
"route1";
1772 first_update[node_one.
id] = node_one;
1775 node_two.
label =
"route2";
1776 first_update[node_two.
id] = node_two;
1779 root_node.
label =
"root";
1782 first_update[root_node.
id] = root_node;
1783 bridge->UpdateSemantics(first_update, actions);
1785 XCTAssertEqual([accessibility_notifications count], 0ul);
1787 bridge->AccessibilityObjectDidBecomeFocused(1);
1793 new_root_node.
label =
"root";
1796 second_update[root_node.
id] = new_root_node;
1797 bridge->UpdateSemantics(second_update, actions);
1798 id focusObject = accessibility_notifications[0][@"argument"];
1801 XCTAssertEqualObjects(focusObject, [NSNull null]);
1802 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1803 UIAccessibilityLayoutChangedNotification);
1806- (void)testAnnouncesLayoutChangeWhenFocusMovedOutside {
1807 flutter::MockDelegate mock_delegate;
1808 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1813 thread_task_runner);
1814 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1816 mock_delegate.settings_.enable_impeller
1821 std::make_shared<fml::SyncSwitch>());
1823 id mockFlutterView = OCMClassMock([
FlutterView class]);
1824 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1826 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1827 [[NSMutableArray alloc] init];
1828 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1829 ios_delegate->on_PostAccessibilityNotification_ =
1830 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1831 [accessibility_notifications addObject:@{
1832 @"notification" : @(notification),
1833 @"argument" : argument ? argument : [NSNull null],
1836 __block
auto bridge =
1837 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1840 std::move(ios_delegate));
1847 node_one.
label =
"route1";
1848 first_update[node_one.
id] = node_one;
1851 node_two.
label =
"route2";
1852 first_update[node_two.
id] = node_two;
1855 root_node.
label =
"root";
1858 first_update[root_node.
id] = root_node;
1859 bridge->UpdateSemantics(first_update, actions);
1861 XCTAssertEqual([accessibility_notifications count], 0ul);
1863 bridge->AccessibilityObjectDidBecomeFocused(1);
1865 bridge->AccessibilityObjectDidLoseFocus(1);
1871 new_root_node.
label =
"root";
1874 second_update[root_node.
id] = new_root_node;
1875 bridge->UpdateSemantics(second_update, actions);
1876 NSNull* focusObject = accessibility_notifications[0][@"argument"];
1879 XCTAssertEqual(focusObject, [NSNull null]);
1880 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1881 UIAccessibilityLayoutChangedNotification);
1884- (void)testAnnouncesScrollChangeWithLastFocused {
1885 flutter::MockDelegate mock_delegate;
1886 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1891 thread_task_runner);
1892 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1894 mock_delegate.settings_.enable_impeller
1899 std::make_shared<fml::SyncSwitch>());
1901 id mockFlutterView = OCMClassMock([
FlutterView class]);
1902 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1904 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1905 [[NSMutableArray alloc] init];
1906 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1907 ios_delegate->on_PostAccessibilityNotification_ =
1908 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1909 [accessibility_notifications addObject:@{
1910 @"notification" : @(notification),
1911 @"argument" : argument ? argument : [NSNull null],
1914 __block
auto bridge =
1915 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1918 std::move(ios_delegate));
1925 node_one.
label =
"route1";
1927 first_update[node_one.
id] = node_one;
1930 root_node.
label =
"root";
1933 first_update[root_node.
id] = root_node;
1934 bridge->UpdateSemantics(first_update, actions);
1937 [accessibility_notifications removeAllObjects];
1940 bridge->AccessibilityObjectDidBecomeFocused(1);
1945 new_node_one.
id = 1;
1946 new_node_one.
label =
"route1";
1948 second_update[new_node_one.
id] = new_node_one;
1949 bridge->UpdateSemantics(second_update, actions);
1950 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
1953 XCTAssertEqual([focusObject uid], 1);
1954 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1955 UIAccessibilityPageScrolledNotification);
1958- (void)testAnnouncesScrollChangeDoesCallNativeAccessibility {
1959 flutter::MockDelegate mock_delegate;
1960 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
1965 thread_task_runner);
1966 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1968 mock_delegate.settings_.enable_impeller
1973 std::make_shared<fml::SyncSwitch>());
1975 id mockFlutterView = OCMClassMock([
FlutterView class]);
1976 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
1978 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1979 [[NSMutableArray alloc] init];
1980 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1981 ios_delegate->on_PostAccessibilityNotification_ =
1982 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1983 [accessibility_notifications addObject:@{
1984 @"notification" : @(notification),
1985 @"argument" : argument ? argument : [NSNull null],
1988 __block
auto bridge =
1989 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1992 std::move(ios_delegate));
1999 node_one.
label =
"route1";
2002 first_update[node_one.
id] = node_one;
2005 root_node.
label =
"root";
2008 first_update[root_node.
id] = root_node;
2009 bridge->UpdateSemantics(first_update, actions);
2012 [accessibility_notifications removeAllObjects];
2015 bridge->AccessibilityObjectDidBecomeFocused(1);
2020 new_node_one.
id = 1;
2021 new_node_one.
label =
"route1";
2024 second_update[new_node_one.
id] = new_node_one;
2025 bridge->UpdateSemantics(second_update, actions);
2026 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
2030 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
2031 UIAccessibilityPageScrolledNotification);
2034- (void)testAnnouncesIgnoresRouteChangesWhenModal {
2035 flutter::MockDelegate mock_delegate;
2036 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
2041 thread_task_runner);
2042 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2044 mock_delegate.settings_.enable_impeller
2049 std::make_shared<fml::SyncSwitch>());
2050 id mockFlutterView = OCMClassMock([
FlutterView class]);
2052 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
2053 std::string label =
"some label";
2055 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2056 [[NSMutableArray alloc] init];
2057 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2058 ios_delegate->on_PostAccessibilityNotification_ =
2059 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2060 [accessibility_notifications addObject:@{
2061 @"notification" : @(notification),
2062 @"argument" : argument ? argument : [NSNull null],
2065 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2066 __block
auto bridge =
2067 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2070 std::move(ios_delegate));
2079 route_node.
label =
"route";
2080 nodes[route_node.
id] = route_node;
2083 root_node.
label = label;
2086 nodes[root_node.
id] = root_node;
2087 bridge->UpdateSemantics(nodes, actions);
2089 XCTAssertEqual([accessibility_notifications count], 0ul);
2092- (void)testAnnouncesIgnoresLayoutChangeWhenModal {
2093 flutter::MockDelegate mock_delegate;
2094 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
2099 thread_task_runner);
2100 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2102 mock_delegate.settings_.enable_impeller
2107 std::make_shared<fml::SyncSwitch>());
2108 id mockFlutterView = OCMClassMock([
FlutterView class]);
2110 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
2112 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2113 [[NSMutableArray alloc] init];
2114 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2115 ios_delegate->on_PostAccessibilityNotification_ =
2116 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2117 [accessibility_notifications addObject:@{
2118 @"notification" : @(notification),
2119 @"argument" : argument ? argument : [NSNull null],
2122 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2123 __block
auto bridge =
2124 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2127 std::move(ios_delegate));
2134 child_node.
label =
"child_node";
2135 nodes[child_node.
id] = child_node;
2138 root_node.
label =
"root";
2141 nodes[root_node.
id] = root_node;
2142 bridge->UpdateSemantics(nodes, actions);
2148 new_root_node.
label =
"root";
2149 new_nodes[new_root_node.
id] = new_root_node;
2150 bridge->UpdateSemantics(new_nodes, actions);
2152 XCTAssertEqual([accessibility_notifications count], 0ul);
2155- (void)testAnnouncesIgnoresScrollChangeWhenModal {
2156 flutter::MockDelegate mock_delegate;
2157 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
2162 thread_task_runner);
2163 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2165 mock_delegate.settings_.enable_impeller
2170 std::make_shared<fml::SyncSwitch>());
2171 id mockFlutterView = OCMClassMock([
FlutterView class]);
2173 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
2175 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2176 [[NSMutableArray alloc] init];
2177 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2178 ios_delegate->on_PostAccessibilityNotification_ =
2179 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2180 [accessibility_notifications addObject:@{
2181 @"notification" : @(notification),
2182 @"argument" : argument ? argument : [NSNull null],
2185 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2186 __block
auto bridge =
2187 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2190 std::move(ios_delegate));
2197 root_node.
label =
"root";
2199 nodes[root_node.
id] = root_node;
2200 bridge->UpdateSemantics(nodes, actions);
2206 new_root_node.
label =
"root";
2208 new_nodes[new_root_node.
id] = new_root_node;
2209 bridge->UpdateSemantics(new_nodes, actions);
2211 XCTAssertEqual([accessibility_notifications count], 0ul);
2214- (void)testAccessibilityMessageAfterDeletion {
2215 flutter::MockDelegate mock_delegate;
2216 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2217 auto thread_task_runner = thread->GetTaskRunner();
2222 thread_task_runner);
2223 id messenger = OCMProtocolMock(
@protocol(FlutterBinaryMessenger));
2227 OCMStub([flutterViewController
engine]).andReturn(
engine);
2228 OCMStub([
engine binaryMessenger]).andReturn(messenger);
2230 OCMStub([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
2231 binaryMessageHandler:[OCMArg any]])
2232 .andReturn(connection);
2234 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2236 mock_delegate.settings_.enable_impeller
2241 std::make_shared<fml::SyncSwitch>());
2243 thread_task_runner->PostTask([&] {
2244 platform_view->SetOwnerViewController(flutterViewController);
2246 std::make_unique<flutter::AccessibilityBridge>(nil,
2249 XCTAssertTrue(bridge.get());
2250 OCMVerify([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
2251 binaryMessageHandler:[OCMArg isNotNil]]);
2256 OCMVerify([messenger cleanUpConnection:connection]);
2257 [engine stopMocking];
2260- (void)testFlutterSemanticsScrollViewManagedObjectLifecycleCorrectly {
2261 flutter::MockDelegate mock_delegate;
2262 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
2267 thread_task_runner);
2268 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2270 mock_delegate.settings_.enable_impeller
2275 std::make_shared<fml::SyncSwitch>());
2276 id mockFlutterView = OCMClassMock([
FlutterView class]);
2278 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
2280 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2281 __block
auto bridge =
2282 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2285 std::move(ios_delegate));
2294 XCTAssertTrue(flutterSemanticsScrollView);
2297 XCTAssertFalse([flutterSemanticsScrollView isAccessibilityElement]);
2300- (void)testPlatformViewDestructorDoesNotCallSemanticsAPIs {
2301 class TestDelegate :
public flutter::MockDelegate {
2303 void OnPlatformViewSetSemanticsEnabled(
bool enabled)
override { set_semantics_enabled_calls++; }
2304 int set_semantics_enabled_calls = 0;
2307 TestDelegate test_delegate;
2308 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2309 auto thread_task_runner = thread->GetTaskRunner();
2314 thread_task_runner);
2317 thread_task_runner->PostTask([&] {
2318 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2320 test_delegate.settings_.enable_impeller
2325 std::make_shared<fml::SyncSwitch>());
2333 OCMStub([mockFlutterViewController platformViewsController])
2334 .andReturn(flutterPlatformViewsController);
2335 platform_view->SetOwnerViewController(mockFlutterViewController);
2338 XCTAssertNotEqual(test_delegate.set_semantics_enabled_calls, 0);
2341 test_delegate.set_semantics_enabled_calls = 0;
2343 XCTAssertEqual(test_delegate.set_semantics_enabled_calls, 0);
2350- (void)testResetsAccessibilityElementsOnHotRestart {
2351 flutter::MockDelegate mock_delegate;
2352 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2353 auto thread_task_runner = thread->GetTaskRunner();
2358 thread_task_runner);
2359 id mockFlutterView = OCMClassMock([
FlutterView class]);
2361 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
2364 thread_task_runner->PostTask([&] {
2365 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2367 mock_delegate.settings_.enable_impeller
2372 std::make_shared<fml::SyncSwitch>());
2374 platform_view->SetOwnerViewController(mockFlutterViewController);
2378 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg isNil]]);
2380 OCMVerifyAll(mockFlutterView);
2387- (void)testWeakViewController {
2388 flutter::MockDelegate mock_delegate;
2389 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
2394 thread_task_runner);
2395 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2397 mock_delegate.settings_.enable_impeller
2402 std::make_shared<fml::SyncSwitch>());
2404 std::unique_ptr<flutter::AccessibilityBridge> bridge;
2406 id mockFlutterView = OCMClassMock([
FlutterView class]);
2408 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
2409 OCMStub([mockFlutterViewController
view]).andReturn(mockFlutterView);
2411 bridge = std::make_unique<flutter::AccessibilityBridge>(
2412 mockFlutterViewController,
2415 XCTAssertTrue(bridge.get());
2416 XCTAssertNotNil(bridge->view());
2418 XCTAssertNil(bridge->view());
2421- (void)testSemanticsObjectAndContainerAccessAfterBridgeDestruction {
2422 flutter::MockDelegate mock_delegate;
2423 auto thread_task_runner = CreateNewThread(
"AccessibilityBridgeTest");
2428 thread_task_runner);
2429 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2431 mock_delegate.settings_.enable_impeller
2436 std::make_shared<fml::SyncSwitch>());
2441 enableWideGamut:NO];
2442 OCMStub([mockFlutterViewController
view]).andReturn(flutterView);
2445 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(flutterView);
2447 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
2448 mockFlutterViewController,
2455 root_node.
label =
"root";
2461 child_node.
label =
"child";
2462 nodes[root_node.
id] = root_node;
2463 nodes[child_node.
id] = child_node;
2466 bridge->UpdateSemantics(nodes, actions);
2468 NSArray* accessibilityElements = flutterView.accessibilityElements;
2469 XCTAssertEqual([accessibilityElements count], 1u);
2471 XCTAssertNotNil(rootContainer);
2473 XCTAssertNotNil(rootObject);
2479 XCTAssertNil([rootContainer accessibilityContainer]);
2483 XCTAssertFalse([rootObject accessibilityActivate]);
2484 XCTAssertTrue(CGPointEqualToPoint([rootObject accessibilityActivationPoint], CGPointZero));
2485 XCTAssertTrue(CGRectEqualToRect([rootObject accessibilityFrame], CGRectZero));
2486 XCTAssertNil([rootObject _accessibilityHitTest:CGPointZero withEvent:nil]);
2489- (void)testAccessibilityChannelCallbackAfterBridgeDestruction {
2490 flutter::MockDelegate mock_delegate;
2499 thread_task_runner);
2500 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2502 mock_delegate.settings_.enable_impeller
2507 std::make_shared<fml::SyncSwitch>());
2511 id mockBinaryMessenger = OCMProtocolMock(
@protocol(FlutterBinaryMessenger));
2513 OCMStub([mockFlutterViewController
engine]).andReturn(mockEngine);
2514 OCMStub([mockEngine binaryMessenger]).andReturn(mockBinaryMessenger);
2518 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(nil);
2523 OCMStub([mockFlutterViewController isViewLoaded]).andReturn(NO);
2526 OCMStub([mockBinaryMessenger setMessageHandlerOnChannel:
@"flutter/accessibility"
2527 binaryMessageHandler:[OCMArg checkWithBlock:^BOOL(id obj) {
2529 capturedHandler = [obj copy];
2534 platform_view->SetOwnerViewController(mockFlutterViewController);
2536 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
2537 mockFlutterViewController,
2541 XCTAssertNotNil(capturedHandler);
2545 NSDictionary*
event = @{
@"type" :
@"announce",
@"data" : @{
@"message" :
@"test"}};
2547 if (capturedHandler) {
2548 capturedHandler(messageData, ^(NSData* reply){
void(^ FlutterBinaryMessageHandler)(NSData *_Nullable message, FlutterBinaryReply reply)
int64_t FlutterBinaryMessengerConnection
void(^ FlutterResult)(id _Nullable result)
NS_ASSUME_NONNULL_BEGIN 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.
static void EnsureInitializedForCurrentThread()
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
G_BEGIN_DECLS FlutterViewId view_id
FlutterDesktopBinaryReply callback
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
SemanticsObject * semanticsObject
constexpr int kHorizontalScrollSemanticsActions
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
std::unordered_map< int32_t, CustomAccessibilityAction > CustomAccessibilityActionUpdates
std::function< void()> closure
instancetype sharedInstance()
impeller::ShaderType type
SemanticsCheckState isChecked
SemanticsTristate isEnabled
bool isInMutuallyExclusiveGroup
bool hasImplicitScrolling
std::vector< int32_t > childrenInHitTestOrder
std::vector< int32_t > childrenInTraversalOrder