5 #import <OCMock/OCMock.h>
6 #import <XCTest/XCTest.h>
8 #import "flutter/fml/thread.h"
26 - (instancetype)init {
41 @property(nonatomic, strong) UIView* view;
46 - (instancetype)init {
47 if (
self = [super init]) {
59 - (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
60 viewIdentifier:(int64_t)viewId
61 arguments:(
id _Nullable)args {
69 class MockDelegate :
public PlatformView::Delegate {
71 void OnPlatformViewCreated(std::unique_ptr<Surface> surface)
override {}
72 void OnPlatformViewDestroyed()
override {}
73 void OnPlatformViewScheduleFrame()
override {}
74 void OnPlatformViewAddView(int64_t view_id,
75 const ViewportMetrics& viewport_metrics,
76 AddViewCallback callback)
override {}
77 void OnPlatformViewRemoveView(int64_t view_id, RemoveViewCallback callback)
override {}
78 void OnPlatformViewSendViewFocusEvent(
const ViewFocusEvent& event)
override {};
79 void OnPlatformViewSetNextFrameCallback(
const fml::closure& closure)
override {}
80 void OnPlatformViewSetViewportMetrics(int64_t view_id,
const ViewportMetrics& metrics)
override {}
81 const flutter::Settings& OnPlatformViewGetSettings()
const override {
return settings_; }
82 void OnPlatformViewDispatchPlatformMessage(std::unique_ptr<PlatformMessage> message)
override {}
83 void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet)
override {
85 void OnPlatformViewDispatchSemanticsAction(int64_t view_id,
87 SemanticsAction action,
88 fml::MallocMapping args)
override {}
89 void OnPlatformViewSetSemanticsEnabled(
bool enabled)
override {}
90 void OnPlatformViewSetAccessibilityFeatures(int32_t flags)
override {}
91 void OnPlatformViewRegisterTexture(std::shared_ptr<Texture> texture)
override {}
92 void OnPlatformViewUnregisterTexture(int64_t
texture_id)
override {}
93 void OnPlatformViewMarkTextureFrameAvailable(int64_t
texture_id)
override {}
95 void LoadDartDeferredLibrary(intptr_t loading_unit_id,
96 std::unique_ptr<const fml::Mapping> snapshot_data,
97 std::unique_ptr<const fml::Mapping> snapshot_instructions)
override {
99 void LoadDartDeferredLibraryError(intptr_t loading_unit_id,
100 const std::string error_message,
101 bool transient)
override {}
102 void UpdateAssetResolverByType(std::unique_ptr<flutter::AssetResolver> updated_asset_resolver,
103 flutter::AssetResolver::AssetResolverType type)
override {}
108 class MockIosDelegate :
public AccessibilityBridge::IosDelegate {
110 bool IsFlutterViewControllerPresentingModalViewController(
112 return result_IsFlutterViewControllerPresentingModalViewController_;
115 void PostAccessibilityNotification(UIAccessibilityNotifications notification,
116 id argument)
override {
117 if (on_PostAccessibilityNotification_) {
118 on_PostAccessibilityNotification_(notification, argument);
121 std::function<void(UIAccessibilityNotifications,
id)> on_PostAccessibilityNotification_;
122 bool result_IsFlutterViewControllerPresentingModalViewController_ =
false;
128 fml::RefPtr<fml::TaskRunner>
CreateNewThread(
const std::string& name) {
129 auto thread = std::make_unique<fml::Thread>(name);
130 auto runner = thread->GetTaskRunner();
141 flutter::MockDelegate mock_delegate;
143 flutter::TaskRunners runners(
self.name.UTF8String,
148 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
150 mock_delegate.settings_.enable_impeller
156 std::make_shared<fml::SyncSwitch>());
158 std::make_unique<flutter::AccessibilityBridge>(nil,
161 XCTAssertTrue(bridge.get());
164 - (void)testUpdateSemanticsEmpty {
165 flutter::MockDelegate mock_delegate;
167 flutter::TaskRunners runners(
self.name.UTF8String,
172 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
174 mock_delegate.settings_.enable_impeller
180 std::make_shared<fml::SyncSwitch>());
181 id mockFlutterView = OCMClassMock([
FlutterView class]);
183 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
184 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg isNil]]);
186 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
189 flutter::SemanticsNodeUpdates nodes;
190 flutter::CustomAccessibilityActionUpdates actions;
191 bridge->UpdateSemantics(nodes, actions);
192 OCMVerifyAll(mockFlutterView);
195 - (void)testUpdateSemanticsOneNode {
196 flutter::MockDelegate mock_delegate;
198 flutter::TaskRunners runners(
self.name.UTF8String,
203 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
205 mock_delegate.settings_.enable_impeller
211 std::make_shared<fml::SyncSwitch>());
212 id mockFlutterView = OCMClassMock([
FlutterView class]);
214 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
215 std::string label =
"some label";
217 __block
auto bridge =
218 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
222 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg checkWithBlock:^BOOL(NSArray* value) {
223 if ([value count] != 1) {
229 object.bridge.get() == bridge.get() &&
230 object.node.label == label;
234 flutter::SemanticsNodeUpdates nodes;
235 flutter::SemanticsNode semantics_node;
237 semantics_node.label = label;
238 nodes[kRootNodeId] = semantics_node;
239 flutter::CustomAccessibilityActionUpdates actions;
240 bridge->UpdateSemantics(nodes, actions);
241 OCMVerifyAll(mockFlutterView);
244 - (void)testIsVoiceOverRunning {
245 flutter::MockDelegate mock_delegate;
247 flutter::TaskRunners runners(
self.name.UTF8String,
252 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
254 mock_delegate.settings_.enable_impeller
260 std::make_shared<fml::SyncSwitch>());
261 id mockFlutterView = OCMClassMock([
FlutterView class]);
263 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
264 OCMStub([mockFlutterViewController isVoiceOverRunning]).andReturn(YES);
266 __block
auto bridge =
267 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
271 XCTAssertTrue(bridge->isVoiceOverRunning());
274 - (void)testSemanticsDeallocated {
276 flutter::MockDelegate mock_delegate;
278 flutter::TaskRunners runners(
self.name.UTF8String,
286 flutterPlatformViewsController.
taskRunner = thread_task_runner;
287 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
289 mock_delegate.settings_.enable_impeller
292 flutterPlatformViewsController,
295 std::make_shared<fml::SyncSwitch>());
296 id mockFlutterView = OCMClassMock([
FlutterView class]);
298 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
299 std::string label =
"some label";
300 flutterPlatformViewsController.
flutterView = mockFlutterView;
303 [flutterPlatformViewsController
305 withId:@"MockFlutterPlatformView"
309 [flutterPlatformViewsController
313 @"viewType" : @"MockFlutterPlatformView"
317 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
318 mockFlutterViewController,
320 flutterPlatformViewsController);
322 flutter::SemanticsNodeUpdates nodes;
323 flutter::SemanticsNode semantics_node;
324 semantics_node.id = 2;
325 semantics_node.platformViewId = 2;
326 semantics_node.label = label;
327 nodes[kRootNodeId] = semantics_node;
328 flutter::CustomAccessibilityActionUpdates actions;
329 bridge->UpdateSemantics(nodes, actions);
331 [flutterPlatformViewsController
reset];
336 - (void)testSemanticsDeallocatedWithoutLoadingView {
341 flutter::MockDelegate mock_delegate;
343 flutter::TaskRunners runners(
self.name.UTF8String,
351 flutterPlatformViewsController.
taskRunner = thread_task_runner;
352 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
354 mock_delegate.settings_.enable_impeller
357 flutterPlatformViewsController,
360 std::make_shared<fml::SyncSwitch>());
363 [flutterPlatformViewsController
365 withId:@"MockFlutterPlatformView"
369 [flutterPlatformViewsController
373 @"viewType" : @"MockFlutterPlatformView"
377 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
378 flutterViewController,
380 flutterPlatformViewsController);
383 [flutterPlatformViewsController
reset];
387 XCTAssertNil(flutterViewController.viewIfLoaded);
388 [flutterViewController deregisterNotifications];
391 - (void)testReplacedSemanticsDoesNotCleanupChildren {
392 flutter::MockDelegate mock_delegate;
394 flutter::TaskRunners runners(
self.name.UTF8String,
402 flutterPlatformViewsController.
taskRunner = thread_task_runner;
403 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
405 mock_delegate.settings_.enable_impeller
408 flutterPlatformViewsController,
411 std::make_shared<fml::SyncSwitch>());
417 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
418 std::string label =
"some label";
419 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
420 mockFlutterViewController,
422 flutterPlatformViewsController);
424 flutter::SemanticsNodeUpdates nodes;
425 flutter::SemanticsNode parent;
427 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
428 parent.label =
"label";
429 parent.value =
"value";
430 parent.hint =
"hint";
432 flutter::SemanticsNode node;
434 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
435 node.label =
"label";
436 node.value =
"value";
438 node.scrollExtentMax = 100.0;
439 node.scrollPosition = 0.0;
440 parent.childrenInTraversalOrder.push_back(1);
441 parent.childrenInHitTestOrder.push_back(1);
443 flutter::SemanticsNode child;
445 child.rect = SkRect::MakeXYWH(0, 0, 100, 200);
446 child.label =
"label";
447 child.value =
"value";
449 node.childrenInTraversalOrder.push_back(2);
450 node.childrenInHitTestOrder.push_back(2);
455 flutter::CustomAccessibilityActionUpdates actions;
456 bridge->UpdateSemantics(nodes, actions);
459 flutter::SemanticsNodeUpdates new_nodes;
460 flutter::SemanticsNode new_node;
462 new_node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
463 new_node.flags.hasImplicitScrolling =
true;
464 new_node.actions = flutter::kHorizontalScrollSemanticsActions;
465 new_node.label =
"label";
466 new_node.value =
"value";
467 new_node.hint =
"hint";
468 new_node.scrollExtentMax = 100.0;
469 new_node.scrollPosition = 0.0;
470 new_node.childrenInTraversalOrder.push_back(2);
471 new_node.childrenInHitTestOrder.push_back(2);
473 new_nodes[1] = new_node;
474 bridge->UpdateSemantics(new_nodes, actions);
478 id rootContainer = flutterView.accessibilityElements[0];
479 XCTAssertTrue([rootContainer accessibilityElementCount] ==
481 id scrollableContainer = [rootContainer accessibilityElementAtIndex:1];
482 XCTAssertTrue([scrollableContainer accessibilityElementCount] ==
484 id child = [scrollableContainer accessibilityElementAtIndex:1];
486 XCTAssertNotNil([child accessibilityContainer]);
489 - (void)testScrollableSemanticsDeallocated {
490 flutter::MockDelegate mock_delegate;
492 flutter::TaskRunners runners(
self.name.UTF8String,
500 flutterPlatformViewsController.
taskRunner = thread_task_runner;
501 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
503 mock_delegate.settings_.enable_impeller
506 flutterPlatformViewsController,
509 std::make_shared<fml::SyncSwitch>());
515 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
516 std::string label =
"some label";
518 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
519 mockFlutterViewController,
521 flutterPlatformViewsController);
523 flutter::SemanticsNodeUpdates nodes;
524 flutter::SemanticsNode parent;
526 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
527 parent.label =
"label";
528 parent.value =
"value";
529 parent.hint =
"hint";
531 flutter::SemanticsNode node;
533 node.flags.hasImplicitScrolling =
true;
534 node.actions = flutter::kHorizontalScrollSemanticsActions;
535 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
536 node.label =
"label";
537 node.value =
"value";
539 node.scrollExtentMax = 100.0;
540 node.scrollPosition = 0.0;
541 parent.childrenInTraversalOrder.push_back(1);
542 parent.childrenInHitTestOrder.push_back(1);
545 flutter::CustomAccessibilityActionUpdates actions;
546 bridge->UpdateSemantics(nodes, actions);
547 XCTAssertTrue([flutterView.subviews count] == 1);
549 XCTAssertTrue([flutterView.subviews[0].accessibilityLabel isEqualToString:
@"label"]);
552 flutter::SemanticsNodeUpdates new_nodes;
553 flutter::SemanticsNode new_parent;
555 new_parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
556 new_parent.label =
"label";
557 new_parent.value =
"value";
558 new_parent.hint =
"hint";
559 new_nodes[0] = new_parent;
560 bridge->UpdateSemantics(new_nodes, actions);
562 XCTAssertTrue([flutterView.subviews count] == 0);
565 - (void)testBridgeReplacesSemanticsNode {
566 flutter::MockDelegate mock_delegate;
568 flutter::TaskRunners runners(
self.name.UTF8String,
576 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
578 mock_delegate.settings_.enable_impeller
581 flutterPlatformViewsController,
584 std::make_shared<fml::SyncSwitch>());
590 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
591 std::string label =
"some label";
593 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
594 mockFlutterViewController,
596 flutterPlatformViewsController);
598 flutter::SemanticsNodeUpdates nodes;
599 flutter::SemanticsNode parent;
601 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
602 parent.label =
"label";
603 parent.value =
"value";
604 parent.hint =
"hint";
606 flutter::SemanticsNode node;
608 node.flags.hasImplicitScrolling =
true;
609 node.actions = flutter::kHorizontalScrollSemanticsActions;
610 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
611 node.label =
"label";
612 node.value =
"value";
614 node.scrollExtentMax = 100.0;
615 node.scrollPosition = 0.0;
616 parent.childrenInTraversalOrder.push_back(1);
617 parent.childrenInHitTestOrder.push_back(1);
620 flutter::CustomAccessibilityActionUpdates actions;
621 bridge->UpdateSemantics(nodes, actions);
622 XCTAssertTrue([flutterView.subviews count] == 1);
624 XCTAssertTrue([flutterView.subviews[0].accessibilityLabel isEqualToString:
@"label"]);
627 flutter::SemanticsNodeUpdates new_nodes;
628 flutter::SemanticsNode new_node;
630 new_node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
631 new_node.label =
"label";
632 new_node.value =
"value";
633 new_node.hint =
"hint";
634 new_node.scrollExtentMax = 100.0;
635 new_node.scrollPosition = 0.0;
636 new_nodes[1] = new_node;
637 bridge->UpdateSemantics(new_nodes, actions);
639 XCTAssertTrue([flutterView.subviews count] == 0);
642 - (void)testAnnouncesRouteChanges {
643 flutter::MockDelegate mock_delegate;
645 flutter::TaskRunners runners(
self.name.UTF8String,
650 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
652 mock_delegate.settings_.enable_impeller
658 std::make_shared<fml::SyncSwitch>());
659 id mockFlutterView = OCMClassMock([
FlutterView class]);
661 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
663 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
664 [[NSMutableArray alloc] init];
665 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
666 ios_delegate->on_PostAccessibilityNotification_ =
667 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
668 [accessibility_notifications addObject:@{
669 @"notification" : @(notification),
670 @"argument" : argument ? argument : [NSNull null],
673 __block
auto bridge =
674 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
677 std::move(ios_delegate));
679 flutter::CustomAccessibilityActionUpdates actions;
680 flutter::SemanticsNodeUpdates nodes;
682 flutter::SemanticsNode node1;
684 node1.label =
"node1";
685 node1.flags.scopesRoute =
true;
686 node1.childrenInTraversalOrder = {2, 3};
687 node1.childrenInHitTestOrder = {2, 3};
688 nodes[node1.id] = node1;
689 flutter::SemanticsNode node2;
691 node2.label =
"node2";
692 nodes[node2.id] = node2;
693 flutter::SemanticsNode node3;
695 node3.flags.namesRoute =
true;
696 node3.label =
"node3";
697 nodes[node3.id] = node3;
698 flutter::SemanticsNode root_node;
700 root_node.flags.scopesRoute =
true;
701 root_node.childrenInTraversalOrder = {1};
702 root_node.childrenInHitTestOrder = {1};
703 nodes[root_node.id] = root_node;
704 bridge->UpdateSemantics(nodes, actions);
706 XCTAssertEqual([accessibility_notifications count], 1ul);
707 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node3");
708 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
709 UIAccessibilityScreenChangedNotification);
712 - (void)testRadioButtonIsNotSwitchButton {
713 flutter::MockDelegate mock_delegate;
715 flutter::TaskRunners runners(
self.name.UTF8String,
720 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
722 mock_delegate.settings_.enable_impeller
728 std::make_shared<fml::SyncSwitch>());
734 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
735 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
736 __block
auto bridge =
737 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
740 std::move(ios_delegate));
742 flutter::CustomAccessibilityActionUpdates actions;
743 flutter::SemanticsNodeUpdates nodes;
745 flutter::SemanticsNode root_node;
747 root_node.flags.isInMutuallyExclusiveGroup =
true;
748 root_node.flags.isEnabled = flutter::SemanticsTristate::kTrue;
749 root_node.flags.isChecked = flutter::SemanticsCheckState::kFalse;
750 nodes[root_node.id] = root_node;
751 bridge->UpdateSemantics(nodes, actions);
756 XCTAssertTrue((rootNode.accessibilityTraits & UIAccessibilityTraitButton) > 0);
757 XCTAssertNil(rootNode.accessibilityValue);
760 - (void)testSemanticObjectWithNoAccessibilityFlagNotMarkedAsResponsiveToUserInteraction {
761 flutter::MockDelegate mock_delegate;
763 flutter::TaskRunners runners(
self.name.UTF8String,
768 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
770 mock_delegate.settings_.enable_impeller
776 std::make_shared<fml::SyncSwitch>());
782 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
783 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
784 __block
auto bridge =
785 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
788 std::move(ios_delegate));
790 flutter::CustomAccessibilityActionUpdates actions;
791 flutter::SemanticsNodeUpdates nodes;
793 flutter::SemanticsNode root_node;
796 nodes[root_node.id] = root_node;
797 bridge->UpdateSemantics(nodes, actions);
802 XCTAssertFalse(rootNode.accessibilityRespondsToUserInteraction);
805 - (void)testSemanticObjectWithAccessibilityFlagsMarkedAsResponsiveToUserInteraction {
806 flutter::MockDelegate mock_delegate;
808 flutter::TaskRunners runners(
self.name.UTF8String,
813 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
815 mock_delegate.settings_.enable_impeller
821 std::make_shared<fml::SyncSwitch>());
827 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
828 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
829 __block
auto bridge =
830 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
833 std::move(ios_delegate));
835 flutter::CustomAccessibilityActionUpdates actions;
836 flutter::SemanticsNodeUpdates nodes;
838 flutter::SemanticsNode root_node;
840 root_node.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
842 nodes[root_node.id] = root_node;
843 bridge->UpdateSemantics(nodes, actions);
848 XCTAssertTrue(rootNode.accessibilityRespondsToUserInteraction);
853 - (void)testLabeledParentAndChildNotInteractive {
854 flutter::MockDelegate mock_delegate;
856 flutter::TaskRunners runners(
self.name.UTF8String,
864 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
866 mock_delegate.settings_.enable_impeller
869 flutterPlatformViewsController,
872 std::make_shared<fml::SyncSwitch>());
878 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
881 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
882 mockFlutterViewController,
884 flutterPlatformViewsController);
886 flutter::SemanticsNodeUpdates nodes;
888 flutter::SemanticsNode parent;
890 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
891 parent.label =
"parent_label";
893 flutter::SemanticsNode node;
895 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
896 node.label =
"child_label";
898 parent.childrenInTraversalOrder.push_back(1);
899 parent.childrenInHitTestOrder.push_back(1);
902 flutter::CustomAccessibilityActionUpdates actions;
903 bridge->UpdateSemantics(nodes, actions);
909 XCTAssertTrue([parentNode.accessibilityLabel isEqualToString:
@"parent_label"]);
910 XCTAssertTrue([childNode.accessibilityLabel isEqualToString:
@"child_label"]);
911 XCTAssertFalse(parentNode.accessibilityRespondsToUserInteraction);
912 XCTAssertFalse(childNode.accessibilityRespondsToUserInteraction);
916 - (void)testLayoutChangeWithNonAccessibilityElement {
917 flutter::MockDelegate mock_delegate;
919 flutter::TaskRunners runners(
self.name.UTF8String,
924 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
926 mock_delegate.settings_.enable_impeller
932 std::make_shared<fml::SyncSwitch>());
933 id mockFlutterView = OCMClassMock([
FlutterView class]);
935 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
937 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
938 [[NSMutableArray alloc] init];
939 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
940 ios_delegate->on_PostAccessibilityNotification_ =
941 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
942 [accessibility_notifications addObject:@{
943 @"notification" : @(notification),
944 @"argument" : argument ? argument : [NSNull null],
947 __block
auto bridge =
948 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
951 std::move(ios_delegate));
953 flutter::CustomAccessibilityActionUpdates actions;
954 flutter::SemanticsNodeUpdates nodes;
956 flutter::SemanticsNode node1;
958 node1.label =
"node1";
959 node1.childrenInTraversalOrder = {2, 3};
960 node1.childrenInHitTestOrder = {2, 3};
961 nodes[node1.id] = node1;
962 flutter::SemanticsNode node2;
964 node2.label =
"node2";
965 nodes[node2.id] = node2;
966 flutter::SemanticsNode node3;
968 node3.label =
"node3";
969 nodes[node3.id] = node3;
970 flutter::SemanticsNode root_node;
972 root_node.label =
"root";
973 root_node.childrenInTraversalOrder = {1};
974 root_node.childrenInHitTestOrder = {1};
975 nodes[root_node.id] = root_node;
976 bridge->UpdateSemantics(nodes, actions);
979 bridge->AccessibilityObjectDidBecomeFocused(1);
984 flutter::CustomAccessibilityActionUpdates new_actions;
985 flutter::SemanticsNodeUpdates new_nodes;
987 flutter::SemanticsNode new_node1;
989 new_node1.childrenInTraversalOrder = {2};
990 new_node1.childrenInHitTestOrder = {2};
991 new_nodes[new_node1.id] = new_node1;
992 bridge->UpdateSemantics(new_nodes, new_actions);
994 XCTAssertEqual([accessibility_notifications count], 1ul);
995 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
997 XCTAssertEqual([focusObject uid], 2);
998 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
999 UIAccessibilityLayoutChangedNotification);
1002 - (void)testLayoutChangeDoesCallNativeAccessibility {
1003 flutter::MockDelegate mock_delegate;
1005 flutter::TaskRunners runners(
self.name.UTF8String,
1009 thread_task_runner);
1010 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1012 mock_delegate.settings_.enable_impeller
1018 std::make_shared<fml::SyncSwitch>());
1019 id mockFlutterView = OCMClassMock([
FlutterView class]);
1021 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1023 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1024 [[NSMutableArray alloc] init];
1025 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1026 ios_delegate->on_PostAccessibilityNotification_ =
1027 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1028 [accessibility_notifications addObject:@{
1029 @"notification" : @(notification),
1030 @"argument" : argument ? argument : [NSNull null],
1033 __block
auto bridge =
1034 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1037 std::move(ios_delegate));
1039 flutter::CustomAccessibilityActionUpdates actions;
1040 flutter::SemanticsNodeUpdates nodes;
1042 flutter::SemanticsNode node1;
1044 node1.label =
"node1";
1045 nodes[node1.id] = node1;
1046 flutter::SemanticsNode root_node;
1048 root_node.label =
"root";
1049 root_node.flags.hasImplicitScrolling =
true;
1050 root_node.childrenInTraversalOrder = {1};
1051 root_node.childrenInHitTestOrder = {1};
1052 nodes[root_node.id] = root_node;
1053 bridge->UpdateSemantics(nodes, actions);
1056 bridge->AccessibilityObjectDidBecomeFocused(0);
1059 flutter::CustomAccessibilityActionUpdates new_actions;
1060 flutter::SemanticsNodeUpdates new_nodes;
1062 flutter::SemanticsNode new_root_node;
1064 new_root_node.label =
"root";
1065 new_root_node.flags.hasImplicitScrolling =
true;
1066 new_nodes[new_root_node.id] = new_root_node;
1067 bridge->UpdateSemantics(new_nodes, new_actions);
1069 XCTAssertEqual([accessibility_notifications count], 1ul);
1070 id focusObject = accessibility_notifications[0][@"argument"];
1074 XCTAssertEqualObjects(focusObject, [NSNull
null]);
1075 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1076 UIAccessibilityLayoutChangedNotification);
1079 - (void)testLayoutChangeDoesCallNativeAccessibilityWhenFocusChanged {
1080 flutter::MockDelegate mock_delegate;
1082 flutter::TaskRunners runners(
self.name.UTF8String,
1086 thread_task_runner);
1087 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1089 mock_delegate.settings_.enable_impeller
1095 std::make_shared<fml::SyncSwitch>());
1096 id mockFlutterView = OCMClassMock([
FlutterView class]);
1098 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1100 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1101 [[NSMutableArray alloc] init];
1102 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1103 ios_delegate->on_PostAccessibilityNotification_ =
1104 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1105 [accessibility_notifications addObject:@{
1106 @"notification" : @(notification),
1107 @"argument" : argument ? argument : [NSNull null],
1110 __block
auto bridge =
1111 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1114 std::move(ios_delegate));
1116 flutter::CustomAccessibilityActionUpdates actions;
1117 flutter::SemanticsNodeUpdates nodes;
1119 flutter::SemanticsNode node1;
1121 node1.label =
"node1";
1122 nodes[node1.id] = node1;
1123 flutter::SemanticsNode root_node;
1125 root_node.label =
"root";
1126 root_node.flags.hasImplicitScrolling =
true;
1127 root_node.childrenInTraversalOrder = {1};
1128 root_node.childrenInHitTestOrder = {1};
1129 nodes[root_node.id] = root_node;
1130 bridge->UpdateSemantics(nodes, actions);
1133 bridge->AccessibilityObjectDidBecomeFocused(1);
1136 flutter::CustomAccessibilityActionUpdates new_actions;
1137 flutter::SemanticsNodeUpdates new_nodes;
1139 flutter::SemanticsNode new_root_node;
1141 new_root_node.label =
"root";
1142 new_root_node.flags.hasImplicitScrolling =
true;
1143 new_nodes[new_root_node.id] = new_root_node;
1144 bridge->UpdateSemantics(new_nodes, new_actions);
1146 XCTAssertEqual([accessibility_notifications count], 1ul);
1147 SemanticsObject* focusObject2 = accessibility_notifications[0][@"argument"];
1151 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1152 UIAccessibilityLayoutChangedNotification);
1155 - (void)testScrollableSemanticsContainerReturnsCorrectChildren {
1156 flutter::MockDelegate mock_delegate;
1158 flutter::TaskRunners runners(
self.name.UTF8String,
1162 thread_task_runner);
1163 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1165 mock_delegate.settings_.enable_impeller
1171 std::make_shared<fml::SyncSwitch>());
1172 id mockFlutterView = OCMClassMock([
FlutterView class]);
1174 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1176 OCMExpect([mockFlutterView
1177 setAccessibilityElements:[OCMArg checkWithBlock:^BOOL(NSArray* value) {
1178 if ([value count] != 1) {
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));
1196 flutter::CustomAccessibilityActionUpdates actions;
1197 flutter::SemanticsNodeUpdates nodes;
1199 flutter::SemanticsNode node1;
1201 node1.label =
"node1";
1202 node1.flags.hasImplicitScrolling =
true;
1203 nodes[node1.id] = node1;
1204 flutter::SemanticsNode root_node;
1206 root_node.label =
"root";
1207 root_node.childrenInTraversalOrder = {1};
1208 root_node.childrenInHitTestOrder = {1};
1209 nodes[root_node.id] = root_node;
1210 bridge->UpdateSemantics(nodes, actions);
1211 OCMVerifyAll(mockFlutterView);
1214 - (void)testAnnouncesRouteChangesAndLayoutChangeInOneUpdate {
1215 flutter::MockDelegate mock_delegate;
1217 flutter::TaskRunners runners(
self.name.UTF8String,
1221 thread_task_runner);
1222 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1224 mock_delegate.settings_.enable_impeller
1230 std::make_shared<fml::SyncSwitch>());
1231 id mockFlutterView = OCMClassMock([
FlutterView class]);
1233 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1235 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1236 [[NSMutableArray alloc] init];
1237 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1238 ios_delegate->on_PostAccessibilityNotification_ =
1239 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1240 [accessibility_notifications addObject:@{
1241 @"notification" : @(notification),
1242 @"argument" : argument ? argument : [NSNull null],
1245 __block
auto bridge =
1246 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1249 std::move(ios_delegate));
1251 flutter::CustomAccessibilityActionUpdates actions;
1252 flutter::SemanticsNodeUpdates nodes;
1254 flutter::SemanticsNode node1;
1256 node1.label =
"node1";
1257 node1.flags.scopesRoute =
true;
1258 node1.flags.namesRoute =
true;
1259 nodes[node1.id] = node1;
1260 flutter::SemanticsNode node3;
1262 node3.label =
"node3";
1263 nodes[node3.id] = node3;
1264 flutter::SemanticsNode root_node;
1266 root_node.label =
"root";
1267 root_node.childrenInTraversalOrder = {1, 3};
1268 root_node.childrenInHitTestOrder = {1, 3};
1269 nodes[root_node.id] = root_node;
1270 bridge->UpdateSemantics(nodes, actions);
1272 XCTAssertEqual([accessibility_notifications count], 1ul);
1273 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node1");
1274 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1275 UIAccessibilityScreenChangedNotification);
1278 bridge->AccessibilityObjectDidBecomeFocused(0);
1280 flutter::SemanticsNodeUpdates new_nodes;
1282 flutter::SemanticsNode new_node1;
1284 new_node1.label =
"new_node1";
1285 new_node1.flags.scopesRoute =
true;
1286 new_node1.flags.namesRoute =
true;
1287 new_node1.childrenInTraversalOrder = {2};
1288 new_node1.childrenInHitTestOrder = {2};
1289 new_nodes[new_node1.id] = new_node1;
1290 flutter::SemanticsNode new_node2;
1292 new_node2.label =
"new_node2";
1293 new_node2.flags.scopesRoute =
true;
1294 new_node2.flags.namesRoute =
true;
1295 new_nodes[new_node2.id] = new_node2;
1296 flutter::SemanticsNode new_root_node;
1298 new_root_node.label =
"root";
1299 new_root_node.childrenInTraversalOrder = {1};
1300 new_root_node.childrenInHitTestOrder = {1};
1301 new_nodes[new_root_node.id] = new_root_node;
1302 bridge->UpdateSemantics(new_nodes, actions);
1303 XCTAssertEqual([accessibility_notifications count], 3ul);
1304 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1305 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1306 UIAccessibilityScreenChangedNotification);
1307 SemanticsObject* focusObject = accessibility_notifications[2][@"argument"];
1308 XCTAssertEqual([focusObject uid], 0);
1309 XCTAssertEqual([accessibility_notifications[2][
@"notification"] unsignedIntValue],
1310 UIAccessibilityLayoutChangedNotification);
1313 - (void)testAnnouncesRouteChangesWhenAddAdditionalRoute {
1314 flutter::MockDelegate mock_delegate;
1316 flutter::TaskRunners runners(
self.name.UTF8String,
1320 thread_task_runner);
1321 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1323 mock_delegate.settings_.enable_impeller
1329 std::make_shared<fml::SyncSwitch>());
1330 id mockFlutterView = OCMClassMock([
FlutterView class]);
1332 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1334 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1335 [[NSMutableArray alloc] init];
1336 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1337 ios_delegate->on_PostAccessibilityNotification_ =
1338 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1339 [accessibility_notifications addObject:@{
1340 @"notification" : @(notification),
1341 @"argument" : argument ? argument : [NSNull null],
1344 __block
auto bridge =
1345 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1348 std::move(ios_delegate));
1350 flutter::CustomAccessibilityActionUpdates actions;
1351 flutter::SemanticsNodeUpdates nodes;
1353 flutter::SemanticsNode node1;
1355 node1.label =
"node1";
1356 node1.flags.scopesRoute =
true;
1357 node1.flags.namesRoute =
true;
1358 nodes[node1.id] = node1;
1359 flutter::SemanticsNode root_node;
1361 root_node.flags.scopesRoute =
true;
1362 root_node.childrenInTraversalOrder = {1};
1363 root_node.childrenInHitTestOrder = {1};
1364 nodes[root_node.id] = root_node;
1365 bridge->UpdateSemantics(nodes, actions);
1367 XCTAssertEqual([accessibility_notifications count], 1ul);
1368 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node1");
1369 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1370 UIAccessibilityScreenChangedNotification);
1372 flutter::SemanticsNodeUpdates new_nodes;
1374 flutter::SemanticsNode new_node1;
1376 new_node1.label =
"new_node1";
1377 new_node1.flags.scopesRoute =
true;
1378 new_node1.flags.namesRoute =
true;
1379 new_node1.childrenInTraversalOrder = {2};
1380 new_node1.childrenInHitTestOrder = {2};
1381 new_nodes[new_node1.id] = new_node1;
1382 flutter::SemanticsNode new_node2;
1384 new_node2.label =
"new_node2";
1385 new_node2.flags.scopesRoute =
true;
1386 new_node2.flags.namesRoute =
true;
1387 new_nodes[new_node2.id] = new_node2;
1388 flutter::SemanticsNode new_root_node;
1390 new_root_node.flags.scopesRoute =
true;
1391 new_root_node.childrenInTraversalOrder = {1};
1392 new_root_node.childrenInHitTestOrder = {1};
1393 new_nodes[new_root_node.id] = new_root_node;
1394 bridge->UpdateSemantics(new_nodes, actions);
1395 XCTAssertEqual([accessibility_notifications count], 2ul);
1396 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1397 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1398 UIAccessibilityScreenChangedNotification);
1401 - (void)testAnnouncesRouteChangesRemoveRouteInMiddle {
1402 flutter::MockDelegate mock_delegate;
1404 flutter::TaskRunners runners(
self.name.UTF8String,
1408 thread_task_runner);
1409 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1411 mock_delegate.settings_.enable_impeller
1417 std::make_shared<fml::SyncSwitch>());
1418 id mockFlutterView = OCMClassMock([
FlutterView class]);
1420 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1422 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1423 [[NSMutableArray alloc] init];
1424 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1425 ios_delegate->on_PostAccessibilityNotification_ =
1426 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1427 [accessibility_notifications addObject:@{
1428 @"notification" : @(notification),
1429 @"argument" : argument ? argument : [NSNull null],
1432 __block
auto bridge =
1433 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1436 std::move(ios_delegate));
1438 flutter::CustomAccessibilityActionUpdates actions;
1439 flutter::SemanticsNodeUpdates nodes;
1441 flutter::SemanticsNode node1;
1443 node1.label =
"node1";
1444 node1.flags.scopesRoute =
true;
1445 node1.flags.namesRoute =
true;
1446 node1.childrenInTraversalOrder = {2};
1447 node1.childrenInHitTestOrder = {2};
1448 nodes[node1.id] = node1;
1449 flutter::SemanticsNode node2;
1451 node2.label =
"node2";
1452 node2.flags.scopesRoute =
true;
1453 node2.flags.namesRoute =
true;
1454 nodes[node2.id] = node2;
1455 flutter::SemanticsNode root_node;
1457 root_node.flags.scopesRoute =
true;
1458 root_node.childrenInTraversalOrder = {1};
1459 root_node.childrenInHitTestOrder = {1};
1460 nodes[root_node.id] = root_node;
1461 bridge->UpdateSemantics(nodes, actions);
1463 XCTAssertEqual([accessibility_notifications count], 1ul);
1464 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node2");
1465 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1466 UIAccessibilityScreenChangedNotification);
1468 flutter::SemanticsNodeUpdates new_nodes;
1470 flutter::SemanticsNode new_node1;
1472 new_node1.label =
"new_node1";
1473 new_node1.childrenInTraversalOrder = {2};
1474 new_node1.childrenInHitTestOrder = {2};
1475 new_nodes[new_node1.id] = new_node1;
1476 flutter::SemanticsNode new_node2;
1478 new_node2.label =
"new_node2";
1479 new_node2.flags.scopesRoute =
true;
1480 new_node2.flags.namesRoute =
true;
1481 new_nodes[new_node2.id] = new_node2;
1482 flutter::SemanticsNode new_root_node;
1484 new_root_node.flags.scopesRoute =
true;
1485 new_root_node.childrenInTraversalOrder = {1};
1486 new_root_node.childrenInHitTestOrder = {1};
1487 new_nodes[new_root_node.id] = new_root_node;
1488 bridge->UpdateSemantics(new_nodes, actions);
1489 XCTAssertEqual([accessibility_notifications count], 2ul);
1490 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1491 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1492 UIAccessibilityScreenChangedNotification);
1495 - (void)testHandleEvent {
1496 flutter::MockDelegate mock_delegate;
1498 flutter::TaskRunners runners(
self.name.UTF8String,
1502 thread_task_runner);
1503 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1505 mock_delegate.settings_.enable_impeller
1511 std::make_shared<fml::SyncSwitch>());
1512 id mockFlutterView = OCMClassMock([
FlutterView class]);
1514 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1516 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1517 [[NSMutableArray alloc] init];
1518 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1519 ios_delegate->on_PostAccessibilityNotification_ =
1520 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1521 [accessibility_notifications addObject:@{
1522 @"notification" : @(notification),
1523 @"argument" : argument ? argument : [NSNull null],
1526 __block
auto bridge =
1527 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1530 std::move(ios_delegate));
1532 NSDictionary<NSString*, id>* annotatedEvent = @{
@"type" :
@"focus",
@"nodeId" : @123};
1534 bridge->HandleEvent(annotatedEvent);
1536 XCTAssertEqual([accessibility_notifications count], 1ul);
1537 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1538 UIAccessibilityLayoutChangedNotification);
1541 - (void)testAccessibilityObjectDidBecomeFocused {
1542 flutter::MockDelegate mock_delegate;
1543 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
1544 auto thread_task_runner = thread->GetTaskRunner();
1545 flutter::TaskRunners runners(
self.name.UTF8String,
1549 thread_task_runner);
1554 OCMStub([flutterViewController
engine]).andReturn(
engine);
1555 OCMStub([
engine binaryMessenger]).andReturn(messenger);
1557 OCMStub([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
1558 binaryMessageHandler:[OCMArg any]])
1559 .andReturn(connection);
1561 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1563 mock_delegate.settings_.enable_impeller
1569 std::make_shared<fml::SyncSwitch>());
1570 fml::AutoResetWaitableEvent latch;
1571 thread_task_runner->PostTask([&] {
1572 platform_view->SetOwnerViewController(flutterViewController);
1574 std::make_unique<flutter::AccessibilityBridge>(nil,
1577 XCTAssertTrue(bridge.get());
1578 OCMVerify([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
1579 binaryMessageHandler:[OCMArg isNotNil]]);
1581 bridge->AccessibilityObjectDidBecomeFocused(123);
1583 NSDictionary<NSString*, id>* annotatedEvent = @{
@"type" :
@"didGainFocus",
@"nodeId" : @123};
1586 OCMVerify([messenger sendOnChannel:
@"flutter/accessibility" message:encodedMessage]);
1591 [engine stopMocking];
1594 - (void)testAnnouncesRouteChangesWhenNoNamesRoute {
1595 flutter::MockDelegate mock_delegate;
1597 flutter::TaskRunners runners(
self.name.UTF8String,
1601 thread_task_runner);
1602 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1604 mock_delegate.settings_.enable_impeller
1610 std::make_shared<fml::SyncSwitch>());
1611 id mockFlutterView = OCMClassMock([
FlutterView class]);
1613 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1615 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1616 [[NSMutableArray alloc] init];
1617 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1618 ios_delegate->on_PostAccessibilityNotification_ =
1619 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1620 [accessibility_notifications addObject:@{
1621 @"notification" : @(notification),
1622 @"argument" : argument ? argument : [NSNull null],
1625 __block
auto bridge =
1626 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1629 std::move(ios_delegate));
1631 flutter::CustomAccessibilityActionUpdates actions;
1632 flutter::SemanticsNodeUpdates nodes;
1634 flutter::SemanticsNode node1;
1636 node1.label =
"node1";
1637 node1.flags.scopesRoute =
true;
1638 node1.flags.namesRoute =
true;
1639 node1.childrenInTraversalOrder = {2, 3};
1640 node1.childrenInHitTestOrder = {2, 3};
1641 nodes[node1.id] = node1;
1642 flutter::SemanticsNode node2;
1644 node2.label =
"node2";
1645 nodes[node2.id] = node2;
1646 flutter::SemanticsNode node3;
1648 node3.label =
"node3";
1649 nodes[node3.id] = node3;
1650 flutter::SemanticsNode root_node;
1652 root_node.childrenInTraversalOrder = {1};
1653 root_node.childrenInHitTestOrder = {1};
1654 nodes[root_node.id] = root_node;
1655 bridge->UpdateSemantics(nodes, actions);
1658 XCTAssertEqual([accessibility_notifications count], 1ul);
1659 id focusObject = accessibility_notifications[0][@"argument"];
1660 XCTAssertTrue([focusObject isKindOfClass:[NSString
class]]);
1661 XCTAssertEqualObjects(focusObject,
@"node1");
1662 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1663 UIAccessibilityScreenChangedNotification);
1666 - (void)testAnnouncesLayoutChangeWithNilIfLastFocusIsRemoved {
1667 flutter::MockDelegate mock_delegate;
1669 flutter::TaskRunners runners(
self.name.UTF8String,
1673 thread_task_runner);
1674 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1676 mock_delegate.settings_.enable_impeller
1682 std::make_shared<fml::SyncSwitch>());
1684 id mockFlutterView = OCMClassMock([
FlutterView class]);
1685 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1687 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1688 [[NSMutableArray alloc] init];
1689 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1690 ios_delegate->on_PostAccessibilityNotification_ =
1691 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1692 [accessibility_notifications addObject:@{
1693 @"notification" : @(notification),
1694 @"argument" : argument ? argument : [NSNull null],
1697 __block
auto bridge =
1698 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1701 std::move(ios_delegate));
1703 flutter::CustomAccessibilityActionUpdates actions;
1704 flutter::SemanticsNodeUpdates first_update;
1706 flutter::SemanticsNode route_node;
1708 route_node.label =
"route";
1709 first_update[route_node.id] = route_node;
1710 flutter::SemanticsNode root_node;
1712 root_node.label =
"root";
1713 root_node.childrenInTraversalOrder = {1};
1714 root_node.childrenInHitTestOrder = {1};
1715 first_update[root_node.id] = root_node;
1716 bridge->UpdateSemantics(first_update, actions);
1718 XCTAssertEqual([accessibility_notifications count], 0ul);
1720 bridge->AccessibilityObjectDidBecomeFocused(1);
1722 flutter::SemanticsNodeUpdates second_update;
1724 flutter::SemanticsNode new_root_node;
1726 new_root_node.label =
"root";
1727 second_update[root_node.id] = new_root_node;
1728 bridge->UpdateSemantics(second_update, actions);
1729 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
1731 XCTAssertEqual([focusObject uid], 0);
1732 XCTAssertEqualObjects([focusObject accessibilityLabel],
@"root");
1733 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1734 UIAccessibilityLayoutChangedNotification);
1737 - (void)testAnnouncesLayoutChangeWithTheSameItemFocused {
1738 flutter::MockDelegate mock_delegate;
1740 flutter::TaskRunners runners(
self.name.UTF8String,
1744 thread_task_runner);
1745 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1747 mock_delegate.settings_.enable_impeller
1753 std::make_shared<fml::SyncSwitch>());
1755 id mockFlutterView = OCMClassMock([
FlutterView class]);
1756 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1758 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1759 [[NSMutableArray alloc] init];
1760 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1761 ios_delegate->on_PostAccessibilityNotification_ =
1762 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1763 [accessibility_notifications addObject:@{
1764 @"notification" : @(notification),
1765 @"argument" : argument ? argument : [NSNull null],
1768 __block
auto bridge =
1769 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1772 std::move(ios_delegate));
1774 flutter::CustomAccessibilityActionUpdates actions;
1775 flutter::SemanticsNodeUpdates first_update;
1777 flutter::SemanticsNode node_one;
1779 node_one.label =
"route1";
1780 first_update[node_one.id] = node_one;
1781 flutter::SemanticsNode node_two;
1783 node_two.label =
"route2";
1784 first_update[node_two.id] = node_two;
1785 flutter::SemanticsNode root_node;
1787 root_node.label =
"root";
1788 root_node.childrenInTraversalOrder = {1, 2};
1789 root_node.childrenInHitTestOrder = {1, 2};
1790 first_update[root_node.id] = root_node;
1791 bridge->UpdateSemantics(first_update, actions);
1793 XCTAssertEqual([accessibility_notifications count], 0ul);
1795 bridge->AccessibilityObjectDidBecomeFocused(1);
1797 flutter::SemanticsNodeUpdates second_update;
1799 flutter::SemanticsNode new_root_node;
1801 new_root_node.label =
"root";
1802 new_root_node.childrenInTraversalOrder = {1};
1803 new_root_node.childrenInHitTestOrder = {1};
1804 second_update[root_node.id] = new_root_node;
1805 bridge->UpdateSemantics(second_update, actions);
1806 id focusObject = accessibility_notifications[0][@"argument"];
1809 XCTAssertEqualObjects(focusObject, [NSNull
null]);
1810 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1811 UIAccessibilityLayoutChangedNotification);
1814 - (void)testAnnouncesLayoutChangeWhenFocusMovedOutside {
1815 flutter::MockDelegate mock_delegate;
1817 flutter::TaskRunners runners(
self.name.UTF8String,
1821 thread_task_runner);
1822 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1824 mock_delegate.settings_.enable_impeller
1830 std::make_shared<fml::SyncSwitch>());
1832 id mockFlutterView = OCMClassMock([
FlutterView class]);
1833 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1835 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1836 [[NSMutableArray alloc] init];
1837 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1838 ios_delegate->on_PostAccessibilityNotification_ =
1839 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1840 [accessibility_notifications addObject:@{
1841 @"notification" : @(notification),
1842 @"argument" : argument ? argument : [NSNull null],
1845 __block
auto bridge =
1846 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1849 std::move(ios_delegate));
1851 flutter::CustomAccessibilityActionUpdates actions;
1852 flutter::SemanticsNodeUpdates first_update;
1854 flutter::SemanticsNode node_one;
1856 node_one.label =
"route1";
1857 first_update[node_one.id] = node_one;
1858 flutter::SemanticsNode node_two;
1860 node_two.label =
"route2";
1861 first_update[node_two.id] = node_two;
1862 flutter::SemanticsNode root_node;
1864 root_node.label =
"root";
1865 root_node.childrenInTraversalOrder = {1, 2};
1866 root_node.childrenInHitTestOrder = {1, 2};
1867 first_update[root_node.id] = root_node;
1868 bridge->UpdateSemantics(first_update, actions);
1870 XCTAssertEqual([accessibility_notifications count], 0ul);
1872 bridge->AccessibilityObjectDidBecomeFocused(1);
1874 bridge->AccessibilityObjectDidLoseFocus(1);
1876 flutter::SemanticsNodeUpdates second_update;
1878 flutter::SemanticsNode new_root_node;
1880 new_root_node.label =
"root";
1881 new_root_node.childrenInTraversalOrder = {1};
1882 new_root_node.childrenInHitTestOrder = {1};
1883 second_update[root_node.id] = new_root_node;
1884 bridge->UpdateSemantics(second_update, actions);
1885 NSNull* focusObject = accessibility_notifications[0][@"argument"];
1888 XCTAssertEqual(focusObject, [NSNull
null]);
1889 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1890 UIAccessibilityLayoutChangedNotification);
1893 - (void)testAnnouncesScrollChangeWithLastFocused {
1894 flutter::MockDelegate mock_delegate;
1896 flutter::TaskRunners runners(
self.name.UTF8String,
1900 thread_task_runner);
1901 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1903 mock_delegate.settings_.enable_impeller
1909 std::make_shared<fml::SyncSwitch>());
1911 id mockFlutterView = OCMClassMock([
FlutterView class]);
1912 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1914 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1915 [[NSMutableArray alloc] init];
1916 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1917 ios_delegate->on_PostAccessibilityNotification_ =
1918 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1919 [accessibility_notifications addObject:@{
1920 @"notification" : @(notification),
1921 @"argument" : argument ? argument : [NSNull null],
1924 __block
auto bridge =
1925 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1928 std::move(ios_delegate));
1930 flutter::CustomAccessibilityActionUpdates actions;
1931 flutter::SemanticsNodeUpdates first_update;
1933 flutter::SemanticsNode node_one;
1935 node_one.label =
"route1";
1936 node_one.scrollPosition = 0.0;
1937 first_update[node_one.id] = node_one;
1938 flutter::SemanticsNode root_node;
1940 root_node.label =
"root";
1941 root_node.childrenInTraversalOrder = {1};
1942 root_node.childrenInHitTestOrder = {1};
1943 first_update[root_node.id] = root_node;
1944 bridge->UpdateSemantics(first_update, actions);
1947 [accessibility_notifications removeAllObjects];
1950 bridge->AccessibilityObjectDidBecomeFocused(1);
1952 flutter::SemanticsNodeUpdates second_update;
1954 flutter::SemanticsNode new_node_one;
1955 new_node_one.id = 1;
1956 new_node_one.label =
"route1";
1957 new_node_one.scrollPosition = 1.0;
1958 second_update[new_node_one.id] = new_node_one;
1959 bridge->UpdateSemantics(second_update, actions);
1960 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
1963 XCTAssertEqual([focusObject uid], 1);
1964 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1965 UIAccessibilityPageScrolledNotification);
1968 - (void)testAnnouncesScrollChangeDoesCallNativeAccessibility {
1969 flutter::MockDelegate mock_delegate;
1971 flutter::TaskRunners runners(
self.name.UTF8String,
1975 thread_task_runner);
1976 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1978 mock_delegate.settings_.enable_impeller
1984 std::make_shared<fml::SyncSwitch>());
1986 id mockFlutterView = OCMClassMock([
FlutterView class]);
1987 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1989 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1990 [[NSMutableArray alloc] init];
1991 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1992 ios_delegate->on_PostAccessibilityNotification_ =
1993 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1994 [accessibility_notifications addObject:@{
1995 @"notification" : @(notification),
1996 @"argument" : argument ? argument : [NSNull null],
1999 __block
auto bridge =
2000 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2003 std::move(ios_delegate));
2005 flutter::CustomAccessibilityActionUpdates actions;
2006 flutter::SemanticsNodeUpdates first_update;
2008 flutter::SemanticsNode node_one;
2010 node_one.label =
"route1";
2011 node_one.flags.hasImplicitScrolling =
true;
2012 node_one.scrollPosition = 0.0;
2013 first_update[node_one.id] = node_one;
2014 flutter::SemanticsNode root_node;
2016 root_node.label =
"root";
2017 root_node.childrenInTraversalOrder = {1};
2018 root_node.childrenInHitTestOrder = {1};
2019 first_update[root_node.id] = root_node;
2020 bridge->UpdateSemantics(first_update, actions);
2023 [accessibility_notifications removeAllObjects];
2026 bridge->AccessibilityObjectDidBecomeFocused(1);
2028 flutter::SemanticsNodeUpdates second_update;
2030 flutter::SemanticsNode new_node_one;
2031 new_node_one.id = 1;
2032 new_node_one.label =
"route1";
2033 new_node_one.flags.hasImplicitScrolling =
true;
2034 new_node_one.scrollPosition = 1.0;
2035 second_update[new_node_one.id] = new_node_one;
2036 bridge->UpdateSemantics(second_update, actions);
2037 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
2041 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
2042 UIAccessibilityPageScrolledNotification);
2045 - (void)testAnnouncesIgnoresRouteChangesWhenModal {
2046 flutter::MockDelegate mock_delegate;
2048 flutter::TaskRunners runners(
self.name.UTF8String,
2052 thread_task_runner);
2053 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2055 mock_delegate.settings_.enable_impeller
2061 std::make_shared<fml::SyncSwitch>());
2062 id mockFlutterView = OCMClassMock([
FlutterView class]);
2064 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2065 std::string label =
"some label";
2067 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2068 [[NSMutableArray alloc] init];
2069 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2070 ios_delegate->on_PostAccessibilityNotification_ =
2071 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2072 [accessibility_notifications addObject:@{
2073 @"notification" : @(notification),
2074 @"argument" : argument ? argument : [NSNull null],
2077 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2078 __block
auto bridge =
2079 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2082 std::move(ios_delegate));
2084 flutter::CustomAccessibilityActionUpdates actions;
2085 flutter::SemanticsNodeUpdates nodes;
2087 flutter::SemanticsNode route_node;
2089 route_node.flags.scopesRoute =
true;
2090 route_node.flags.namesRoute =
true;
2091 route_node.label =
"route";
2092 nodes[route_node.id] = route_node;
2093 flutter::SemanticsNode root_node;
2095 root_node.label = label;
2096 root_node.childrenInTraversalOrder = {1};
2097 root_node.childrenInHitTestOrder = {1};
2098 nodes[root_node.id] = root_node;
2099 bridge->UpdateSemantics(nodes, actions);
2101 XCTAssertEqual([accessibility_notifications count], 0ul);
2104 - (void)testAnnouncesIgnoresLayoutChangeWhenModal {
2105 flutter::MockDelegate mock_delegate;
2107 flutter::TaskRunners runners(
self.name.UTF8String,
2111 thread_task_runner);
2112 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2114 mock_delegate.settings_.enable_impeller
2120 std::make_shared<fml::SyncSwitch>());
2121 id mockFlutterView = OCMClassMock([
FlutterView class]);
2123 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2125 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2126 [[NSMutableArray alloc] init];
2127 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2128 ios_delegate->on_PostAccessibilityNotification_ =
2129 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2130 [accessibility_notifications addObject:@{
2131 @"notification" : @(notification),
2132 @"argument" : argument ? argument : [NSNull null],
2135 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2136 __block
auto bridge =
2137 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2140 std::move(ios_delegate));
2142 flutter::CustomAccessibilityActionUpdates actions;
2143 flutter::SemanticsNodeUpdates nodes;
2145 flutter::SemanticsNode child_node;
2147 child_node.label =
"child_node";
2148 nodes[child_node.id] = child_node;
2149 flutter::SemanticsNode root_node;
2151 root_node.label =
"root";
2152 root_node.childrenInTraversalOrder = {1};
2153 root_node.childrenInHitTestOrder = {1};
2154 nodes[root_node.id] = root_node;
2155 bridge->UpdateSemantics(nodes, actions);
2158 flutter::SemanticsNodeUpdates new_nodes;
2159 flutter::SemanticsNode new_root_node;
2161 new_root_node.label =
"root";
2162 new_nodes[new_root_node.id] = new_root_node;
2163 bridge->UpdateSemantics(new_nodes, actions);
2165 XCTAssertEqual([accessibility_notifications count], 0ul);
2168 - (void)testAnnouncesIgnoresScrollChangeWhenModal {
2169 flutter::MockDelegate mock_delegate;
2171 flutter::TaskRunners runners(
self.name.UTF8String,
2175 thread_task_runner);
2176 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2178 mock_delegate.settings_.enable_impeller
2184 std::make_shared<fml::SyncSwitch>());
2185 id mockFlutterView = OCMClassMock([
FlutterView class]);
2187 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2189 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2190 [[NSMutableArray alloc] init];
2191 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2192 ios_delegate->on_PostAccessibilityNotification_ =
2193 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2194 [accessibility_notifications addObject:@{
2195 @"notification" : @(notification),
2196 @"argument" : argument ? argument : [NSNull null],
2199 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2200 __block
auto bridge =
2201 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2204 std::move(ios_delegate));
2206 flutter::CustomAccessibilityActionUpdates actions;
2207 flutter::SemanticsNodeUpdates nodes;
2209 flutter::SemanticsNode root_node;
2211 root_node.label =
"root";
2212 root_node.scrollPosition = 1;
2213 nodes[root_node.id] = root_node;
2214 bridge->UpdateSemantics(nodes, actions);
2217 flutter::SemanticsNodeUpdates new_nodes;
2218 flutter::SemanticsNode new_root_node;
2220 new_root_node.label =
"root";
2221 new_root_node.scrollPosition = 2;
2222 new_nodes[new_root_node.id] = new_root_node;
2223 bridge->UpdateSemantics(new_nodes, actions);
2225 XCTAssertEqual([accessibility_notifications count], 0ul);
2228 - (void)testAccessibilityMessageAfterDeletion {
2229 flutter::MockDelegate mock_delegate;
2230 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2231 auto thread_task_runner = thread->GetTaskRunner();
2232 flutter::TaskRunners runners(
self.name.UTF8String,
2236 thread_task_runner);
2241 OCMStub([flutterViewController
engine]).andReturn(
engine);
2242 OCMStub([
engine binaryMessenger]).andReturn(messenger);
2244 OCMStub([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
2245 binaryMessageHandler:[OCMArg any]])
2246 .andReturn(connection);
2248 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2250 mock_delegate.settings_.enable_impeller
2256 std::make_shared<fml::SyncSwitch>());
2257 fml::AutoResetWaitableEvent latch;
2258 thread_task_runner->PostTask([&] {
2259 platform_view->SetOwnerViewController(flutterViewController);
2261 std::make_unique<flutter::AccessibilityBridge>(nil,
2264 XCTAssertTrue(bridge.get());
2265 OCMVerify([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
2266 binaryMessageHandler:[OCMArg isNotNil]]);
2271 OCMVerify([messenger cleanUpConnection:connection]);
2272 [engine stopMocking];
2275 - (void)testFlutterSemanticsScrollViewManagedObjectLifecycleCorrectly {
2276 flutter::MockDelegate mock_delegate;
2278 flutter::TaskRunners runners(
self.name.UTF8String,
2282 thread_task_runner);
2283 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2285 mock_delegate.settings_.enable_impeller
2291 std::make_shared<fml::SyncSwitch>());
2292 id mockFlutterView = OCMClassMock([
FlutterView class]);
2294 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2296 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2297 __block
auto bridge =
2298 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2301 std::move(ios_delegate));
2310 XCTAssertTrue(flutterSemanticsScrollView);
2313 XCTAssertFalse([flutterSemanticsScrollView isAccessibilityElement]);
2316 - (void)testPlatformViewDestructorDoesNotCallSemanticsAPIs {
2317 class TestDelegate :
public flutter::MockDelegate {
2319 void OnPlatformViewSetSemanticsEnabled(
bool enabled)
override { set_semantics_enabled_calls++; }
2320 int set_semantics_enabled_calls = 0;
2323 TestDelegate test_delegate;
2324 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2325 auto thread_task_runner = thread->GetTaskRunner();
2326 flutter::TaskRunners runners(
self.name.UTF8String,
2330 thread_task_runner);
2332 fml::AutoResetWaitableEvent latch;
2333 thread_task_runner->PostTask([&] {
2334 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2336 test_delegate.settings_.enable_impeller
2342 std::make_shared<fml::SyncSwitch>());
2347 flutterPlatformViewsController.
taskRunner = thread_task_runner;
2349 OCMStub([mockFlutterViewController platformViewsController])
2350 .andReturn(flutterPlatformViewsController);
2351 platform_view->SetOwnerViewController(mockFlutterViewController);
2354 XCTAssertNotEqual(test_delegate.set_semantics_enabled_calls, 0);
2357 test_delegate.set_semantics_enabled_calls = 0;
2359 XCTAssertEqual(test_delegate.set_semantics_enabled_calls, 0);
2366 - (void)testResetsAccessibilityElementsOnHotRestart {
2367 flutter::MockDelegate mock_delegate;
2368 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2369 auto thread_task_runner = thread->GetTaskRunner();
2370 flutter::TaskRunners runners(
self.name.UTF8String,
2374 thread_task_runner);
2375 id mockFlutterView = OCMClassMock([
FlutterView class]);
2377 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
2379 fml::AutoResetWaitableEvent latch;
2380 thread_task_runner->PostTask([&] {
2381 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2383 mock_delegate.settings_.enable_impeller
2389 std::make_shared<fml::SyncSwitch>());
2391 platform_view->SetOwnerViewController(mockFlutterViewController);
2395 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg isNil]]);
2397 OCMVerifyAll(mockFlutterView);
2404 - (void)testWeakViewController {
2405 flutter::MockDelegate mock_delegate;
2407 flutter::TaskRunners runners(
self.name.UTF8String,
2411 thread_task_runner);
2412 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2414 mock_delegate.settings_.enable_impeller
2420 std::make_shared<fml::SyncSwitch>());
2422 std::unique_ptr<flutter::AccessibilityBridge> bridge;
2424 id mockFlutterView = OCMClassMock([
FlutterView class]);
2426 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
2427 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2429 bridge = std::make_unique<flutter::AccessibilityBridge>(
2430 mockFlutterViewController,
2433 XCTAssertTrue(bridge.get());
2434 XCTAssertNotNil(bridge->view());
2436 XCTAssertNil(bridge->view());
int64_t FlutterBinaryMessengerConnection
void(^ FlutterResult)(id _Nullable result)
constexpr int32_t kRootNodeId
static __weak MockPlatformView * gMockPlatformView
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
SemanticsObject * semanticsObject
fml::RefPtr< fml::TaskRunner > CreateNewThread(const std::string &name)
instancetype sharedInstance()