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 =
static_cast<int32_t
>(flutter::SemanticsFlags::kHasImplicitScrolling);
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 =
static_cast<int32_t
>(flutter::SemanticsFlags::kHasImplicitScrolling);
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 =
static_cast<int32_t
>(flutter::SemanticsFlags::kHasImplicitScrolling);
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 =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute);
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 =
static_cast<int32_t
>(flutter::SemanticsFlags::kNamesRoute);
696 node3.label =
"node3";
697 nodes[node3.id] = node3;
698 flutter::SemanticsNode root_node;
700 root_node.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute);
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 =
static_cast<int32_t
>(flutter::SemanticsFlags::kIsInMutuallyExclusiveGroup) |
748 static_cast<int32_t
>(flutter::SemanticsFlags::kIsEnabled) |
749 static_cast<int32_t
>(flutter::SemanticsFlags::kHasCheckedState) |
750 static_cast<int32_t
>(flutter::SemanticsFlags::kHasEnabledState);
751 nodes[root_node.id] = root_node;
752 bridge->UpdateSemantics(nodes, actions);
757 XCTAssertTrue((rootNode.accessibilityTraits & UIAccessibilityTraitButton) > 0);
758 XCTAssertNil(rootNode.accessibilityValue);
761 - (void)testSemanticObjectWithNoAccessibilityFlagNotMarkedAsResponsiveToUserInteraction {
762 flutter::MockDelegate mock_delegate;
764 flutter::TaskRunners runners(
self.name.UTF8String,
769 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
771 mock_delegate.settings_.enable_impeller
777 std::make_shared<fml::SyncSwitch>());
783 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
784 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
785 __block
auto bridge =
786 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
789 std::move(ios_delegate));
791 flutter::CustomAccessibilityActionUpdates actions;
792 flutter::SemanticsNodeUpdates nodes;
794 flutter::SemanticsNode root_node;
797 nodes[root_node.id] = root_node;
798 bridge->UpdateSemantics(nodes, actions);
803 XCTAssertFalse(rootNode.accessibilityRespondsToUserInteraction);
806 - (void)testSemanticObjectWithAccessibilityFlagsMarkedAsResponsiveToUserInteraction {
807 flutter::MockDelegate mock_delegate;
809 flutter::TaskRunners runners(
self.name.UTF8String,
814 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
816 mock_delegate.settings_.enable_impeller
822 std::make_shared<fml::SyncSwitch>());
828 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
829 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
830 __block
auto bridge =
831 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
834 std::move(ios_delegate));
836 flutter::CustomAccessibilityActionUpdates actions;
837 flutter::SemanticsNodeUpdates nodes;
839 flutter::SemanticsNode root_node;
841 root_node.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
843 nodes[root_node.id] = root_node;
844 bridge->UpdateSemantics(nodes, actions);
849 XCTAssertTrue(rootNode.accessibilityRespondsToUserInteraction);
854 - (void)testLabeledParentAndChildNotInteractive {
855 flutter::MockDelegate mock_delegate;
857 flutter::TaskRunners runners(
self.name.UTF8String,
865 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
867 mock_delegate.settings_.enable_impeller
870 flutterPlatformViewsController,
873 std::make_shared<fml::SyncSwitch>());
879 OCMStub([mockFlutterViewController view]).andReturn(flutterView);
882 auto bridge = std::make_unique<flutter::AccessibilityBridge>(
883 mockFlutterViewController,
885 flutterPlatformViewsController);
887 flutter::SemanticsNodeUpdates nodes;
889 flutter::SemanticsNode parent;
891 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
892 parent.label =
"parent_label";
894 flutter::SemanticsNode node;
896 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
897 node.label =
"child_label";
899 parent.childrenInTraversalOrder.push_back(1);
900 parent.childrenInHitTestOrder.push_back(1);
903 flutter::CustomAccessibilityActionUpdates actions;
904 bridge->UpdateSemantics(nodes, actions);
910 XCTAssertTrue([parentNode.accessibilityLabel isEqualToString:
@"parent_label"]);
911 XCTAssertTrue([childNode.accessibilityLabel isEqualToString:
@"child_label"]);
912 XCTAssertFalse(parentNode.accessibilityRespondsToUserInteraction);
913 XCTAssertFalse(childNode.accessibilityRespondsToUserInteraction);
917 - (void)testLayoutChangeWithNonAccessibilityElement {
918 flutter::MockDelegate mock_delegate;
920 flutter::TaskRunners runners(
self.name.UTF8String,
925 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
927 mock_delegate.settings_.enable_impeller
933 std::make_shared<fml::SyncSwitch>());
934 id mockFlutterView = OCMClassMock([
FlutterView class]);
936 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
938 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
939 [[NSMutableArray alloc] init];
940 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
941 ios_delegate->on_PostAccessibilityNotification_ =
942 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
943 [accessibility_notifications addObject:@{
944 @"notification" : @(notification),
945 @"argument" : argument ? argument : [NSNull null],
948 __block
auto bridge =
949 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
952 std::move(ios_delegate));
954 flutter::CustomAccessibilityActionUpdates actions;
955 flutter::SemanticsNodeUpdates nodes;
957 flutter::SemanticsNode node1;
959 node1.label =
"node1";
960 node1.childrenInTraversalOrder = {2, 3};
961 node1.childrenInHitTestOrder = {2, 3};
962 nodes[node1.id] = node1;
963 flutter::SemanticsNode node2;
965 node2.label =
"node2";
966 nodes[node2.id] = node2;
967 flutter::SemanticsNode node3;
969 node3.label =
"node3";
970 nodes[node3.id] = node3;
971 flutter::SemanticsNode root_node;
973 root_node.label =
"root";
974 root_node.childrenInTraversalOrder = {1};
975 root_node.childrenInHitTestOrder = {1};
976 nodes[root_node.id] = root_node;
977 bridge->UpdateSemantics(nodes, actions);
980 bridge->AccessibilityObjectDidBecomeFocused(1);
985 flutter::CustomAccessibilityActionUpdates new_actions;
986 flutter::SemanticsNodeUpdates new_nodes;
988 flutter::SemanticsNode new_node1;
990 new_node1.childrenInTraversalOrder = {2};
991 new_node1.childrenInHitTestOrder = {2};
992 new_nodes[new_node1.id] = new_node1;
993 bridge->UpdateSemantics(new_nodes, new_actions);
995 XCTAssertEqual([accessibility_notifications count], 1ul);
996 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
998 XCTAssertEqual([focusObject uid], 2);
999 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1000 UIAccessibilityLayoutChangedNotification);
1003 - (void)testLayoutChangeDoesCallNativeAccessibility {
1004 flutter::MockDelegate mock_delegate;
1006 flutter::TaskRunners runners(
self.name.UTF8String,
1010 thread_task_runner);
1011 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1013 mock_delegate.settings_.enable_impeller
1019 std::make_shared<fml::SyncSwitch>());
1020 id mockFlutterView = OCMClassMock([
FlutterView class]);
1022 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1024 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1025 [[NSMutableArray alloc] init];
1026 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1027 ios_delegate->on_PostAccessibilityNotification_ =
1028 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1029 [accessibility_notifications addObject:@{
1030 @"notification" : @(notification),
1031 @"argument" : argument ? argument : [NSNull null],
1034 __block
auto bridge =
1035 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1038 std::move(ios_delegate));
1040 flutter::CustomAccessibilityActionUpdates actions;
1041 flutter::SemanticsNodeUpdates nodes;
1043 flutter::SemanticsNode node1;
1045 node1.label =
"node1";
1046 nodes[node1.id] = node1;
1047 flutter::SemanticsNode root_node;
1049 root_node.label =
"root";
1050 root_node.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kHasImplicitScrolling);
1051 root_node.childrenInTraversalOrder = {1};
1052 root_node.childrenInHitTestOrder = {1};
1053 nodes[root_node.id] = root_node;
1054 bridge->UpdateSemantics(nodes, actions);
1057 bridge->AccessibilityObjectDidBecomeFocused(0);
1060 flutter::CustomAccessibilityActionUpdates new_actions;
1061 flutter::SemanticsNodeUpdates new_nodes;
1063 flutter::SemanticsNode new_root_node;
1065 new_root_node.label =
"root";
1066 new_root_node.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kHasImplicitScrolling);
1067 new_nodes[new_root_node.id] = new_root_node;
1068 bridge->UpdateSemantics(new_nodes, new_actions);
1070 XCTAssertEqual([accessibility_notifications count], 1ul);
1071 id focusObject = accessibility_notifications[0][@"argument"];
1075 XCTAssertEqualObjects(focusObject, [NSNull
null]);
1076 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1077 UIAccessibilityLayoutChangedNotification);
1080 - (void)testLayoutChangeDoesCallNativeAccessibilityWhenFocusChanged {
1081 flutter::MockDelegate mock_delegate;
1083 flutter::TaskRunners runners(
self.name.UTF8String,
1087 thread_task_runner);
1088 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1090 mock_delegate.settings_.enable_impeller
1096 std::make_shared<fml::SyncSwitch>());
1097 id mockFlutterView = OCMClassMock([
FlutterView class]);
1099 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1101 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1102 [[NSMutableArray alloc] init];
1103 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1104 ios_delegate->on_PostAccessibilityNotification_ =
1105 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1106 [accessibility_notifications addObject:@{
1107 @"notification" : @(notification),
1108 @"argument" : argument ? argument : [NSNull null],
1111 __block
auto bridge =
1112 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1115 std::move(ios_delegate));
1117 flutter::CustomAccessibilityActionUpdates actions;
1118 flutter::SemanticsNodeUpdates nodes;
1120 flutter::SemanticsNode node1;
1122 node1.label =
"node1";
1123 nodes[node1.id] = node1;
1124 flutter::SemanticsNode root_node;
1126 root_node.label =
"root";
1127 root_node.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kHasImplicitScrolling);
1128 root_node.childrenInTraversalOrder = {1};
1129 root_node.childrenInHitTestOrder = {1};
1130 nodes[root_node.id] = root_node;
1131 bridge->UpdateSemantics(nodes, actions);
1134 bridge->AccessibilityObjectDidBecomeFocused(1);
1137 flutter::CustomAccessibilityActionUpdates new_actions;
1138 flutter::SemanticsNodeUpdates new_nodes;
1140 flutter::SemanticsNode new_root_node;
1142 new_root_node.label =
"root";
1143 new_root_node.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kHasImplicitScrolling);
1144 new_nodes[new_root_node.id] = new_root_node;
1145 bridge->UpdateSemantics(new_nodes, new_actions);
1147 XCTAssertEqual([accessibility_notifications count], 1ul);
1148 SemanticsObject* focusObject2 = accessibility_notifications[0][@"argument"];
1152 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1153 UIAccessibilityLayoutChangedNotification);
1156 - (void)testScrollableSemanticsContainerReturnsCorrectChildren {
1157 flutter::MockDelegate mock_delegate;
1159 flutter::TaskRunners runners(
self.name.UTF8String,
1163 thread_task_runner);
1164 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1166 mock_delegate.settings_.enable_impeller
1172 std::make_shared<fml::SyncSwitch>());
1173 id mockFlutterView = OCMClassMock([
FlutterView class]);
1175 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1177 OCMExpect([mockFlutterView
1178 setAccessibilityElements:[OCMArg checkWithBlock:^BOOL(NSArray* value) {
1179 if ([value count] != 1) {
1188 return [scrollableContainer indexOfAccessibilityElement:nativeScrollable] == 1;
1190 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1191 __block
auto bridge =
1192 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1195 std::move(ios_delegate));
1197 flutter::CustomAccessibilityActionUpdates actions;
1198 flutter::SemanticsNodeUpdates nodes;
1200 flutter::SemanticsNode node1;
1202 node1.label =
"node1";
1203 node1.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kHasImplicitScrolling);
1204 nodes[node1.id] = node1;
1205 flutter::SemanticsNode root_node;
1207 root_node.label =
"root";
1208 root_node.childrenInTraversalOrder = {1};
1209 root_node.childrenInHitTestOrder = {1};
1210 nodes[root_node.id] = root_node;
1211 bridge->UpdateSemantics(nodes, actions);
1212 OCMVerifyAll(mockFlutterView);
1215 - (void)testAnnouncesRouteChangesAndLayoutChangeInOneUpdate {
1216 flutter::MockDelegate mock_delegate;
1218 flutter::TaskRunners runners(
self.name.UTF8String,
1222 thread_task_runner);
1223 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1225 mock_delegate.settings_.enable_impeller
1231 std::make_shared<fml::SyncSwitch>());
1232 id mockFlutterView = OCMClassMock([
FlutterView class]);
1234 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1236 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1237 [[NSMutableArray alloc] init];
1238 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1239 ios_delegate->on_PostAccessibilityNotification_ =
1240 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1241 [accessibility_notifications addObject:@{
1242 @"notification" : @(notification),
1243 @"argument" : argument ? argument : [NSNull null],
1246 __block
auto bridge =
1247 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1250 std::move(ios_delegate));
1252 flutter::CustomAccessibilityActionUpdates actions;
1253 flutter::SemanticsNodeUpdates nodes;
1255 flutter::SemanticsNode node1;
1257 node1.label =
"node1";
1258 node1.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute) |
1259 static_cast<int32_t
>(flutter::SemanticsFlags::kNamesRoute);
1260 nodes[node1.id] = node1;
1261 flutter::SemanticsNode node3;
1263 node3.label =
"node3";
1264 nodes[node3.id] = node3;
1265 flutter::SemanticsNode root_node;
1267 root_node.label =
"root";
1268 root_node.childrenInTraversalOrder = {1, 3};
1269 root_node.childrenInHitTestOrder = {1, 3};
1270 nodes[root_node.id] = root_node;
1271 bridge->UpdateSemantics(nodes, actions);
1273 XCTAssertEqual([accessibility_notifications count], 1ul);
1274 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node1");
1275 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1276 UIAccessibilityScreenChangedNotification);
1279 bridge->AccessibilityObjectDidBecomeFocused(0);
1281 flutter::SemanticsNodeUpdates new_nodes;
1283 flutter::SemanticsNode new_node1;
1285 new_node1.label =
"new_node1";
1286 new_node1.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute) |
1287 static_cast<int32_t
>(flutter::SemanticsFlags::kNamesRoute);
1288 new_node1.childrenInTraversalOrder = {2};
1289 new_node1.childrenInHitTestOrder = {2};
1290 new_nodes[new_node1.id] = new_node1;
1291 flutter::SemanticsNode new_node2;
1293 new_node2.label =
"new_node2";
1294 new_node2.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute) |
1295 static_cast<int32_t
>(flutter::SemanticsFlags::kNamesRoute);
1296 new_nodes[new_node2.id] = new_node2;
1297 flutter::SemanticsNode new_root_node;
1299 new_root_node.label =
"root";
1300 new_root_node.childrenInTraversalOrder = {1};
1301 new_root_node.childrenInHitTestOrder = {1};
1302 new_nodes[new_root_node.id] = new_root_node;
1303 bridge->UpdateSemantics(new_nodes, actions);
1304 XCTAssertEqual([accessibility_notifications count], 3ul);
1305 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1306 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1307 UIAccessibilityScreenChangedNotification);
1308 SemanticsObject* focusObject = accessibility_notifications[2][@"argument"];
1309 XCTAssertEqual([focusObject uid], 0);
1310 XCTAssertEqual([accessibility_notifications[2][
@"notification"] unsignedIntValue],
1311 UIAccessibilityLayoutChangedNotification);
1314 - (void)testAnnouncesRouteChangesWhenAddAdditionalRoute {
1315 flutter::MockDelegate mock_delegate;
1317 flutter::TaskRunners runners(
self.name.UTF8String,
1321 thread_task_runner);
1322 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1324 mock_delegate.settings_.enable_impeller
1330 std::make_shared<fml::SyncSwitch>());
1331 id mockFlutterView = OCMClassMock([
FlutterView class]);
1333 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1335 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1336 [[NSMutableArray alloc] init];
1337 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1338 ios_delegate->on_PostAccessibilityNotification_ =
1339 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1340 [accessibility_notifications addObject:@{
1341 @"notification" : @(notification),
1342 @"argument" : argument ? argument : [NSNull null],
1345 __block
auto bridge =
1346 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1349 std::move(ios_delegate));
1351 flutter::CustomAccessibilityActionUpdates actions;
1352 flutter::SemanticsNodeUpdates nodes;
1354 flutter::SemanticsNode node1;
1356 node1.label =
"node1";
1357 node1.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute) |
1358 static_cast<int32_t
>(flutter::SemanticsFlags::kNamesRoute);
1359 nodes[node1.id] = node1;
1360 flutter::SemanticsNode root_node;
1362 root_node.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute);
1363 root_node.childrenInTraversalOrder = {1};
1364 root_node.childrenInHitTestOrder = {1};
1365 nodes[root_node.id] = root_node;
1366 bridge->UpdateSemantics(nodes, actions);
1368 XCTAssertEqual([accessibility_notifications count], 1ul);
1369 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node1");
1370 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1371 UIAccessibilityScreenChangedNotification);
1373 flutter::SemanticsNodeUpdates new_nodes;
1375 flutter::SemanticsNode new_node1;
1377 new_node1.label =
"new_node1";
1378 new_node1.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute) |
1379 static_cast<int32_t
>(flutter::SemanticsFlags::kNamesRoute);
1380 new_node1.childrenInTraversalOrder = {2};
1381 new_node1.childrenInHitTestOrder = {2};
1382 new_nodes[new_node1.id] = new_node1;
1383 flutter::SemanticsNode new_node2;
1385 new_node2.label =
"new_node2";
1386 new_node2.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute) |
1387 static_cast<int32_t
>(flutter::SemanticsFlags::kNamesRoute);
1388 new_nodes[new_node2.id] = new_node2;
1389 flutter::SemanticsNode new_root_node;
1391 new_root_node.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute);
1392 new_root_node.childrenInTraversalOrder = {1};
1393 new_root_node.childrenInHitTestOrder = {1};
1394 new_nodes[new_root_node.id] = new_root_node;
1395 bridge->UpdateSemantics(new_nodes, actions);
1396 XCTAssertEqual([accessibility_notifications count], 2ul);
1397 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1398 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1399 UIAccessibilityScreenChangedNotification);
1402 - (void)testAnnouncesRouteChangesRemoveRouteInMiddle {
1403 flutter::MockDelegate mock_delegate;
1405 flutter::TaskRunners runners(
self.name.UTF8String,
1409 thread_task_runner);
1410 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1412 mock_delegate.settings_.enable_impeller
1418 std::make_shared<fml::SyncSwitch>());
1419 id mockFlutterView = OCMClassMock([
FlutterView class]);
1421 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1423 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1424 [[NSMutableArray alloc] init];
1425 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1426 ios_delegate->on_PostAccessibilityNotification_ =
1427 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1428 [accessibility_notifications addObject:@{
1429 @"notification" : @(notification),
1430 @"argument" : argument ? argument : [NSNull null],
1433 __block
auto bridge =
1434 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1437 std::move(ios_delegate));
1439 flutter::CustomAccessibilityActionUpdates actions;
1440 flutter::SemanticsNodeUpdates nodes;
1442 flutter::SemanticsNode node1;
1444 node1.label =
"node1";
1445 node1.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute) |
1446 static_cast<int32_t
>(flutter::SemanticsFlags::kNamesRoute);
1447 node1.childrenInTraversalOrder = {2};
1448 node1.childrenInHitTestOrder = {2};
1449 nodes[node1.id] = node1;
1450 flutter::SemanticsNode node2;
1452 node2.label =
"node2";
1453 node2.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute) |
1454 static_cast<int32_t
>(flutter::SemanticsFlags::kNamesRoute);
1455 nodes[node2.id] = node2;
1456 flutter::SemanticsNode root_node;
1458 root_node.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute);
1459 root_node.childrenInTraversalOrder = {1};
1460 root_node.childrenInHitTestOrder = {1};
1461 nodes[root_node.id] = root_node;
1462 bridge->UpdateSemantics(nodes, actions);
1464 XCTAssertEqual([accessibility_notifications count], 1ul);
1465 XCTAssertEqualObjects(accessibility_notifications[0][
@"argument"],
@"node2");
1466 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1467 UIAccessibilityScreenChangedNotification);
1469 flutter::SemanticsNodeUpdates new_nodes;
1471 flutter::SemanticsNode new_node1;
1473 new_node1.label =
"new_node1";
1474 new_node1.childrenInTraversalOrder = {2};
1475 new_node1.childrenInHitTestOrder = {2};
1476 new_nodes[new_node1.id] = new_node1;
1477 flutter::SemanticsNode new_node2;
1479 new_node2.label =
"new_node2";
1480 new_node2.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute) |
1481 static_cast<int32_t
>(flutter::SemanticsFlags::kNamesRoute);
1482 new_nodes[new_node2.id] = new_node2;
1483 flutter::SemanticsNode new_root_node;
1485 new_root_node.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute);
1486 new_root_node.childrenInTraversalOrder = {1};
1487 new_root_node.childrenInHitTestOrder = {1};
1488 new_nodes[new_root_node.id] = new_root_node;
1489 bridge->UpdateSemantics(new_nodes, actions);
1490 XCTAssertEqual([accessibility_notifications count], 2ul);
1491 XCTAssertEqualObjects(accessibility_notifications[1][
@"argument"],
@"new_node2");
1492 XCTAssertEqual([accessibility_notifications[1][
@"notification"] unsignedIntValue],
1493 UIAccessibilityScreenChangedNotification);
1496 - (void)testHandleEvent {
1497 flutter::MockDelegate mock_delegate;
1499 flutter::TaskRunners runners(
self.name.UTF8String,
1503 thread_task_runner);
1504 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1506 mock_delegate.settings_.enable_impeller
1512 std::make_shared<fml::SyncSwitch>());
1513 id mockFlutterView = OCMClassMock([
FlutterView class]);
1515 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1517 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1518 [[NSMutableArray alloc] init];
1519 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1520 ios_delegate->on_PostAccessibilityNotification_ =
1521 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1522 [accessibility_notifications addObject:@{
1523 @"notification" : @(notification),
1524 @"argument" : argument ? argument : [NSNull null],
1527 __block
auto bridge =
1528 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1531 std::move(ios_delegate));
1533 NSDictionary<NSString*, id>* annotatedEvent = @{
@"type" :
@"focus",
@"nodeId" : @123};
1535 bridge->HandleEvent(annotatedEvent);
1537 XCTAssertEqual([accessibility_notifications count], 1ul);
1538 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1539 UIAccessibilityLayoutChangedNotification);
1542 - (void)testAccessibilityObjectDidBecomeFocused {
1543 flutter::MockDelegate mock_delegate;
1544 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
1545 auto thread_task_runner = thread->GetTaskRunner();
1546 flutter::TaskRunners runners(
self.name.UTF8String,
1550 thread_task_runner);
1555 OCMStub([flutterViewController
engine]).andReturn(
engine);
1556 OCMStub([
engine binaryMessenger]).andReturn(messenger);
1558 OCMStub([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
1559 binaryMessageHandler:[OCMArg any]])
1560 .andReturn(connection);
1562 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1564 mock_delegate.settings_.enable_impeller
1570 std::make_shared<fml::SyncSwitch>());
1571 fml::AutoResetWaitableEvent latch;
1572 thread_task_runner->PostTask([&] {
1573 platform_view->SetOwnerViewController(flutterViewController);
1575 std::make_unique<flutter::AccessibilityBridge>(nil,
1578 XCTAssertTrue(bridge.get());
1579 OCMVerify([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
1580 binaryMessageHandler:[OCMArg isNotNil]]);
1582 bridge->AccessibilityObjectDidBecomeFocused(123);
1584 NSDictionary<NSString*, id>* annotatedEvent = @{
@"type" :
@"didGainFocus",
@"nodeId" : @123};
1587 OCMVerify([messenger sendOnChannel:
@"flutter/accessibility" message:encodedMessage]);
1592 [engine stopMocking];
1595 - (void)testAnnouncesRouteChangesWhenNoNamesRoute {
1596 flutter::MockDelegate mock_delegate;
1598 flutter::TaskRunners runners(
self.name.UTF8String,
1602 thread_task_runner);
1603 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1605 mock_delegate.settings_.enable_impeller
1611 std::make_shared<fml::SyncSwitch>());
1612 id mockFlutterView = OCMClassMock([
FlutterView class]);
1614 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1616 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1617 [[NSMutableArray alloc] init];
1618 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1619 ios_delegate->on_PostAccessibilityNotification_ =
1620 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1621 [accessibility_notifications addObject:@{
1622 @"notification" : @(notification),
1623 @"argument" : argument ? argument : [NSNull null],
1626 __block
auto bridge =
1627 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1630 std::move(ios_delegate));
1632 flutter::CustomAccessibilityActionUpdates actions;
1633 flutter::SemanticsNodeUpdates nodes;
1635 flutter::SemanticsNode node1;
1637 node1.label =
"node1";
1638 node1.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute) |
1639 static_cast<int32_t
>(flutter::SemanticsFlags::kNamesRoute);
1640 node1.childrenInTraversalOrder = {2, 3};
1641 node1.childrenInHitTestOrder = {2, 3};
1642 nodes[node1.id] = node1;
1643 flutter::SemanticsNode node2;
1645 node2.label =
"node2";
1646 nodes[node2.id] = node2;
1647 flutter::SemanticsNode node3;
1649 node3.label =
"node3";
1650 nodes[node3.id] = node3;
1651 flutter::SemanticsNode root_node;
1653 root_node.childrenInTraversalOrder = {1};
1654 root_node.childrenInHitTestOrder = {1};
1655 nodes[root_node.id] = root_node;
1656 bridge->UpdateSemantics(nodes, actions);
1659 XCTAssertEqual([accessibility_notifications count], 1ul);
1660 id focusObject = accessibility_notifications[0][@"argument"];
1661 XCTAssertTrue([focusObject isKindOfClass:[NSString
class]]);
1662 XCTAssertEqualObjects(focusObject,
@"node1");
1663 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1664 UIAccessibilityScreenChangedNotification);
1667 - (void)testAnnouncesLayoutChangeWithNilIfLastFocusIsRemoved {
1668 flutter::MockDelegate mock_delegate;
1670 flutter::TaskRunners runners(
self.name.UTF8String,
1674 thread_task_runner);
1675 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1677 mock_delegate.settings_.enable_impeller
1683 std::make_shared<fml::SyncSwitch>());
1685 id mockFlutterView = OCMClassMock([
FlutterView class]);
1686 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1688 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1689 [[NSMutableArray alloc] init];
1690 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1691 ios_delegate->on_PostAccessibilityNotification_ =
1692 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1693 [accessibility_notifications addObject:@{
1694 @"notification" : @(notification),
1695 @"argument" : argument ? argument : [NSNull null],
1698 __block
auto bridge =
1699 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1702 std::move(ios_delegate));
1704 flutter::CustomAccessibilityActionUpdates actions;
1705 flutter::SemanticsNodeUpdates first_update;
1707 flutter::SemanticsNode route_node;
1709 route_node.label =
"route";
1710 first_update[route_node.id] = route_node;
1711 flutter::SemanticsNode root_node;
1713 root_node.label =
"root";
1714 root_node.childrenInTraversalOrder = {1};
1715 root_node.childrenInHitTestOrder = {1};
1716 first_update[root_node.id] = root_node;
1717 bridge->UpdateSemantics(first_update, actions);
1719 XCTAssertEqual([accessibility_notifications count], 0ul);
1721 bridge->AccessibilityObjectDidBecomeFocused(1);
1723 flutter::SemanticsNodeUpdates second_update;
1725 flutter::SemanticsNode new_root_node;
1727 new_root_node.label =
"root";
1728 second_update[root_node.id] = new_root_node;
1729 bridge->UpdateSemantics(second_update, actions);
1730 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
1732 XCTAssertEqual([focusObject uid], 0);
1733 XCTAssertEqualObjects([focusObject accessibilityLabel],
@"root");
1734 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1735 UIAccessibilityLayoutChangedNotification);
1738 - (void)testAnnouncesLayoutChangeWithTheSameItemFocused {
1739 flutter::MockDelegate mock_delegate;
1741 flutter::TaskRunners runners(
self.name.UTF8String,
1745 thread_task_runner);
1746 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1748 mock_delegate.settings_.enable_impeller
1754 std::make_shared<fml::SyncSwitch>());
1756 id mockFlutterView = OCMClassMock([
FlutterView class]);
1757 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1759 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1760 [[NSMutableArray alloc] init];
1761 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1762 ios_delegate->on_PostAccessibilityNotification_ =
1763 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1764 [accessibility_notifications addObject:@{
1765 @"notification" : @(notification),
1766 @"argument" : argument ? argument : [NSNull null],
1769 __block
auto bridge =
1770 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1773 std::move(ios_delegate));
1775 flutter::CustomAccessibilityActionUpdates actions;
1776 flutter::SemanticsNodeUpdates first_update;
1778 flutter::SemanticsNode node_one;
1780 node_one.label =
"route1";
1781 first_update[node_one.id] = node_one;
1782 flutter::SemanticsNode node_two;
1784 node_two.label =
"route2";
1785 first_update[node_two.id] = node_two;
1786 flutter::SemanticsNode root_node;
1788 root_node.label =
"root";
1789 root_node.childrenInTraversalOrder = {1, 2};
1790 root_node.childrenInHitTestOrder = {1, 2};
1791 first_update[root_node.id] = root_node;
1792 bridge->UpdateSemantics(first_update, actions);
1794 XCTAssertEqual([accessibility_notifications count], 0ul);
1796 bridge->AccessibilityObjectDidBecomeFocused(1);
1798 flutter::SemanticsNodeUpdates second_update;
1800 flutter::SemanticsNode new_root_node;
1802 new_root_node.label =
"root";
1803 new_root_node.childrenInTraversalOrder = {1};
1804 new_root_node.childrenInHitTestOrder = {1};
1805 second_update[root_node.id] = new_root_node;
1806 bridge->UpdateSemantics(second_update, actions);
1807 id focusObject = accessibility_notifications[0][@"argument"];
1810 XCTAssertEqualObjects(focusObject, [NSNull
null]);
1811 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1812 UIAccessibilityLayoutChangedNotification);
1815 - (void)testAnnouncesLayoutChangeWhenFocusMovedOutside {
1816 flutter::MockDelegate mock_delegate;
1818 flutter::TaskRunners runners(
self.name.UTF8String,
1822 thread_task_runner);
1823 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1825 mock_delegate.settings_.enable_impeller
1831 std::make_shared<fml::SyncSwitch>());
1833 id mockFlutterView = OCMClassMock([
FlutterView class]);
1834 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1836 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1837 [[NSMutableArray alloc] init];
1838 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1839 ios_delegate->on_PostAccessibilityNotification_ =
1840 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1841 [accessibility_notifications addObject:@{
1842 @"notification" : @(notification),
1843 @"argument" : argument ? argument : [NSNull null],
1846 __block
auto bridge =
1847 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1850 std::move(ios_delegate));
1852 flutter::CustomAccessibilityActionUpdates actions;
1853 flutter::SemanticsNodeUpdates first_update;
1855 flutter::SemanticsNode node_one;
1857 node_one.label =
"route1";
1858 first_update[node_one.id] = node_one;
1859 flutter::SemanticsNode node_two;
1861 node_two.label =
"route2";
1862 first_update[node_two.id] = node_two;
1863 flutter::SemanticsNode root_node;
1865 root_node.label =
"root";
1866 root_node.childrenInTraversalOrder = {1, 2};
1867 root_node.childrenInHitTestOrder = {1, 2};
1868 first_update[root_node.id] = root_node;
1869 bridge->UpdateSemantics(first_update, actions);
1871 XCTAssertEqual([accessibility_notifications count], 0ul);
1873 bridge->AccessibilityObjectDidBecomeFocused(1);
1875 bridge->AccessibilityObjectDidLoseFocus(1);
1877 flutter::SemanticsNodeUpdates second_update;
1879 flutter::SemanticsNode new_root_node;
1881 new_root_node.label =
"root";
1882 new_root_node.childrenInTraversalOrder = {1};
1883 new_root_node.childrenInHitTestOrder = {1};
1884 second_update[root_node.id] = new_root_node;
1885 bridge->UpdateSemantics(second_update, actions);
1886 NSNull* focusObject = accessibility_notifications[0][@"argument"];
1889 XCTAssertEqual(focusObject, [NSNull
null]);
1890 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1891 UIAccessibilityLayoutChangedNotification);
1894 - (void)testAnnouncesScrollChangeWithLastFocused {
1895 flutter::MockDelegate mock_delegate;
1897 flutter::TaskRunners runners(
self.name.UTF8String,
1901 thread_task_runner);
1902 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1904 mock_delegate.settings_.enable_impeller
1910 std::make_shared<fml::SyncSwitch>());
1912 id mockFlutterView = OCMClassMock([
FlutterView class]);
1913 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1915 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1916 [[NSMutableArray alloc] init];
1917 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1918 ios_delegate->on_PostAccessibilityNotification_ =
1919 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1920 [accessibility_notifications addObject:@{
1921 @"notification" : @(notification),
1922 @"argument" : argument ? argument : [NSNull null],
1925 __block
auto bridge =
1926 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
1929 std::move(ios_delegate));
1931 flutter::CustomAccessibilityActionUpdates actions;
1932 flutter::SemanticsNodeUpdates first_update;
1934 flutter::SemanticsNode node_one;
1936 node_one.label =
"route1";
1937 node_one.scrollPosition = 0.0;
1938 first_update[node_one.id] = node_one;
1939 flutter::SemanticsNode root_node;
1941 root_node.label =
"root";
1942 root_node.childrenInTraversalOrder = {1};
1943 root_node.childrenInHitTestOrder = {1};
1944 first_update[root_node.id] = root_node;
1945 bridge->UpdateSemantics(first_update, actions);
1948 [accessibility_notifications removeAllObjects];
1951 bridge->AccessibilityObjectDidBecomeFocused(1);
1953 flutter::SemanticsNodeUpdates second_update;
1955 flutter::SemanticsNode new_node_one;
1956 new_node_one.id = 1;
1957 new_node_one.label =
"route1";
1958 new_node_one.scrollPosition = 1.0;
1959 second_update[new_node_one.id] = new_node_one;
1960 bridge->UpdateSemantics(second_update, actions);
1961 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
1964 XCTAssertEqual([focusObject uid], 1);
1965 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
1966 UIAccessibilityPageScrolledNotification);
1969 - (void)testAnnouncesScrollChangeDoesCallNativeAccessibility {
1970 flutter::MockDelegate mock_delegate;
1972 flutter::TaskRunners runners(
self.name.UTF8String,
1976 thread_task_runner);
1977 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
1979 mock_delegate.settings_.enable_impeller
1985 std::make_shared<fml::SyncSwitch>());
1987 id mockFlutterView = OCMClassMock([
FlutterView class]);
1988 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
1990 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
1991 [[NSMutableArray alloc] init];
1992 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
1993 ios_delegate->on_PostAccessibilityNotification_ =
1994 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
1995 [accessibility_notifications addObject:@{
1996 @"notification" : @(notification),
1997 @"argument" : argument ? argument : [NSNull null],
2000 __block
auto bridge =
2001 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2004 std::move(ios_delegate));
2006 flutter::CustomAccessibilityActionUpdates actions;
2007 flutter::SemanticsNodeUpdates first_update;
2009 flutter::SemanticsNode node_one;
2011 node_one.label =
"route1";
2012 node_one.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kHasImplicitScrolling);
2013 node_one.scrollPosition = 0.0;
2014 first_update[node_one.id] = node_one;
2015 flutter::SemanticsNode root_node;
2017 root_node.label =
"root";
2018 root_node.childrenInTraversalOrder = {1};
2019 root_node.childrenInHitTestOrder = {1};
2020 first_update[root_node.id] = root_node;
2021 bridge->UpdateSemantics(first_update, actions);
2024 [accessibility_notifications removeAllObjects];
2027 bridge->AccessibilityObjectDidBecomeFocused(1);
2029 flutter::SemanticsNodeUpdates second_update;
2031 flutter::SemanticsNode new_node_one;
2032 new_node_one.id = 1;
2033 new_node_one.label =
"route1";
2034 new_node_one.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kHasImplicitScrolling);
2035 new_node_one.scrollPosition = 1.0;
2036 second_update[new_node_one.id] = new_node_one;
2037 bridge->UpdateSemantics(second_update, actions);
2038 SemanticsObject* focusObject = accessibility_notifications[0][@"argument"];
2042 XCTAssertEqual([accessibility_notifications[0][
@"notification"] unsignedIntValue],
2043 UIAccessibilityPageScrolledNotification);
2046 - (void)testAnnouncesIgnoresRouteChangesWhenModal {
2047 flutter::MockDelegate mock_delegate;
2049 flutter::TaskRunners runners(
self.name.UTF8String,
2053 thread_task_runner);
2054 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2056 mock_delegate.settings_.enable_impeller
2062 std::make_shared<fml::SyncSwitch>());
2063 id mockFlutterView = OCMClassMock([
FlutterView class]);
2065 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2066 std::string label =
"some label";
2068 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2069 [[NSMutableArray alloc] init];
2070 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2071 ios_delegate->on_PostAccessibilityNotification_ =
2072 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2073 [accessibility_notifications addObject:@{
2074 @"notification" : @(notification),
2075 @"argument" : argument ? argument : [NSNull null],
2078 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2079 __block
auto bridge =
2080 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2083 std::move(ios_delegate));
2085 flutter::CustomAccessibilityActionUpdates actions;
2086 flutter::SemanticsNodeUpdates nodes;
2088 flutter::SemanticsNode route_node;
2090 route_node.flags =
static_cast<int32_t
>(flutter::SemanticsFlags::kScopesRoute) |
2091 static_cast<int32_t
>(flutter::SemanticsFlags::kNamesRoute);
2092 route_node.label =
"route";
2093 nodes[route_node.id] = route_node;
2094 flutter::SemanticsNode root_node;
2096 root_node.label = label;
2097 root_node.childrenInTraversalOrder = {1};
2098 root_node.childrenInHitTestOrder = {1};
2099 nodes[root_node.id] = root_node;
2100 bridge->UpdateSemantics(nodes, actions);
2102 XCTAssertEqual([accessibility_notifications count], 0ul);
2105 - (void)testAnnouncesIgnoresLayoutChangeWhenModal {
2106 flutter::MockDelegate mock_delegate;
2108 flutter::TaskRunners runners(
self.name.UTF8String,
2112 thread_task_runner);
2113 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2115 mock_delegate.settings_.enable_impeller
2121 std::make_shared<fml::SyncSwitch>());
2122 id mockFlutterView = OCMClassMock([
FlutterView class]);
2124 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2126 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2127 [[NSMutableArray alloc] init];
2128 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2129 ios_delegate->on_PostAccessibilityNotification_ =
2130 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2131 [accessibility_notifications addObject:@{
2132 @"notification" : @(notification),
2133 @"argument" : argument ? argument : [NSNull null],
2136 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2137 __block
auto bridge =
2138 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2141 std::move(ios_delegate));
2143 flutter::CustomAccessibilityActionUpdates actions;
2144 flutter::SemanticsNodeUpdates nodes;
2146 flutter::SemanticsNode child_node;
2148 child_node.label =
"child_node";
2149 nodes[child_node.id] = child_node;
2150 flutter::SemanticsNode root_node;
2152 root_node.label =
"root";
2153 root_node.childrenInTraversalOrder = {1};
2154 root_node.childrenInHitTestOrder = {1};
2155 nodes[root_node.id] = root_node;
2156 bridge->UpdateSemantics(nodes, actions);
2159 flutter::SemanticsNodeUpdates new_nodes;
2160 flutter::SemanticsNode new_root_node;
2162 new_root_node.label =
"root";
2163 new_nodes[new_root_node.id] = new_root_node;
2164 bridge->UpdateSemantics(new_nodes, actions);
2166 XCTAssertEqual([accessibility_notifications count], 0ul);
2169 - (void)testAnnouncesIgnoresScrollChangeWhenModal {
2170 flutter::MockDelegate mock_delegate;
2172 flutter::TaskRunners runners(
self.name.UTF8String,
2176 thread_task_runner);
2177 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2179 mock_delegate.settings_.enable_impeller
2185 std::make_shared<fml::SyncSwitch>());
2186 id mockFlutterView = OCMClassMock([
FlutterView class]);
2188 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2190 NSMutableArray<NSDictionary<NSString*, id>*>* accessibility_notifications =
2191 [[NSMutableArray alloc] init];
2192 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2193 ios_delegate->on_PostAccessibilityNotification_ =
2194 [accessibility_notifications](UIAccessibilityNotifications notification,
id argument) {
2195 [accessibility_notifications addObject:@{
2196 @"notification" : @(notification),
2197 @"argument" : argument ? argument : [NSNull null],
2200 ios_delegate->result_IsFlutterViewControllerPresentingModalViewController_ =
true;
2201 __block
auto bridge =
2202 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2205 std::move(ios_delegate));
2207 flutter::CustomAccessibilityActionUpdates actions;
2208 flutter::SemanticsNodeUpdates nodes;
2210 flutter::SemanticsNode root_node;
2212 root_node.label =
"root";
2213 root_node.scrollPosition = 1;
2214 nodes[root_node.id] = root_node;
2215 bridge->UpdateSemantics(nodes, actions);
2218 flutter::SemanticsNodeUpdates new_nodes;
2219 flutter::SemanticsNode new_root_node;
2221 new_root_node.label =
"root";
2222 new_root_node.scrollPosition = 2;
2223 new_nodes[new_root_node.id] = new_root_node;
2224 bridge->UpdateSemantics(new_nodes, actions);
2226 XCTAssertEqual([accessibility_notifications count], 0ul);
2229 - (void)testAccessibilityMessageAfterDeletion {
2230 flutter::MockDelegate mock_delegate;
2231 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2232 auto thread_task_runner = thread->GetTaskRunner();
2233 flutter::TaskRunners runners(
self.name.UTF8String,
2237 thread_task_runner);
2242 OCMStub([flutterViewController
engine]).andReturn(
engine);
2243 OCMStub([
engine binaryMessenger]).andReturn(messenger);
2245 OCMStub([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
2246 binaryMessageHandler:[OCMArg any]])
2247 .andReturn(connection);
2249 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2251 mock_delegate.settings_.enable_impeller
2257 std::make_shared<fml::SyncSwitch>());
2258 fml::AutoResetWaitableEvent latch;
2259 thread_task_runner->PostTask([&] {
2260 platform_view->SetOwnerViewController(flutterViewController);
2262 std::make_unique<flutter::AccessibilityBridge>(nil,
2265 XCTAssertTrue(bridge.get());
2266 OCMVerify([messenger setMessageHandlerOnChannel:
@"flutter/accessibility"
2267 binaryMessageHandler:[OCMArg isNotNil]]);
2272 OCMVerify([messenger cleanUpConnection:connection]);
2273 [engine stopMocking];
2276 - (void)testFlutterSemanticsScrollViewManagedObjectLifecycleCorrectly {
2277 flutter::MockDelegate mock_delegate;
2279 flutter::TaskRunners runners(
self.name.UTF8String,
2283 thread_task_runner);
2284 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2286 mock_delegate.settings_.enable_impeller
2292 std::make_shared<fml::SyncSwitch>());
2293 id mockFlutterView = OCMClassMock([
FlutterView class]);
2295 OCMStub([mockFlutterViewController view]).andReturn(mockFlutterView);
2297 auto ios_delegate = std::make_unique<flutter::MockIosDelegate>();
2298 __block
auto bridge =
2299 std::make_unique<flutter::AccessibilityBridge>(mockFlutterViewController,
2302 std::move(ios_delegate));
2311 XCTAssertTrue(flutterSemanticsScrollView);
2314 XCTAssertFalse([flutterSemanticsScrollView isAccessibilityElement]);
2317 - (void)testPlatformViewDestructorDoesNotCallSemanticsAPIs {
2318 class TestDelegate :
public flutter::MockDelegate {
2320 void OnPlatformViewSetSemanticsEnabled(
bool enabled)
override { set_semantics_enabled_calls++; }
2321 int set_semantics_enabled_calls = 0;
2324 TestDelegate test_delegate;
2325 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2326 auto thread_task_runner = thread->GetTaskRunner();
2327 flutter::TaskRunners runners(
self.name.UTF8String,
2331 thread_task_runner);
2333 fml::AutoResetWaitableEvent latch;
2334 thread_task_runner->PostTask([&] {
2335 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2337 test_delegate.settings_.enable_impeller
2343 std::make_shared<fml::SyncSwitch>());
2348 flutterPlatformViewsController.
taskRunner = thread_task_runner;
2350 OCMStub([mockFlutterViewController platformViewsController])
2351 .andReturn(flutterPlatformViewsController);
2352 platform_view->SetOwnerViewController(mockFlutterViewController);
2355 XCTAssertNotEqual(test_delegate.set_semantics_enabled_calls, 0);
2358 test_delegate.set_semantics_enabled_calls = 0;
2360 XCTAssertEqual(test_delegate.set_semantics_enabled_calls, 0);
2367 - (void)testResetsAccessibilityElementsOnHotRestart {
2368 flutter::MockDelegate mock_delegate;
2369 auto thread = std::make_unique<fml::Thread>(
"AccessibilityBridgeTest");
2370 auto thread_task_runner = thread->GetTaskRunner();
2371 flutter::TaskRunners runners(
self.name.UTF8String,
2375 thread_task_runner);
2376 id mockFlutterView = OCMClassMock([
FlutterView class]);
2378 OCMStub([mockFlutterViewController viewIfLoaded]).andReturn(mockFlutterView);
2380 fml::AutoResetWaitableEvent latch;
2381 thread_task_runner->PostTask([&] {
2382 auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
2384 mock_delegate.settings_.enable_impeller
2390 std::make_shared<fml::SyncSwitch>());
2392 platform_view->SetOwnerViewController(mockFlutterViewController);
2395 OCMExpect([mockFlutterView setAccessibilityElements:[OCMArg isNil]]);
2397 OCMVerifyAll(mockFlutterView);
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()