5 #import <OCMock/OCMock.h>
6 #import <XCTest/XCTest.h>
8 #import "flutter/fml/thread.h"
28 - (instancetype)init {
43 @property(nonatomic, strong) UIView* view;
48 - (instancetype)init {
49 if (
self = [super init]) {
61 - (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
62 viewIdentifier:(int64_t)viewId
63 arguments:(
id _Nullable)args {
71 class MockDelegate :
public PlatformView::Delegate {
73 void OnPlatformViewCreated(std::unique_ptr<Surface> surface)
override {}
74 void OnPlatformViewDestroyed()
override {}
75 void OnPlatformViewScheduleFrame()
override {}
76 void OnPlatformViewAddView(int64_t view_id,
77 const ViewportMetrics& viewport_metrics,
78 AddViewCallback callback)
override {}
79 void OnPlatformViewRemoveView(int64_t view_id, RemoveViewCallback callback)
override {}
80 void OnPlatformViewSendViewFocusEvent(
const ViewFocusEvent& event)
override {};
81 void OnPlatformViewSetNextFrameCallback(
const fml::closure& closure)
override {}
82 void OnPlatformViewSetViewportMetrics(int64_t view_id,
const ViewportMetrics& metrics)
override {}
83 const flutter::Settings& OnPlatformViewGetSettings()
const override {
return settings_; }
84 void OnPlatformViewDispatchPlatformMessage(std::unique_ptr<PlatformMessage> message)
override {}
85 void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet)
override {
87 HitTestResponse OnPlatformViewHitTest(int64_t view_id,
const flutter::PointData offset)
override {
88 return {.has_platform_view =
false};
90 void OnPlatformViewDispatchSemanticsAction(int64_t view_id,
92 SemanticsAction action,
93 fml::MallocMapping args)
override {}
94 void OnPlatformViewSetSemanticsEnabled(
bool enabled)
override {}
95 void OnPlatformViewSetAccessibilityFeatures(int32_t flags)
override {}
96 void OnPlatformViewRegisterTexture(std::shared_ptr<Texture> texture)
override {}
97 void OnPlatformViewUnregisterTexture(int64_t
texture_id)
override {}
98 void OnPlatformViewMarkTextureFrameAvailable(int64_t
texture_id)
override {}
100 void LoadDartDeferredLibrary(intptr_t loading_unit_id,
101 std::unique_ptr<const fml::Mapping> snapshot_data,
102 std::unique_ptr<const fml::Mapping> snapshot_instructions)
override {
104 void LoadDartDeferredLibraryError(intptr_t loading_unit_id,
105 const std::string error_message,
106 bool transient)
override {}
107 void UpdateAssetResolverByType(std::unique_ptr<flutter::AssetResolver> updated_asset_resolver,
108 flutter::AssetResolver::AssetResolverType type)
override {}
113 class MockIosDelegate :
public AccessibilityBridge::IosDelegate {
115 bool IsFlutterViewControllerPresentingModalViewController(
117 return result_IsFlutterViewControllerPresentingModalViewController_;
120 void PostAccessibilityNotification(UIAccessibilityNotifications notification,
121 id argument)
override {
122 if (on_PostAccessibilityNotification_) {
123 on_PostAccessibilityNotification_(notification, argument);
126 std::function<void(UIAccessibilityNotifications,
id)> on_PostAccessibilityNotification_;
127 bool result_IsFlutterViewControllerPresentingModalViewController_ =
false;
133 fml::RefPtr<fml::TaskRunner>
CreateNewThread(
const std::string& name) {
134 auto thread = std::make_unique<fml::Thread>(name);
135 auto runner = thread->GetTaskRunner();
146 flutter::MockDelegate mock_delegate;
148 flutter::TaskRunners runners(
self.name.UTF8String,
153 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
155 mock_delegate.settings_.enable_impeller
161 std::make_shared<fml::SyncSwitch>());
163 std::make_unique<flutter::AccessibilityBridge>(nil,
166 XCTAssertTrue(bridge.get());
169 - (void)testUpdateSemanticsEmpty {
170 flutter::MockDelegate mock_delegate;
172 flutter::TaskRunners runners(
self.name.UTF8String,
177 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
179 mock_delegate.settings_.enable_impeller
185 std::make_shared<fml::SyncSwitch>());
186 id mockFlutterView = OCMClassMock([
FlutterView class]);
188 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
189 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg isNil]]);
191 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
194 flutter::SemanticsNodeUpdates nodes;
195 flutter::CustomAccessibilityActionUpdates actions;
196 bridge->UpdateSemantics(nodes, actions);
197 OCMVerifyAll(mockFlutterView);
200 - (void)testUpdateSemanticsOneNode {
201 flutter::MockDelegate mock_delegate;
203 flutter::TaskRunners runners(
self.name.UTF8String,
208 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
210 mock_delegate.settings_.enable_impeller
216 std::make_shared<fml::SyncSwitch>());
217 id mockFlutterView = OCMClassMock([
FlutterView class]);
219 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
220 std::string label =
"some label";
222 __block
auto bridge =
223 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
227 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg checkWithBlock:^BOOL(NSArray* value) {
228 if ([value count] != 1) {
234 object.bridge.get() == bridge.get() &&
235 object.node.label == label;
239 flutter::SemanticsNodeUpdates nodes;
240 flutter::SemanticsNode semantics_node;
242 semantics_node.label = label;
243 nodes[kRootNodeId] = semantics_node;
244 flutter::CustomAccessibilityActionUpdates actions;
245 bridge->UpdateSemantics(nodes, actions);
246 OCMVerifyAll(mockFlutterView);
249 - (void)testIsVoiceOverRunning {
250 flutter::MockDelegate mock_delegate;
252 flutter::TaskRunners runners(
self.name.UTF8String,
257 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
259 mock_delegate.settings_.enable_impeller
265 std::make_shared<fml::SyncSwitch>());
266 id mockFlutterView = OCMClassMock([
FlutterView class]);
268 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
269 OCMStub([mockFlutterViewController isVoiceOverRunning]).andReturn(YES);
271 __block
auto bridge =
272 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
276 XCTAssertTrue(bridge->isVoiceOverRunning());
279 - (void)testSemanticsDeallocated {
281 flutter::MockDelegate mock_delegate;
283 flutter::TaskRunners runners(
self.name.UTF8String,
293 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
295 mock_delegate.settings_.enable_impeller
298 flutterPlatformViewsController,
301 std::make_shared<fml::SyncSwitch>());
302 id mockFlutterView = OCMClassMock([
FlutterView class]);
304 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
305 std::string label =
"some label";
306 flutterPlatformViewsController.
flutterView = mockFlutterView;
309 [flutterPlatformViewsController
311 withId:@"MockFlutterPlatformView"
315 [flutterPlatformViewsController
319 @"viewType" : @"MockFlutterPlatformView"
323 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
324 mockFlutterViewController,
326 flutterPlatformViewsController);
328 flutter::SemanticsNodeUpdates nodes;
329 flutter::SemanticsNode semantics_node;
330 semantics_node.id = 2;
331 semantics_node.platformViewId = 2;
332 semantics_node.label = label;
333 nodes[kRootNodeId] = semantics_node;
334 flutter::CustomAccessibilityActionUpdates actions;
335 bridge->UpdateSemantics(nodes, actions);
337 [flutterPlatformViewsController
reset];
342 - (void)testSemanticsDeallocatedWithoutLoadingView {
347 flutter::MockDelegate mock_delegate;
349 flutter::TaskRunners runners(
self.name.UTF8String,
359 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
361 mock_delegate.settings_.enable_impeller
364 flutterPlatformViewsController,
367 std::make_shared<fml::SyncSwitch>());
370 [flutterPlatformViewsController
372 withId:@"MockFlutterPlatformView"
376 [flutterPlatformViewsController
380 @"viewType" : @"MockFlutterPlatformView"
384 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
385 flutterViewController,
387 flutterPlatformViewsController);
390 [flutterPlatformViewsController
reset];
394 XCTAssertNil(flutterViewController.viewIfLoaded);
395 [flutterViewController deregisterNotifications];
398 - (void)testReplacedSemanticsDoesNotCleanupChildren {
399 flutter::MockDelegate mock_delegate;
401 flutter::TaskRunners runners(
self.name.UTF8String,
411 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
413 mock_delegate.settings_.enable_impeller
416 flutterPlatformViewsController,
419 std::make_shared<fml::SyncSwitch>());
425 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
426 std::string label =
"some label";
427 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
428 mockFlutterViewController,
430 flutterPlatformViewsController);
432 flutter::SemanticsNodeUpdates nodes;
433 flutter::SemanticsNode parent;
435 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
436 parent.label =
"label";
437 parent.value =
"value";
438 parent.hint =
"hint";
440 flutter::SemanticsNode node;
442 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
443 node.label =
"label";
444 node.value =
"value";
446 node.scrollExtentMax = 100.0;
447 node.scrollPosition = 0.0;
448 parent.childrenInTraversalOrder.push_back(1);
449 parent.childrenInHitTestOrder.push_back(1);
451 flutter::SemanticsNode child;
453 child.rect = SkRect::MakeXYWH(0, 0, 100, 200);
454 child.label =
"label";
455 child.value =
"value";
457 node.childrenInTraversalOrder.push_back(2);
458 node.childrenInHitTestOrder.push_back(2);
463 flutter::CustomAccessibilityActionUpdates actions;
464 bridge->UpdateSemantics(nodes, actions);
467 flutter::SemanticsNodeUpdates new_nodes;
468 flutter::SemanticsNode new_node;
470 new_node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
471 new_node.flags.hasImplicitScrolling =
true;
472 new_node.actions = flutter::kHorizontalScrollSemanticsActions;
473 new_node.label =
"label";
474 new_node.value =
"value";
475 new_node.hint =
"hint";
476 new_node.scrollExtentMax = 100.0;
477 new_node.scrollPosition = 0.0;
478 new_node.childrenInTraversalOrder.push_back(2);
479 new_node.childrenInHitTestOrder.push_back(2);
481 new_nodes[1] = new_node;
482 bridge->UpdateSemantics(new_nodes, actions);
486 id rootContainer = flutterView.accessibilityElements[0];
487 XCTAssertTrue([rootContainer accessibilityElementCount] ==
489 id scrollableContainer = [rootContainer accessibilityElementAtIndex:1];
490 XCTAssertTrue([scrollableContainer accessibilityElementCount] ==
492 id child = [scrollableContainer accessibilityElementAtIndex:1];
494 XCTAssertNotNil([child accessibilityContainer]);
497 - (void)testScrollableSemanticsDeallocated {
498 flutter::MockDelegate mock_delegate;
500 flutter::TaskRunners runners(
self.name.UTF8String,
510 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
512 mock_delegate.settings_.enable_impeller
515 flutterPlatformViewsController,
518 std::make_shared<fml::SyncSwitch>());
524 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
525 std::string label =
"some label";
527 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
528 mockFlutterViewController,
530 flutterPlatformViewsController);
532 flutter::SemanticsNodeUpdates nodes;
533 flutter::SemanticsNode parent;
535 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
536 parent.label =
"label";
537 parent.value =
"value";
538 parent.hint =
"hint";
540 flutter::SemanticsNode node;
542 node.flags.hasImplicitScrolling =
true;
543 node.actions = flutter::kHorizontalScrollSemanticsActions;
544 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
545 node.label =
"label";
546 node.value =
"value";
548 node.scrollExtentMax = 100.0;
549 node.scrollPosition = 0.0;
550 parent.childrenInTraversalOrder.push_back(1);
551 parent.childrenInHitTestOrder.push_back(1);
554 flutter::CustomAccessibilityActionUpdates actions;
555 bridge->UpdateSemantics(nodes, actions);
556 XCTAssertTrue([flutterView.subviews count] == 1);
558 XCTAssertTrue([flutterView.subviews[0].accessibilityLabel isEqualToString:
@"label"]);
561 flutter::SemanticsNodeUpdates new_nodes;
562 flutter::SemanticsNode new_parent;
564 new_parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
565 new_parent.label =
"label";
566 new_parent.value =
"value";
567 new_parent.hint =
"hint";
568 new_nodes[0] = new_parent;
569 bridge->UpdateSemantics(new_nodes, actions);
571 XCTAssertTrue([flutterView.subviews count] == 0);
574 - (void)testBridgeReplacesSemanticsNode {
575 flutter::MockDelegate mock_delegate;
577 flutter::TaskRunners runners(
self.name.UTF8String,
585 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
587 mock_delegate.settings_.enable_impeller
590 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);
607 flutter::SemanticsNodeUpdates nodes;
608 flutter::SemanticsNode parent;
610 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
611 parent.label =
"label";
612 parent.value =
"value";
613 parent.hint =
"hint";
615 flutter::SemanticsNode node;
617 node.flags.hasImplicitScrolling =
true;
618 node.actions = flutter::kHorizontalScrollSemanticsActions;
619 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
620 node.label =
"label";
621 node.value =
"value";
623 node.scrollExtentMax = 100.0;
624 node.scrollPosition = 0.0;
625 parent.childrenInTraversalOrder.push_back(1);
626 parent.childrenInHitTestOrder.push_back(1);
629 flutter::CustomAccessibilityActionUpdates actions;
630 bridge->UpdateSemantics(nodes, actions);
631 XCTAssertTrue([flutterView.subviews count] == 1);
633 XCTAssertTrue([flutterView.subviews[0].accessibilityLabel isEqualToString:
@"label"]);
636 flutter::SemanticsNodeUpdates new_nodes;
637 flutter::SemanticsNode new_node;
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";
643 new_node.scrollExtentMax = 100.0;
644 new_node.scrollPosition = 0.0;
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;
654 flutter::TaskRunners runners(
self.name.UTF8String,
659 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
661 mock_delegate.settings_.enable_impeller
667 std::make_shared<fml::SyncSwitch>());
668 id mockFlutterView = OCMClassMock([
FlutterView class]);
670 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
672 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
673 [[NSMutableArray alloc] init];
674 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
675 ios_delegate->on_PostAccessibilityNotification_ =
676 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
677 [accessibility_notifications addObject:@{
678 @"notification" : @(notification),
679 @"argument" : argument ? argument : [NSNull null],
682 __block
auto bridge =
683 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
686 std::move(ios_delegate));
688 flutter::CustomAccessibilityActionUpdates actions;
689 flutter::SemanticsNodeUpdates nodes;
691 flutter::SemanticsNode node1;
693 node1.label =
"node1";
694 node1.flags.scopesRoute =
true;
695 node1.childrenInTraversalOrder = {2, 3};
696 node1.childrenInHitTestOrder = {2, 3};
697 nodes[node1.id] = node1;
698 flutter::SemanticsNode node2;
700 node2.label =
"node2";
701 nodes[node2.id] = node2;
702 flutter::SemanticsNode node3;
704 node3.flags.namesRoute =
true;
705 node3.label =
"node3";
706 nodes[node3.id] = node3;
707 flutter::SemanticsNode root_node;
709 root_node.flags.scopesRoute =
true;
710 root_node.childrenInTraversalOrder = {1};
711 root_node.childrenInHitTestOrder = {1};
712 nodes[root_node.id] = root_node;
713 bridge->UpdateSemantics(nodes, actions);
715 XCTAssertEqual([accessibility_notifications count], 1ul);
716 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node3");
717 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
718 UIAccessibilityScreenChangedNotification);
721 - (void)testRadioButtonIsNotSwitchButton {
722 flutter::MockDelegate mock_delegate;
724 flutter::TaskRunners runners(
self.name.UTF8String,
729 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
731 mock_delegate.settings_.enable_impeller
737 std::make_shared<fml::SyncSwitch>());
743 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
744 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
745 __block
auto bridge =
746 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
749 std::move(ios_delegate));
751 flutter::CustomAccessibilityActionUpdates actions;
752 flutter::SemanticsNodeUpdates nodes;
754 flutter::SemanticsNode root_node;
756 root_node.flags.isInMutuallyExclusiveGroup =
true;
757 root_node.flags.isEnabled = flutter::SemanticsTristate::kTrue;
758 root_node.flags.isChecked = flutter::SemanticsCheckState::kFalse;
759 nodes[root_node.id] = root_node;
760 bridge->UpdateSemantics(nodes, actions);
765 XCTAssertTrue((rootNode.accessibilityTraits & UIAccessibilityTraitButton) > 0);
766 XCTAssertNil(rootNode.accessibilityValue);
769 - (void)testSemanticObjectWithNoAccessibilityFlagNotMarkedAsResponsiveToUserInteraction {
770 flutter::MockDelegate mock_delegate;
772 flutter::TaskRunners runners(
self.name.UTF8String,
777 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
779 mock_delegate.settings_.enable_impeller
785 std::make_shared<fml::SyncSwitch>());
791 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
792 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
793 __block
auto bridge =
794 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
797 std::move(ios_delegate));
799 flutter::CustomAccessibilityActionUpdates actions;
800 flutter::SemanticsNodeUpdates nodes;
802 flutter::SemanticsNode root_node;
805 nodes[root_node.id] = root_node;
806 bridge->UpdateSemantics(nodes, actions);
811 XCTAssertFalse(rootNode.accessibilityRespondsToUserInteraction);
814 - (void)testSemanticObjectWithAccessibilityFlagsMarkedAsResponsiveToUserInteraction {
815 flutter::MockDelegate mock_delegate;
817 flutter::TaskRunners runners(
self.name.UTF8String,
822 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
824 mock_delegate.settings_.enable_impeller
830 std::make_shared<fml::SyncSwitch>());
836 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
837 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
838 __block
auto bridge =
839 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
842 std::move(ios_delegate));
844 flutter::CustomAccessibilityActionUpdates actions;
845 flutter::SemanticsNodeUpdates nodes;
847 flutter::SemanticsNode root_node;
849 root_node.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
851 nodes[root_node.id] = root_node;
852 bridge->UpdateSemantics(nodes, actions);
857 XCTAssertTrue(rootNode.accessibilityRespondsToUserInteraction);
862 - (void)testLabeledParentAndChildNotInteractive {
863 flutter::MockDelegate mock_delegate;
865 flutter::TaskRunners runners(
self.name.UTF8String,
873 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
875 mock_delegate.settings_.enable_impeller
878 flutterPlatformViewsController,
881 std::make_shared<fml::SyncSwitch>());
887 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
890 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
891 mockFlutterViewController,
893 flutterPlatformViewsController);
895 flutter::SemanticsNodeUpdates nodes;
897 flutter::SemanticsNode parent;
899 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
900 parent.label =
"parent_label";
902 flutter::SemanticsNode node;
904 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
905 node.label =
"child_label";
907 parent.childrenInTraversalOrder.push_back(1);
908 parent.childrenInHitTestOrder.push_back(1);
911 flutter::CustomAccessibilityActionUpdates actions;
912 bridge->UpdateSemantics(nodes, actions);
918 XCTAssertTrue([parentNode.accessibilityLabel isEqualToString:
@"parent_label"]);
919 XCTAssertTrue([childNode.accessibilityLabel isEqualToString:
@"child_label"]);
920 XCTAssertFalse(parentNode.accessibilityRespondsToUserInteraction);
921 XCTAssertFalse(childNode.accessibilityRespondsToUserInteraction);
925 - (void)testLayoutChangeWithNonAccessibilityElement {
926 flutter::MockDelegate mock_delegate;
928 flutter::TaskRunners runners(
self.name.UTF8String,
933 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
935 mock_delegate.settings_.enable_impeller
941 std::make_shared<fml::SyncSwitch>());
942 id mockFlutterView = OCMClassMock([
FlutterView class]);
944 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
946 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
947 [[NSMutableArray alloc] init];
948 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
949 ios_delegate->on_PostAccessibilityNotification_ =
950 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
951 [accessibility_notifications addObject:@{
952 @"notification" : @(notification),
953 @"argument" : argument ? argument : [NSNull null],
956 __block
auto bridge =
957 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
960 std::move(ios_delegate));
962 flutter::CustomAccessibilityActionUpdates actions;
963 flutter::SemanticsNodeUpdates nodes;
965 flutter::SemanticsNode node1;
967 node1.label =
"node1";
968 node1.childrenInTraversalOrder = {2, 3};
969 node1.childrenInHitTestOrder = {2, 3};
970 nodes[node1.id] = node1;
971 flutter::SemanticsNode node2;
973 node2.label =
"node2";
974 nodes[node2.id] = node2;
975 flutter::SemanticsNode node3;
977 node3.label =
"node3";
978 nodes[node3.id] = node3;
979 flutter::SemanticsNode root_node;
981 root_node.label =
"root";
982 root_node.childrenInTraversalOrder = {1};
983 root_node.childrenInHitTestOrder = {1};
984 nodes[root_node.id] = root_node;
985 bridge->UpdateSemantics(nodes, actions);
988 bridge->AccessibilityObjectDidBecomeFocused(1);
993 flutter::CustomAccessibilityActionUpdates new_actions;
994 flutter::SemanticsNodeUpdates new_nodes;
996 flutter::SemanticsNode new_node1;
998 new_node1.childrenInTraversalOrder = {2};
999 new_node1.childrenInHitTestOrder = {2};
1000 new_nodes[new_node1.id] = new_node1;
1001 bridge->UpdateSemantics(new_nodes, new_actions);
1003 XCTAssertEqual([accessibility_notifications count], 1ul);
1004 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
1006 XCTAssertEqual([focusObject uid], 2);
1007 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1008 UIAccessibilityLayoutChangedNotification);
1011 - (void)testLayoutChangeDoesCallNativeAccessibility {
1012 flutter::MockDelegate mock_delegate;
1014 flutter::TaskRunners runners(
self.name.UTF8String,
1018 thread_task_runner);
1019 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1021 mock_delegate.settings_.enable_impeller
1027 std::make_shared<fml::SyncSwitch>());
1028 id mockFlutterView = OCMClassMock([
FlutterView class]);
1030 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1032 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1033 [[NSMutableArray alloc] init];
1034 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1035 ios_delegate->on_PostAccessibilityNotification_ =
1036 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1037 [accessibility_notifications addObject:@{
1038 @"notification" : @(notification),
1039 @"argument" : argument ? argument : [NSNull null],
1042 __block
auto bridge =
1043 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1046 std::move(ios_delegate));
1048 flutter::CustomAccessibilityActionUpdates actions;
1049 flutter::SemanticsNodeUpdates nodes;
1051 flutter::SemanticsNode node1;
1053 node1.label =
"node1";
1054 nodes[node1.id] = node1;
1055 flutter::SemanticsNode root_node;
1057 root_node.label =
"root";
1058 root_node.flags.hasImplicitScrolling =
true;
1059 root_node.childrenInTraversalOrder = {1};
1060 root_node.childrenInHitTestOrder = {1};
1061 nodes[root_node.id] = root_node;
1062 bridge->UpdateSemantics(nodes, actions);
1065 bridge->AccessibilityObjectDidBecomeFocused(0);
1068 flutter::CustomAccessibilityActionUpdates new_actions;
1069 flutter::SemanticsNodeUpdates new_nodes;
1071 flutter::SemanticsNode new_root_node;
1073 new_root_node.label =
"root";
1074 new_root_node.flags.hasImplicitScrolling =
true;
1075 new_nodes[new_root_node.id] = new_root_node;
1076 bridge->UpdateSemantics(new_nodes, new_actions);
1078 XCTAssertEqual([accessibility_notifications count], 1ul);
1079 id focusObject = accessibility_notifications[0][@"argument"];
1083 XCTAssertEqualObjects(focusObject, [NSNull
null]);
1084 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1085 UIAccessibilityLayoutChangedNotification);
1088 - (void)testLayoutChangeDoesCallNativeAccessibilityWhenFocusChanged {
1089 flutter::MockDelegate mock_delegate;
1091 flutter::TaskRunners runners(
self.name.UTF8String,
1095 thread_task_runner);
1096 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1098 mock_delegate.settings_.enable_impeller
1104 std::make_shared<fml::SyncSwitch>());
1105 id mockFlutterView = OCMClassMock([
FlutterView class]);
1107 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1109 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1110 [[NSMutableArray alloc] init];
1111 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1112 ios_delegate->on_PostAccessibilityNotification_ =
1113 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1114 [accessibility_notifications addObject:@{
1115 @"notification" : @(notification),
1116 @"argument" : argument ? argument : [NSNull null],
1119 __block
auto bridge =
1120 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1123 std::move(ios_delegate));
1125 flutter::CustomAccessibilityActionUpdates actions;
1126 flutter::SemanticsNodeUpdates nodes;
1128 flutter::SemanticsNode node1;
1130 node1.label =
"node1";
1131 nodes[node1.id] = node1;
1132 flutter::SemanticsNode root_node;
1134 root_node.label =
"root";
1135 root_node.flags.hasImplicitScrolling =
true;
1136 root_node.childrenInTraversalOrder = {1};
1137 root_node.childrenInHitTestOrder = {1};
1138 nodes[root_node.id] = root_node;
1139 bridge->UpdateSemantics(nodes, actions);
1142 bridge->AccessibilityObjectDidBecomeFocused(1);
1145 flutter::CustomAccessibilityActionUpdates new_actions;
1146 flutter::SemanticsNodeUpdates new_nodes;
1148 flutter::SemanticsNode new_root_node;
1150 new_root_node.label =
"root";
1151 new_root_node.flags.hasImplicitScrolling =
true;
1152 new_nodes[new_root_node.id] = new_root_node;
1153 bridge->UpdateSemantics(new_nodes, new_actions);
1155 XCTAssertEqual([accessibility_notifications count], 1ul);
1156 SemanticsObject* focusObject2 = accessibility_notifications[0][@"argument"];
1160 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1161 UIAccessibilityLayoutChangedNotification);
1164 - (void)testScrollableSemanticsContainerReturnsCorrectChildren {
1165 flutter::MockDelegate mock_delegate;
1167 flutter::TaskRunners runners(
self.name.UTF8String,
1171 thread_task_runner);
1172 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1174 mock_delegate.settings_.enable_impeller
1180 std::make_shared<fml::SyncSwitch>());
1181 id mockFlutterView = OCMClassMock([
FlutterView class]);
1183 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1185 OCMExpect([mockFlutterView
1186 setAccessibilityElements:[OCMArg checkWithBlock:^BOOL(NSArray* value) {
1187 if ([value count] != 1) {
1196 return [scrollableContainer indexOfAccessibilityElement:nativeScrollable] == 1;
1198 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1199 __block
auto bridge =
1200 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1203 std::move(ios_delegate));
1205 flutter::CustomAccessibilityActionUpdates actions;
1206 flutter::SemanticsNodeUpdates nodes;
1208 flutter::SemanticsNode node1;
1210 node1.label =
"node1";
1211 node1.flags.hasImplicitScrolling =
true;
1212 nodes[node1.id] = node1;
1213 flutter::SemanticsNode root_node;
1215 root_node.label =
"root";
1216 root_node.childrenInTraversalOrder = {1};
1217 root_node.childrenInHitTestOrder = {1};
1218 nodes[root_node.id] = root_node;
1219 bridge->UpdateSemantics(nodes, actions);
1220 OCMVerifyAll(mockFlutterView);
1223 - (void)testAnnouncesRouteChangesAndLayoutChangeInOneUpdate {
1224 flutter::MockDelegate mock_delegate;
1226 flutter::TaskRunners runners(
self.name.UTF8String,
1230 thread_task_runner);
1231 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1233 mock_delegate.settings_.enable_impeller
1239 std::make_shared<fml::SyncSwitch>());
1240 id mockFlutterView = OCMClassMock([
FlutterView class]);
1242 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1244 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1245 [[NSMutableArray alloc] init];
1246 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1247 ios_delegate->on_PostAccessibilityNotification_ =
1248 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1249 [accessibility_notifications addObject:@{
1250 @"notification" : @(notification),
1251 @"argument" : argument ? argument : [NSNull null],
1254 __block
auto bridge =
1255 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1258 std::move(ios_delegate));
1260 flutter::CustomAccessibilityActionUpdates actions;
1261 flutter::SemanticsNodeUpdates nodes;
1263 flutter::SemanticsNode node1;
1265 node1.label =
"node1";
1266 node1.flags.scopesRoute =
true;
1267 node1.flags.namesRoute =
true;
1268 nodes[node1.id] = node1;
1269 flutter::SemanticsNode node3;
1271 node3.label =
"node3";
1272 nodes[node3.id] = node3;
1273 flutter::SemanticsNode root_node;
1275 root_node.label =
"root";
1276 root_node.childrenInTraversalOrder = {1, 3};
1277 root_node.childrenInHitTestOrder = {1, 3};
1278 nodes[root_node.id] = root_node;
1279 bridge->UpdateSemantics(nodes, actions);
1281 XCTAssertEqual([accessibility_notifications count], 1ul);
1282 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node1");
1283 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1284 UIAccessibilityScreenChangedNotification);
1287 bridge->AccessibilityObjectDidBecomeFocused(0);
1289 flutter::SemanticsNodeUpdates new_nodes;
1291 flutter::SemanticsNode new_node1;
1293 new_node1.label =
"new_node1";
1294 new_node1.flags.scopesRoute =
true;
1295 new_node1.flags.namesRoute =
true;
1296 new_node1.childrenInTraversalOrder = {2};
1297 new_node1.childrenInHitTestOrder = {2};
1298 new_nodes[new_node1.id] = new_node1;
1299 flutter::SemanticsNode new_node2;
1301 new_node2.label =
"new_node2";
1302 new_node2.flags.scopesRoute =
true;
1303 new_node2.flags.namesRoute =
true;
1304 new_nodes[new_node2.id] = new_node2;
1305 flutter::SemanticsNode new_root_node;
1307 new_root_node.label =
"root";
1308 new_root_node.childrenInTraversalOrder = {1};
1309 new_root_node.childrenInHitTestOrder = {1};
1310 new_nodes[new_root_node.id] = new_root_node;
1311 bridge->UpdateSemantics(new_nodes, actions);
1312 XCTAssertEqual([accessibility_notifications count], 3ul);
1313 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1314 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1315 UIAccessibilityScreenChangedNotification);
1316 SemanticsObject* focusObject = accessibility_notifications[2][@"argument"];
1317 XCTAssertEqual([focusObject uid], 0);
1318 XCTAssertEqual([accessibility_notifications[2][
@"notification"] unsignedIntValue],
1319 UIAccessibilityLayoutChangedNotification);
1322 - (void)testAnnouncesRouteChangesWhenAddAdditionalRoute {
1323 flutter::MockDelegate mock_delegate;
1325 flutter::TaskRunners runners(
self.name.UTF8String,
1329 thread_task_runner);
1330 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1332 mock_delegate.settings_.enable_impeller
1338 std::make_shared<fml::SyncSwitch>());
1339 id mockFlutterView = OCMClassMock([
FlutterView class]);
1341 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1343 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1344 [[NSMutableArray alloc] init];
1345 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1346 ios_delegate->on_PostAccessibilityNotification_ =
1347 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1348 [accessibility_notifications addObject:@{
1349 @"notification" : @(notification),
1350 @"argument" : argument ? argument : [NSNull null],
1353 __block
auto bridge =
1354 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1357 std::move(ios_delegate));
1359 flutter::CustomAccessibilityActionUpdates actions;
1360 flutter::SemanticsNodeUpdates nodes;
1362 flutter::SemanticsNode node1;
1364 node1.label =
"node1";
1365 node1.flags.scopesRoute =
true;
1366 node1.flags.namesRoute =
true;
1367 nodes[node1.id] = node1;
1368 flutter::SemanticsNode root_node;
1370 root_node.flags.scopesRoute =
true;
1371 root_node.childrenInTraversalOrder = {1};
1372 root_node.childrenInHitTestOrder = {1};
1373 nodes[root_node.id] = root_node;
1374 bridge->UpdateSemantics(nodes, actions);
1376 XCTAssertEqual([accessibility_notifications count], 1ul);
1377 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node1");
1378 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1379 UIAccessibilityScreenChangedNotification);
1381 flutter::SemanticsNodeUpdates new_nodes;
1383 flutter::SemanticsNode new_node1;
1385 new_node1.label =
"new_node1";
1386 new_node1.flags.scopesRoute =
true;
1387 new_node1.flags.namesRoute =
true;
1388 new_node1.childrenInTraversalOrder = {2};
1389 new_node1.childrenInHitTestOrder = {2};
1390 new_nodes[new_node1.id] = new_node1;
1391 flutter::SemanticsNode new_node2;
1393 new_node2.label =
"new_node2";
1394 new_node2.flags.scopesRoute =
true;
1395 new_node2.flags.namesRoute =
true;
1396 new_nodes[new_node2.id] = new_node2;
1397 flutter::SemanticsNode new_root_node;
1399 new_root_node.flags.scopesRoute =
true;
1400 new_root_node.childrenInTraversalOrder = {1};
1401 new_root_node.childrenInHitTestOrder = {1};
1402 new_nodes[new_root_node.id] = new_root_node;
1403 bridge->UpdateSemantics(new_nodes, actions);
1404 XCTAssertEqual([accessibility_notifications count], 2ul);
1405 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1406 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1407 UIAccessibilityScreenChangedNotification);
1410 - (void)testAnnouncesRouteChangesRemoveRouteInMiddle {
1411 flutter::MockDelegate mock_delegate;
1413 flutter::TaskRunners runners(
self.name.UTF8String,
1417 thread_task_runner);
1418 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1420 mock_delegate.settings_.enable_impeller
1426 std::make_shared<fml::SyncSwitch>());
1427 id mockFlutterView = OCMClassMock([
FlutterView class]);
1429 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1431 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1432 [[NSMutableArray alloc] init];
1433 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1434 ios_delegate->on_PostAccessibilityNotification_ =
1435 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1436 [accessibility_notifications addObject:@{
1437 @"notification" : @(notification),
1438 @"argument" : argument ? argument : [NSNull null],
1441 __block
auto bridge =
1442 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1445 std::move(ios_delegate));
1447 flutter::CustomAccessibilityActionUpdates actions;
1448 flutter::SemanticsNodeUpdates nodes;
1450 flutter::SemanticsNode node1;
1452 node1.label =
"node1";
1453 node1.flags.scopesRoute =
true;
1454 node1.flags.namesRoute =
true;
1455 node1.childrenInTraversalOrder = {2};
1456 node1.childrenInHitTestOrder = {2};
1457 nodes[node1.id] = node1;
1458 flutter::SemanticsNode node2;
1460 node2.label =
"node2";
1461 node2.flags.scopesRoute =
true;
1462 node2.flags.namesRoute =
true;
1463 nodes[node2.id] = node2;
1464 flutter::SemanticsNode root_node;
1466 root_node.flags.scopesRoute =
true;
1467 root_node.childrenInTraversalOrder = {1};
1468 root_node.childrenInHitTestOrder = {1};
1469 nodes[root_node.id] = root_node;
1470 bridge->UpdateSemantics(nodes, actions);
1472 XCTAssertEqual([accessibility_notifications count], 1ul);
1473 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node2");
1474 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1475 UIAccessibilityScreenChangedNotification);
1477 flutter::SemanticsNodeUpdates new_nodes;
1479 flutter::SemanticsNode new_node1;
1481 new_node1.label =
"new_node1";
1482 new_node1.childrenInTraversalOrder = {2};
1483 new_node1.childrenInHitTestOrder = {2};
1484 new_nodes[new_node1.id] = new_node1;
1485 flutter::SemanticsNode new_node2;
1487 new_node2.label =
"new_node2";
1488 new_node2.flags.scopesRoute =
true;
1489 new_node2.flags.namesRoute =
true;
1490 new_nodes[new_node2.id] = new_node2;
1491 flutter::SemanticsNode new_root_node;
1493 new_root_node.flags.scopesRoute =
true;
1494 new_root_node.childrenInTraversalOrder = {1};
1495 new_root_node.childrenInHitTestOrder = {1};
1496 new_nodes[new_root_node.id] = new_root_node;
1497 bridge->UpdateSemantics(new_nodes, actions);
1498 XCTAssertEqual([accessibility_notifications count], 2ul);
1499 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1500 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1501 UIAccessibilityScreenChangedNotification);
1504 - (void)testHandleEvent {
1505 flutter::MockDelegate mock_delegate;
1507 flutter::TaskRunners runners(
self.name.UTF8String,
1511 thread_task_runner);
1512 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1514 mock_delegate.settings_.enable_impeller
1520 std::make_shared<fml::SyncSwitch>());
1521 id mockFlutterView = OCMClassMock([
FlutterView class]);
1523 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1525 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1526 [[NSMutableArray alloc] init];
1527 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1528 ios_delegate->on_PostAccessibilityNotification_ =
1529 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1530 [accessibility_notifications addObject:@{
1531 @"notification" : @(notification),
1532 @"argument" : argument ? argument : [NSNull null],
1535 __block
auto bridge =
1536 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1539 std::move(ios_delegate));
1541 NSDictionary<NSString*, id>* annotatedEvent = @{
@"type" :
@"focus",
@"nodeId" : @123};
1543 bridge->HandleEvent(annotatedEvent);
1545 XCTAssertEqual([accessibility_notifications count], 1ul);
1546 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1547 UIAccessibilityLayoutChangedNotification);
1550 - (void)testAccessibilityObjectDidBecomeFocused {
1551 flutter::MockDelegate mock_delegate;
1552 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
1553 auto thread_task_runner = thread->GetTaskRunner();
1554 flutter::TaskRunners runners(
self.name.UTF8String,
1558 thread_task_runner);
1563 OCMStub([flutterViewController
engine]).andReturn(
engine);
1564 OCMStub([
engine binaryMessenger]).andReturn(messenger);
1566 OCMStub([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
1567 binaryMessageHandler:[OCMArg any]])
1568 .andReturn(connection);
1570 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1572 mock_delegate.settings_.enable_impeller
1578 std::make_shared<fml::SyncSwitch>());
1579 fml::AutoResetWaitableEvent latch;
1580 thread_task_runner->PostTask([&] {
1581 platform_view->SetOwnerViewController(flutterViewController);
1583 std::make_unique<flutter::AccessibilityBridge>(nil,
1586 XCTAssertTrue(bridge.get());
1587 OCMVerify([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
1588 binaryMessageHandler:[OCMArg isNotNil]]);
1590 bridge->AccessibilityObjectDidBecomeFocused(123);
1592 NSDictionary<NSString*, id>* annotatedEvent = @{
@"type" :
@"didGainFocus",
@"nodeId" : @123};
1595 OCMVerify([messenger sendOnChannel:
@"flutter/accessibility" message:encodedMessage]);
1600 [engine stopMocking];
1603 - (void)testAnnouncesRouteChangesWhenNoNamesRoute {
1604 flutter::MockDelegate mock_delegate;
1606 flutter::TaskRunners runners(
self.name.UTF8String,
1610 thread_task_runner);
1611 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1613 mock_delegate.settings_.enable_impeller
1619 std::make_shared<fml::SyncSwitch>());
1620 id mockFlutterView = OCMClassMock([
FlutterView class]);
1622 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1624 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1625 [[NSMutableArray alloc] init];
1626 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1627 ios_delegate->on_PostAccessibilityNotification_ =
1628 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1629 [accessibility_notifications addObject:@{
1630 @"notification" : @(notification),
1631 @"argument" : argument ? argument : [NSNull null],
1634 __block
auto bridge =
1635 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1638 std::move(ios_delegate));
1640 flutter::CustomAccessibilityActionUpdates actions;
1641 flutter::SemanticsNodeUpdates nodes;
1643 flutter::SemanticsNode node1;
1645 node1.label =
"node1";
1646 node1.flags.scopesRoute =
true;
1647 node1.flags.namesRoute =
true;
1648 node1.childrenInTraversalOrder = {2, 3};
1649 node1.childrenInHitTestOrder = {2, 3};
1650 nodes[node1.id] = node1;
1651 flutter::SemanticsNode node2;
1653 node2.label =
"node2";
1654 nodes[node2.id] = node2;
1655 flutter::SemanticsNode node3;
1657 node3.label =
"node3";
1658 nodes[node3.id] = node3;
1659 flutter::SemanticsNode root_node;
1661 root_node.childrenInTraversalOrder = {1};
1662 root_node.childrenInHitTestOrder = {1};
1663 nodes[root_node.id] = root_node;
1664 bridge->UpdateSemantics(nodes, actions);
1667 XCTAssertEqual([accessibility_notifications count], 1ul);
1668 id focusObject = accessibility_notifications[0][@"argument"];
1669 XCTAssertTrue([focusObject isKindOfClass:[NSString
class]]);
1670 XCTAssertEqualObjects(focusObject,
@"node1");
1671 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1672 UIAccessibilityScreenChangedNotification);
1675 - (void)testAnnouncesLayoutChangeWithNilIfLastFocusIsRemoved {
1676 flutter::MockDelegate mock_delegate;
1678 flutter::TaskRunners runners(
self.name.UTF8String,
1682 thread_task_runner);
1683 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1685 mock_delegate.settings_.enable_impeller
1691 std::make_shared<fml::SyncSwitch>());
1693 id mockFlutterView = OCMClassMock([
FlutterView class]);
1694 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1696 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1697 [[NSMutableArray alloc] init];
1698 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1699 ios_delegate->on_PostAccessibilityNotification_ =
1700 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1701 [accessibility_notifications addObject:@{
1702 @"notification" : @(notification),
1703 @"argument" : argument ? argument : [NSNull null],
1706 __block
auto bridge =
1707 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1710 std::move(ios_delegate));
1712 flutter::CustomAccessibilityActionUpdates actions;
1713 flutter::SemanticsNodeUpdates first_update;
1715 flutter::SemanticsNode route_node;
1717 route_node.label =
"route";
1718 first_update[route_node.id] = route_node;
1719 flutter::SemanticsNode root_node;
1721 root_node.label =
"root";
1722 root_node.childrenInTraversalOrder = {1};
1723 root_node.childrenInHitTestOrder = {1};
1724 first_update[root_node.id] = root_node;
1725 bridge->UpdateSemantics(first_update, actions);
1727 XCTAssertEqual([accessibility_notifications count], 0ul);
1729 bridge->AccessibilityObjectDidBecomeFocused(1);
1731 flutter::SemanticsNodeUpdates second_update;
1733 flutter::SemanticsNode new_root_node;
1735 new_root_node.label =
"root";
1736 second_update[root_node.id] = new_root_node;
1737 bridge->UpdateSemantics(second_update, actions);
1738 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
1740 XCTAssertEqual([focusObject uid], 0);
1741 XCTAssertEqualObjects([focusObject accessibilityLabel],
@"root");
1742 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1743 UIAccessibilityLayoutChangedNotification);
1746 - (void)testAnnouncesLayoutChangeWithTheSameItemFocused {
1747 flutter::MockDelegate mock_delegate;
1749 flutter::TaskRunners runners(
self.name.UTF8String,
1753 thread_task_runner);
1754 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1756 mock_delegate.settings_.enable_impeller
1762 std::make_shared<fml::SyncSwitch>());
1764 id mockFlutterView = OCMClassMock([
FlutterView class]);
1765 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1767 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1768 [[NSMutableArray alloc] init];
1769 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1770 ios_delegate->on_PostAccessibilityNotification_ =
1771 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1772 [accessibility_notifications addObject:@{
1773 @"notification" : @(notification),
1774 @"argument" : argument ? argument : [NSNull null],
1777 __block
auto bridge =
1778 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1781 std::move(ios_delegate));
1783 flutter::CustomAccessibilityActionUpdates actions;
1784 flutter::SemanticsNodeUpdates first_update;
1786 flutter::SemanticsNode node_one;
1788 node_one.label =
"route1";
1789 first_update[node_one.id] = node_one;
1790 flutter::SemanticsNode node_two;
1792 node_two.label =
"route2";
1793 first_update[node_two.id] = node_two;
1794 flutter::SemanticsNode root_node;
1796 root_node.label =
"root";
1797 root_node.childrenInTraversalOrder = {1, 2};
1798 root_node.childrenInHitTestOrder = {1, 2};
1799 first_update[root_node.id] = root_node;
1800 bridge->UpdateSemantics(first_update, actions);
1802 XCTAssertEqual([accessibility_notifications count], 0ul);
1804 bridge->AccessibilityObjectDidBecomeFocused(1);
1806 flutter::SemanticsNodeUpdates second_update;
1808 flutter::SemanticsNode new_root_node;
1810 new_root_node.label =
"root";
1811 new_root_node.childrenInTraversalOrder = {1};
1812 new_root_node.childrenInHitTestOrder = {1};
1813 second_update[root_node.id] = new_root_node;
1814 bridge->UpdateSemantics(second_update, actions);
1815 id focusObject = accessibility_notifications[0][@"argument"];
1818 XCTAssertEqualObjects(focusObject, [NSNull
null]);
1819 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1820 UIAccessibilityLayoutChangedNotification);
1823 - (void)testAnnouncesLayoutChangeWhenFocusMovedOutside {
1824 flutter::MockDelegate mock_delegate;
1826 flutter::TaskRunners runners(
self.name.UTF8String,
1830 thread_task_runner);
1831 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1833 mock_delegate.settings_.enable_impeller
1839 std::make_shared<fml::SyncSwitch>());
1841 id mockFlutterView = OCMClassMock([
FlutterView class]);
1842 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1844 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1845 [[NSMutableArray alloc] init];
1846 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1847 ios_delegate->on_PostAccessibilityNotification_ =
1848 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1849 [accessibility_notifications addObject:@{
1850 @"notification" : @(notification),
1851 @"argument" : argument ? argument : [NSNull null],
1854 __block
auto bridge =
1855 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1858 std::move(ios_delegate));
1860 flutter::CustomAccessibilityActionUpdates actions;
1861 flutter::SemanticsNodeUpdates first_update;
1863 flutter::SemanticsNode node_one;
1865 node_one.label =
"route1";
1866 first_update[node_one.id] = node_one;
1867 flutter::SemanticsNode node_two;
1869 node_two.label =
"route2";
1870 first_update[node_two.id] = node_two;
1871 flutter::SemanticsNode root_node;
1873 root_node.label =
"root";
1874 root_node.childrenInTraversalOrder = {1, 2};
1875 root_node.childrenInHitTestOrder = {1, 2};
1876 first_update[root_node.id] = root_node;
1877 bridge->UpdateSemantics(first_update, actions);
1879 XCTAssertEqual([accessibility_notifications count], 0ul);
1881 bridge->AccessibilityObjectDidBecomeFocused(1);
1883 bridge->AccessibilityObjectDidLoseFocus(1);
1885 flutter::SemanticsNodeUpdates second_update;
1887 flutter::SemanticsNode new_root_node;
1889 new_root_node.label =
"root";
1890 new_root_node.childrenInTraversalOrder = {1};
1891 new_root_node.childrenInHitTestOrder = {1};
1892 second_update[root_node.id] = new_root_node;
1893 bridge->UpdateSemantics(second_update, actions);
1894 NSNull* focusObject = accessibility_notifications[0][@"argument"];
1897 XCTAssertEqual(focusObject, [NSNull
null]);
1898 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1899 UIAccessibilityLayoutChangedNotification);
1902 - (void)testAnnouncesScrollChangeWithLastFocused {
1903 flutter::MockDelegate mock_delegate;
1905 flutter::TaskRunners runners(
self.name.UTF8String,
1909 thread_task_runner);
1910 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1912 mock_delegate.settings_.enable_impeller
1918 std::make_shared<fml::SyncSwitch>());
1920 id mockFlutterView = OCMClassMock([
FlutterView class]);
1921 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1923 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1924 [[NSMutableArray alloc] init];
1925 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1926 ios_delegate->on_PostAccessibilityNotification_ =
1927 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1928 [accessibility_notifications addObject:@{
1929 @"notification" : @(notification),
1930 @"argument" : argument ? argument : [NSNull null],
1933 __block
auto bridge =
1934 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1937 std::move(ios_delegate));
1939 flutter::CustomAccessibilityActionUpdates actions;
1940 flutter::SemanticsNodeUpdates first_update;
1942 flutter::SemanticsNode node_one;
1944 node_one.label =
"route1";
1945 node_one.scrollPosition = 0.0;
1946 first_update[node_one.id] = node_one;
1947 flutter::SemanticsNode root_node;
1949 root_node.label =
"root";
1950 root_node.childrenInTraversalOrder = {1};
1951 root_node.childrenInHitTestOrder = {1};
1952 first_update[root_node.id] = root_node;
1953 bridge->UpdateSemantics(first_update, actions);
1956 [accessibility_notifications removeAllObjects];
1959 bridge->AccessibilityObjectDidBecomeFocused(1);
1961 flutter::SemanticsNodeUpdates second_update;
1963 flutter::SemanticsNode new_node_one;
1964 new_node_one.id = 1;
1965 new_node_one.label =
"route1";
1966 new_node_one.scrollPosition = 1.0;
1967 second_update[new_node_one.id] = new_node_one;
1968 bridge->UpdateSemantics(second_update, actions);
1969 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
1972 XCTAssertEqual([focusObject uid], 1);
1973 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1974 UIAccessibilityPageScrolledNotification);
1977 - (void)testAnnouncesScrollChangeDoesCallNativeAccessibility {
1978 flutter::MockDelegate mock_delegate;
1980 flutter::TaskRunners runners(
self.name.UTF8String,
1984 thread_task_runner);
1985 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1987 mock_delegate.settings_.enable_impeller
1993 std::make_shared<fml::SyncSwitch>());
1995 id mockFlutterView = OCMClassMock([
FlutterView class]);
1996 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1998 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1999 [[NSMutableArray alloc] init];
2000 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2001 ios_delegate->on_PostAccessibilityNotification_ =
2002 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2003 [accessibility_notifications addObject:@{
2004 @"notification" : @(notification),
2005 @"argument" : argument ? argument : [NSNull null],
2008 __block
auto bridge =
2009 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2012 std::move(ios_delegate));
2014 flutter::CustomAccessibilityActionUpdates actions;
2015 flutter::SemanticsNodeUpdates first_update;
2017 flutter::SemanticsNode node_one;
2019 node_one.label =
"route1";
2020 node_one.flags.hasImplicitScrolling =
true;
2021 node_one.scrollPosition = 0.0;
2022 first_update[node_one.id] = node_one;
2023 flutter::SemanticsNode root_node;
2025 root_node.label =
"root";
2026 root_node.childrenInTraversalOrder = {1};
2027 root_node.childrenInHitTestOrder = {1};
2028 first_update[root_node.id] = root_node;
2029 bridge->UpdateSemantics(first_update, actions);
2032 [accessibility_notifications removeAllObjects];
2035 bridge->AccessibilityObjectDidBecomeFocused(1);
2037 flutter::SemanticsNodeUpdates second_update;
2039 flutter::SemanticsNode new_node_one;
2040 new_node_one.id = 1;
2041 new_node_one.label =
"route1";
2042 new_node_one.flags.hasImplicitScrolling =
true;
2043 new_node_one.scrollPosition = 1.0;
2044 second_update[new_node_one.id] = new_node_one;
2045 bridge->UpdateSemantics(second_update, actions);
2046 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
2050 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
2051 UIAccessibilityPageScrolledNotification);
2054 - (void)testAnnouncesIgnoresRouteChangesWhenModal {
2055 flutter::MockDelegate mock_delegate;
2057 flutter::TaskRunners runners(
self.name.UTF8String,
2061 thread_task_runner);
2062 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2064 mock_delegate.settings_.enable_impeller
2070 std::make_shared<fml::SyncSwitch>());
2071 id mockFlutterView = OCMClassMock([
FlutterView class]);
2073 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2074 std::string label =
"some label";
2076 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2077 [[NSMutableArray alloc] init];
2078 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2079 ios_delegate->on_PostAccessibilityNotification_ =
2080 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2081 [accessibility_notifications addObject:@{
2082 @"notification" : @(notification),
2083 @"argument" : argument ? argument : [NSNull null],
2086 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2087 __block
auto bridge =
2088 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2091 std::move(ios_delegate));
2093 flutter::CustomAccessibilityActionUpdates actions;
2094 flutter::SemanticsNodeUpdates nodes;
2096 flutter::SemanticsNode route_node;
2098 route_node.flags.scopesRoute =
true;
2099 route_node.flags.namesRoute =
true;
2100 route_node.label =
"route";
2101 nodes[route_node.id] = route_node;
2102 flutter::SemanticsNode root_node;
2104 root_node.label = label;
2105 root_node.childrenInTraversalOrder = {1};
2106 root_node.childrenInHitTestOrder = {1};
2107 nodes[root_node.id] = root_node;
2108 bridge->UpdateSemantics(nodes, actions);
2110 XCTAssertEqual([accessibility_notifications count], 0ul);
2113 - (void)testAnnouncesIgnoresLayoutChangeWhenModal {
2114 flutter::MockDelegate mock_delegate;
2116 flutter::TaskRunners runners(
self.name.UTF8String,
2120 thread_task_runner);
2121 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2123 mock_delegate.settings_.enable_impeller
2129 std::make_shared<fml::SyncSwitch>());
2130 id mockFlutterView = OCMClassMock([
FlutterView class]);
2132 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2134 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2135 [[NSMutableArray alloc] init];
2136 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2137 ios_delegate->on_PostAccessibilityNotification_ =
2138 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2139 [accessibility_notifications addObject:@{
2140 @"notification" : @(notification),
2141 @"argument" : argument ? argument : [NSNull null],
2144 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2145 __block
auto bridge =
2146 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2149 std::move(ios_delegate));
2151 flutter::CustomAccessibilityActionUpdates actions;
2152 flutter::SemanticsNodeUpdates nodes;
2154 flutter::SemanticsNode child_node;
2156 child_node.label =
"child_node";
2157 nodes[child_node.id] = child_node;
2158 flutter::SemanticsNode root_node;
2160 root_node.label =
"root";
2161 root_node.childrenInTraversalOrder = {1};
2162 root_node.childrenInHitTestOrder = {1};
2163 nodes[root_node.id] = root_node;
2164 bridge->UpdateSemantics(nodes, actions);
2167 flutter::SemanticsNodeUpdates new_nodes;
2168 flutter::SemanticsNode new_root_node;
2170 new_root_node.label =
"root";
2171 new_nodes[new_root_node.id] = new_root_node;
2172 bridge->UpdateSemantics(new_nodes, actions);
2174 XCTAssertEqual([accessibility_notifications count], 0ul);
2177 - (void)testAnnouncesIgnoresScrollChangeWhenModal {
2178 flutter::MockDelegate mock_delegate;
2180 flutter::TaskRunners runners(
self.name.UTF8String,
2184 thread_task_runner);
2185 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2187 mock_delegate.settings_.enable_impeller
2193 std::make_shared<fml::SyncSwitch>());
2194 id mockFlutterView = OCMClassMock([
FlutterView class]);
2196 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2198 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2199 [[NSMutableArray alloc] init];
2200 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2201 ios_delegate->on_PostAccessibilityNotification_ =
2202 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2203 [accessibility_notifications addObject:@{
2204 @"notification" : @(notification),
2205 @"argument" : argument ? argument : [NSNull null],
2208 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2209 __block
auto bridge =
2210 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2213 std::move(ios_delegate));
2215 flutter::CustomAccessibilityActionUpdates actions;
2216 flutter::SemanticsNodeUpdates nodes;
2218 flutter::SemanticsNode root_node;
2220 root_node.label =
"root";
2221 root_node.scrollPosition = 1;
2222 nodes[root_node.id] = root_node;
2223 bridge->UpdateSemantics(nodes, actions);
2226 flutter::SemanticsNodeUpdates new_nodes;
2227 flutter::SemanticsNode new_root_node;
2229 new_root_node.label =
"root";
2230 new_root_node.scrollPosition = 2;
2231 new_nodes[new_root_node.id] = new_root_node;
2232 bridge->UpdateSemantics(new_nodes, actions);
2234 XCTAssertEqual([accessibility_notifications count], 0ul);
2237 - (void)testAccessibilityMessageAfterDeletion {
2238 flutter::MockDelegate mock_delegate;
2239 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2240 auto thread_task_runner = thread->GetTaskRunner();
2241 flutter::TaskRunners runners(
self.name.UTF8String,
2245 thread_task_runner);
2250 OCMStub([flutterViewController
engine]).andReturn(
engine);
2251 OCMStub([
engine binaryMessenger]).andReturn(messenger);
2253 OCMStub([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
2254 binaryMessageHandler:[OCMArg any]])
2255 .andReturn(connection);
2257 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2259 mock_delegate.settings_.enable_impeller
2265 std::make_shared<fml::SyncSwitch>());
2266 fml::AutoResetWaitableEvent latch;
2267 thread_task_runner->PostTask([&] {
2268 platform_view->SetOwnerViewController(flutterViewController);
2270 std::make_unique<flutter::AccessibilityBridge>(nil,
2273 XCTAssertTrue(bridge.get());
2274 OCMVerify([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
2275 binaryMessageHandler:[OCMArg isNotNil]]);
2280 OCMVerify([messenger cleanUpConnection:connection]);
2281 [engine stopMocking];
2284 - (void)testFlutterSemanticsScrollViewManagedObjectLifecycleCorrectly {
2285 flutter::MockDelegate mock_delegate;
2287 flutter::TaskRunners runners(
self.name.UTF8String,
2291 thread_task_runner);
2292 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2294 mock_delegate.settings_.enable_impeller
2300 std::make_shared<fml::SyncSwitch>());
2301 id mockFlutterView = OCMClassMock([
FlutterView class]);
2303 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2305 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2306 __block
auto bridge =
2307 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2310 std::move(ios_delegate));
2319 XCTAssertTrue(flutterSemanticsScrollView);
2322 XCTAssertFalse([flutterSemanticsScrollView isAccessibilityElement]);
2325 - (void)testPlatformViewDestructorDoesNotCallSemanticsAPIs {
2326 class TestDelegate :
public flutter::MockDelegate {
2328 void OnPlatformViewSetSemanticsEnabled(
bool enabled)
override { set_semantics_enabled_calls++; }
2329 int set_semantics_enabled_calls = 0;
2332 TestDelegate test_delegate;
2333 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2334 auto thread_task_runner = thread->GetTaskRunner();
2335 flutter::TaskRunners runners(
self.name.UTF8String,
2339 thread_task_runner);
2341 fml::AutoResetWaitableEvent latch;
2342 thread_task_runner->PostTask([&] {
2343 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2345 test_delegate.settings_.enable_impeller
2351 std::make_shared<fml::SyncSwitch>());
2359 OCMStub([mockFlutterViewController platformViewsController])
2360 .andReturn(flutterPlatformViewsController);
2361 platform_view->SetOwnerViewController(mockFlutterViewController);
2364 XCTAssertNotEqual(test_delegate.set_semantics_enabled_calls, 0);
2367 test_delegate.set_semantics_enabled_calls = 0;
2369 XCTAssertEqual(test_delegate.set_semantics_enabled_calls, 0);
2376 - (void)testResetsAccessibilityElementsOnHotRestart {
2377 flutter::MockDelegate mock_delegate;
2378 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2379 auto thread_task_runner = thread->GetTaskRunner();
2380 flutter::TaskRunners runners(
self.name.UTF8String,
2384 thread_task_runner);
2385 id mockFlutterView = OCMClassMock([
FlutterView class]);
2387 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
2389 fml::AutoResetWaitableEvent latch;
2390 thread_task_runner->PostTask([&] {
2391 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2393 mock_delegate.settings_.enable_impeller
2399 std::make_shared<fml::SyncSwitch>());
2401 platform_view->SetOwnerViewController(mockFlutterViewController);
2405 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg isNil]]);
2407 OCMVerifyAll(mockFlutterView);
2414 - (void)testWeakViewController {
2415 flutter::MockDelegate mock_delegate;
2417 flutter::TaskRunners runners(
self.name.UTF8String,
2421 thread_task_runner);
2422 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2424 mock_delegate.settings_.enable_impeller
2430 std::make_shared<fml::SyncSwitch>());
2432 std::unique_ptr<flutter::AccessibilityBridge> bridge;
2434 id mockFlutterView = OCMClassMock([
FlutterView class]);
2436 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
2437 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2439 bridge = std::make_unique<flutter::AccessibilityBridge>(
2440 mockFlutterViewController,
2443 XCTAssertTrue(bridge.get());
2444 XCTAssertNotNil(bridge->view());
2446 XCTAssertNil(bridge->view());
int64_t FlutterBinaryMessengerConnection
void(^ FlutterResult)(id _Nullable result)
constexpr int32_t kRootNodeId
static __weak MockPlatformView * gMockPlatformView
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
SemanticsObject * semanticsObject
fml::RefPtr< fml::TaskRunner > CreateNewThread(const std::string &name)
instancetype sharedInstance()