5 #import <OCMock/OCMock.h>
6 #import <XCTest/XCTest.h>
24 UIFocusItemScrollableContainer>
37 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
39 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
41 XCTAssertNotNil(
object);
44 - (void)testUIFocusSystemMethodsDoNotCrashWhenBridgeIsDead {
45 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge;
48 auto mock_bridge = std::make_unique<flutter::testing::MockAccessibilityBridge>();
49 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock_bridge.get());
50 bridge = factory.GetWeakPtr();
55 XCTAssertNil([
object parentFocusEnvironment]);
56 XCTAssertNil([
object coordinateSpace]);
57 XCTAssertTrue(CGRectEqualToRect([
object frame], CGRectZero));
60 - (void)testSetChildren {
61 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
63 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
67 XCTAssertEqual(parent, child.
parent);
69 XCTAssertNil(child.
parent);
72 - (void)testAccessibilityHitTestFocusAtLeaf {
73 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
75 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
82 object1.
children = @[ object2, object3 ];
85 flutter::SemanticsNode node0;
87 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
91 flutter::SemanticsNode node1;
93 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
97 flutter::SemanticsNode node2;
99 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
103 flutter::SemanticsNode node3;
105 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
109 CGPoint point = CGPointMake(10, 10);
113 XCTAssertEqual(hitTestResult, object2);
116 - (void)testAccessibilityHitTestNoFocusableItem {
117 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
119 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
126 object1.
children = @[ object2, object3 ];
129 flutter::SemanticsNode node0;
131 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
134 flutter::SemanticsNode node1;
136 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
139 flutter::SemanticsNode node2;
141 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
144 flutter::SemanticsNode node3;
146 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
149 CGPoint point = CGPointMake(10, 10);
152 XCTAssertNil(hitTestResult);
155 - (void)testAccessibilityScrollToVisible {
156 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
158 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
161 flutter::SemanticsNode node3;
163 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
168 XCTAssertTrue(bridge->observations.size() == 1);
169 XCTAssertTrue(bridge->observations[0].id == 3);
170 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
173 - (void)testFlutterScrollableSemanticsObjectIsNotAccessibilityElementWhenVoiceOverIsRunning {
176 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
177 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
179 flutter::SemanticsNode node;
180 node.flags.hasImplicitScrolling =
true;
182 node.actions = flutter::kHorizontalScrollSemanticsActions |
183 static_cast<int32_t
>(flutter::SemanticsAction::kCustomAction);
185 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
186 node.scrollExtentMax = 100.0;
187 node.scrollPosition = 0.0;
196 XCTAssertFalse(scrollView.isAccessibilityElement);
199 - (void)testAccessibilityScrollToVisibleWithChild {
200 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
202 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
205 flutter::SemanticsNode node3;
207 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
212 XCTAssertTrue(bridge->observations.size() == 1);
213 XCTAssertTrue(bridge->observations[0].id == 3);
214 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
217 - (void)testAccessibilityHitTestOutOfRect {
218 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
220 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
227 object1.
children = @[ object2, object3 ];
230 flutter::SemanticsNode node0;
232 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
236 flutter::SemanticsNode node1;
238 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
242 flutter::SemanticsNode node2;
244 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
248 flutter::SemanticsNode node3;
250 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
254 CGPoint point = CGPointMake(300, 300);
257 XCTAssertNil(hitTestResult);
260 - (void)testReplaceChildAtIndex {
261 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
263 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
269 XCTAssertNil(child1.
parent);
270 XCTAssertEqual(parent, child2.
parent);
271 XCTAssertEqualObjects(parent.
children, @[ child2 ]);
274 - (void)testPlainSemanticsObjectWithLabelHasStaticTextTrait {
275 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
277 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
278 flutter::SemanticsNode node;
282 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitStaticText);
285 - (void)testPlainSemanticsObjectWithHeadingLevelHasHeaderTrait {
286 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
288 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
289 flutter::SemanticsNode node;
290 node.headingLevel = 2;
293 XCTAssertTrue(([
object accessibilityTraits] & UIAccessibilityTraitHeader) > 0);
296 - (void)testNodeWithImplicitScrollIsAnAccessibilityElementWhenItisHidden {
297 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
299 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
300 flutter::SemanticsNode node;
302 node.flags.hasImplicitScrolling =
true;
303 node.flags.isHidden =
true;
306 XCTAssertEqual(
object.isAccessibilityElement, YES);
309 - (void)testNodeWithImplicitScrollIsNotAnAccessibilityElementWhenItisNotHidden {
310 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
312 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
313 flutter::SemanticsNode node;
314 node.flags.hasImplicitScrolling =
true;
317 XCTAssertEqual(
object.isAccessibilityElement, NO);
320 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait {
321 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
323 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
324 flutter::SemanticsNode node;
330 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitNone);
333 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait1 {
334 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
336 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
337 flutter::SemanticsNode node;
339 node.flags.isTextField =
true;
342 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitNone);
345 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait2 {
346 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
348 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
349 flutter::SemanticsNode node;
352 node.flags.isButton =
true;
355 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitButton);
358 - (void)testVerticalFlutterScrollableSemanticsObject {
359 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
361 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
363 float transformScale = 0.5f;
364 float screenScale = [[bridge->view() window] screen].scale;
365 float effectivelyScale = transformScale / screenScale;
370 float scrollExtentMax = 500.0;
371 float scrollPosition = 150.0;
373 flutter::SemanticsNode node;
374 node.flags.hasImplicitScrolling =
true;
375 node.actions = flutter::kVerticalScrollSemanticsActions;
376 node.rect = SkRect::MakeXYWH(x, y, w, h);
377 node.scrollExtentMax = scrollExtentMax;
378 node.scrollPosition = scrollPosition;
380 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
387 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
388 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
389 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
391 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
394 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
396 XCTAssertEqualWithAccuracy(scrollView.contentSize.height,
399 XCTAssertEqual(scrollView.contentOffset.x, 0);
400 XCTAssertEqualWithAccuracy(scrollView.contentOffset.y, scrollPosition * effectivelyScale,
404 - (void)testVerticalFlutterScrollableSemanticsObjectNoWindowDoesNotCrash {
405 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
407 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
409 float transformScale = 0.5f;
414 float scrollExtentMax = 500.0;
415 float scrollPosition = 150.0;
417 flutter::SemanticsNode node;
418 node.flags.hasImplicitScrolling =
true;
419 node.actions = flutter::kVerticalScrollSemanticsActions;
420 node.rect = SkRect::MakeXYWH(x, y, w, h);
421 node.scrollExtentMax = scrollExtentMax;
422 node.scrollPosition = scrollPosition;
424 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
429 XCTAssertNoThrow([scrollable accessibilityBridgeDidFinishUpdate]);
432 - (void)testHorizontalFlutterScrollableSemanticsObject {
433 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
435 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
437 float transformScale = 0.5f;
438 float screenScale = [[bridge->view() window] screen].scale;
439 float effectivelyScale = transformScale / screenScale;
444 float scrollExtentMax = 500.0;
445 float scrollPosition = 150.0;
447 flutter::SemanticsNode node;
448 node.flags.hasImplicitScrolling =
true;
449 node.actions = flutter::kHorizontalScrollSemanticsActions;
450 node.rect = SkRect::MakeXYWH(x, y, w, h);
451 node.scrollExtentMax = scrollExtentMax;
452 node.scrollPosition = scrollPosition;
454 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
461 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
462 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
463 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
465 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
468 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, (w + scrollExtentMax) * effectivelyScale,
470 XCTAssertEqualWithAccuracy(scrollView.contentSize.height, h * effectivelyScale,
473 XCTAssertEqualWithAccuracy(scrollView.contentOffset.x, scrollPosition * effectivelyScale,
475 XCTAssertEqual(scrollView.contentOffset.y, 0);
478 - (void)testCanHandleInfiniteScrollExtent {
479 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
481 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
483 float transformScale = 0.5f;
484 float screenScale = [[bridge->view() window] screen].scale;
485 float effectivelyScale = transformScale / screenScale;
490 float scrollExtentMax = INFINITY;
491 float scrollPosition = 150.0;
493 flutter::SemanticsNode node;
494 node.flags.hasImplicitScrolling =
true;
495 node.actions = flutter::kVerticalScrollSemanticsActions;
496 node.rect = SkRect::MakeXYWH(x, y, w, h);
497 node.scrollExtentMax = scrollExtentMax;
498 node.scrollPosition = scrollPosition;
500 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
506 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
507 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
508 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
510 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
513 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
515 XCTAssertEqualWithAccuracy(scrollView.contentSize.height,
519 XCTAssertEqual(scrollView.contentOffset.x, 0);
520 XCTAssertEqualWithAccuracy(scrollView.contentOffset.y, scrollPosition * effectivelyScale,
524 - (void)testCanHandleNaNScrollExtentAndScrollPoisition {
525 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
527 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
529 float transformScale = 0.5f;
530 float screenScale = [[bridge->view() window] screen].scale;
531 float effectivelyScale = transformScale / screenScale;
536 float scrollExtentMax = std::nan(
"");
537 float scrollPosition = std::nan(
"");
539 flutter::SemanticsNode node;
540 node.flags.hasImplicitScrolling =
true;
541 node.actions = flutter::kVerticalScrollSemanticsActions;
542 node.rect = SkRect::MakeXYWH(x, y, w, h);
543 node.scrollExtentMax = scrollExtentMax;
544 node.scrollPosition = scrollPosition;
546 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
553 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
554 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
555 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
557 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
561 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
563 XCTAssertEqualWithAccuracy(scrollView.contentSize.height, h * effectivelyScale,
566 XCTAssertEqual(scrollView.contentOffset.x, 0);
567 XCTAssertEqual(scrollView.contentOffset.y, 0);
570 - (void)testFlutterScrollableSemanticsObjectIsNotHittestable {
571 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
573 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
575 flutter::SemanticsNode node;
576 node.flags.hasImplicitScrolling =
true;
577 node.actions = flutter::kHorizontalScrollSemanticsActions;
578 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
579 node.scrollExtentMax = 100.0;
580 node.scrollPosition = 0.0;
587 XCTAssertEqual([scrollView hitTest:CGPointMake(10, 10) withEvent:nil], nil);
590 - (void)testFlutterScrollableSemanticsObjectIsHiddenWhenVoiceOverIsRunning {
593 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
594 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
596 flutter::SemanticsNode node;
597 node.flags.hasImplicitScrolling =
true;
598 node.actions = flutter::kHorizontalScrollSemanticsActions;
599 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
600 node.scrollExtentMax = 100.0;
601 node.scrollPosition = 0.0;
608 XCTAssertTrue(scrollView.isAccessibilityElement);
610 XCTAssertFalse(scrollView.isAccessibilityElement);
613 - (void)testFlutterSemanticsObjectHasIdentifier {
616 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
617 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
619 flutter::SemanticsNode node;
620 node.identifier =
"identifier";
624 XCTAssertTrue([
object.accessibilityIdentifier isEqualToString:
@"identifier"]);
627 - (void)testFlutterSemanticsObjectHasLocale {
630 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
631 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
633 flutter::SemanticsNode node;
634 node.locale =
"es-MX";
638 XCTAssertTrue([
object.accessibilityLanguage isEqualToString:
@"es-MX"]);
641 - (void)testFlutterSemanticsObjectUseDefaultLocale {
644 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
645 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
647 flutter::SemanticsNode node;
652 XCTAssertTrue([
object.accessibilityLanguage isEqualToString:
@"es-MX"]);
655 - (void)testFlutterSemanticsObjectPrioritizedSectionLocale {
658 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
659 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
661 flutter::SemanticsNode node;
664 node.locale =
"zh-TW";
669 XCTAssertTrue([
object.accessibilityLanguage isEqualToString:
@"zh-TW"]);
672 - (void)testFlutterSemanticsObjectLocaleNil {
675 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
676 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
678 flutter::SemanticsNode node;
682 XCTAssertTrue(
object.accessibilityLanguage == nil);
685 - (void)testFlutterScrollableSemanticsObjectWithLabelValueHintIsNotHiddenWhenVoiceOverIsRunning {
688 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
689 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
691 flutter::SemanticsNode node;
692 node.flags.hasImplicitScrolling =
true;
693 node.actions = flutter::kHorizontalScrollSemanticsActions;
694 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
695 node.label =
"label";
696 node.value =
"value";
698 node.scrollExtentMax = 100.0;
699 node.scrollPosition = 0.0;
706 XCTAssertTrue(scrollView.isAccessibilityElement);
708 [scrollView.accessibilityLabel isEqualToString:NSLocalizedString(
@"label",
@"test")]);
710 [scrollView.accessibilityValue isEqualToString:NSLocalizedString(
@"value",
@"test")]);
711 XCTAssertTrue([scrollView.accessibilityHint isEqualToString:NSLocalizedString(
@"hint",
@"test")]);
714 - (void)testFlutterSemanticsObjectMergeTooltipToLabel {
717 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
718 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
720 flutter::SemanticsNode node;
721 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
722 node.label =
"label";
723 node.tooltip =
"tooltip";
726 XCTAssertTrue(
object.isAccessibilityElement);
727 XCTAssertTrue([
object.accessibilityLabel isEqualToString:
@"label\ntooltip"]);
730 - (void)testSemanticsObjectContainerAccessibilityFrameCoversEntireScreen {
733 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
734 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
736 flutter::SemanticsNode parent;
738 parent.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
740 flutter::SemanticsNode child;
742 child.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
743 child.rect = SkRect::MakeXYWH(0, 0, 100, 100);
744 parent.childrenInTraversalOrder.push_back(1);
754 parentObject.
children = @[ childObject ];
761 XCTAssertTrue(childObject.accessibilityRespondsToUserInteraction);
762 XCTAssertTrue(CGRectEqualToRect(container.accessibilityFrame, UIScreen.mainScreen.bounds));
765 - (void)testFlutterSemanticsObjectAttributedStringsDoNotCrashWhenEmpty {
768 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
769 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
771 flutter::SemanticsNode node;
772 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
775 XCTAssertTrue(
object.accessibilityAttributedLabel == nil);
778 - (void)testFlutterScrollableSemanticsObjectReturnsParentContainerIfNoChildren {
781 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
782 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
784 flutter::SemanticsNode parent;
786 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
787 parent.label =
"label";
788 parent.value =
"value";
789 parent.hint =
"hint";
791 flutter::SemanticsNode node;
793 node.flags.hasImplicitScrolling =
true;
794 node.actions = flutter::kHorizontalScrollSemanticsActions;
795 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
796 node.label =
"label";
797 node.value =
"value";
799 node.scrollExtentMax = 100.0;
800 node.scrollPosition = 0.0;
801 parent.childrenInTraversalOrder.push_back(1);
812 parentObject.
children = @[ scrollable ];
815 XCTAssertTrue(scrollView.isAccessibilityElement);
821 - (void)testFlutterScrollableSemanticsObjectNoScrollBarOrContentInsets {
822 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
824 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
826 flutter::SemanticsNode node;
827 node.flags.hasImplicitScrolling =
true;
828 node.actions = flutter::kHorizontalScrollSemanticsActions;
829 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
830 node.scrollExtentMax = 100.0;
831 node.scrollPosition = 0.0;
839 XCTAssertFalse(scrollView.showsHorizontalScrollIndicator);
840 XCTAssertFalse(scrollView.showsVerticalScrollIndicator);
841 XCTAssertEqual(scrollView.contentInsetAdjustmentBehavior,
842 UIScrollViewContentInsetAdjustmentNever);
843 XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(scrollView.contentInset, UIEdgeInsetsZero));
846 - (void)testSemanticsObjectBuildsAttributedString {
847 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
849 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
850 flutter::SemanticsNode node;
851 node.label =
"label";
852 std::shared_ptr<flutter::SpellOutStringAttribute> attribute =
853 std::make_shared<flutter::SpellOutStringAttribute>();
854 attribute->start = 1;
856 attribute->type = flutter::StringAttributeType::kSpellOut;
857 node.labelAttributes.push_back(attribute);
858 node.value =
"value";
859 attribute = std::make_shared<flutter::SpellOutStringAttribute>();
860 attribute->start = 2;
862 attribute->type = flutter::StringAttributeType::kSpellOut;
863 node.valueAttributes.push_back(attribute);
865 std::shared_ptr<flutter::LocaleStringAttribute> local_attribute =
866 std::make_shared<flutter::LocaleStringAttribute>();
867 local_attribute->start = 3;
868 local_attribute->end = 4;
869 local_attribute->type = flutter::StringAttributeType::kLocale;
870 local_attribute->locale =
"en-MX";
871 node.hintAttributes.push_back(local_attribute);
874 NSMutableAttributedString* expectedAttributedLabel =
875 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"label", @"test")];
876 NSDictionary* attributeDict = @{
877 UIAccessibilitySpeechAttributeSpellOut : @YES,
879 [expectedAttributedLabel setAttributes:attributeDict range:NSMakeRange(1, 1)];
881 [
object.accessibilityAttributedLabel isEqualToAttributedString:expectedAttributedLabel]);
883 NSMutableAttributedString* expectedAttributedValue =
884 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"value", @"test")];
886 UIAccessibilitySpeechAttributeSpellOut : @YES,
888 [expectedAttributedValue setAttributes:attributeDict range:NSMakeRange(2, 1)];
890 [
object.accessibilityAttributedValue isEqualToAttributedString:expectedAttributedValue]);
892 NSMutableAttributedString* expectedAttributedHint =
893 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"hint", @"test")];
895 UIAccessibilitySpeechAttributeLanguage :
@"en-MX",
897 [expectedAttributedHint setAttributes:attributeDict range:NSMakeRange(3, 1)];
899 [
object.accessibilityAttributedHint isEqualToAttributedString:expectedAttributedHint]);
902 - (void)testShouldTriggerAnnouncement {
903 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
905 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
909 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:nil]);
912 flutter::SemanticsNode node;
913 node.flags.isLiveRegion =
true;
915 XCTAssertTrue([
object nodeShouldTriggerAnnouncement:&node]);
919 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:nil]);
922 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:&node]);
925 flutter::SemanticsNode updatedNode;
926 updatedNode.flags.isLiveRegion =
true;
927 updatedNode.label =
"bar";
928 XCTAssertTrue([
object nodeShouldTriggerAnnouncement:&updatedNode]);
931 updatedNode.flags = flutter::SemanticsFlags{};
932 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:&updatedNode]);
935 updatedNode.label =
"foo";
937 XCTAssertTrue([
object nodeShouldTriggerAnnouncement:&node]);
940 - (void)testShouldDispatchShowOnScreenActionForHeader {
941 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
943 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
947 flutter::SemanticsNode node;
948 node.flags.isHeader =
true;
954 [object accessibilityElementDidBecomeFocused];
956 XCTAssertTrue(bridge->observations.size() == 1);
957 XCTAssertTrue(bridge->observations[0].id == 1);
958 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
961 - (void)testShouldDispatchShowOnScreenActionForHidden {
962 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
964 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
968 flutter::SemanticsNode node;
969 node.flags.isHidden =
true;
975 [object accessibilityElementDidBecomeFocused];
977 XCTAssertTrue(bridge->observations.size() == 1);
978 XCTAssertTrue(bridge->observations[0].id == 1);
979 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
982 - (void)testFlutterSwitchSemanticsObjectMatchesUISwitch {
983 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
985 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
990 flutter::SemanticsNode node;
991 node.flags.isToggled = flutter::SemanticsTristate::kTrue;
992 node.flags.isEnabled = flutter::SemanticsTristate::kTrue;
996 UISwitch* nativeSwitch = [[UISwitch alloc] init];
997 nativeSwitch.on = YES;
999 XCTAssertEqual(
object.accessibilityTraits, nativeSwitch.accessibilityTraits);
1000 XCTAssertEqualObjects(
object.accessibilityValue, nativeSwitch.accessibilityValue);
1003 flutter::SemanticsNode update;
1004 update.flags.isToggled = flutter::SemanticsTristate::kFalse;
1005 update.flags.isEnabled = flutter::SemanticsTristate::kTrue;
1007 update.label =
"foo";
1010 nativeSwitch.on = NO;
1012 XCTAssertEqual(
object.accessibilityTraits, nativeSwitch.accessibilityTraits);
1013 XCTAssertEqualObjects(
object.accessibilityValue, nativeSwitch.accessibilityValue);
1016 - (void)testFlutterSemanticsObjectOfRadioButton {
1017 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
1019 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1023 flutter::SemanticsNode node;
1024 node.flags.isInMutuallyExclusiveGroup =
true;
1025 node.flags.isChecked = flutter::SemanticsCheckState::kFalse;
1026 node.flags.isEnabled = flutter::SemanticsTristate::kTrue;
1029 XCTAssertTrue((
object.accessibilityTraits & UIAccessibilityTraitButton) > 0);
1030 XCTAssertNil(
object.accessibilityValue);
1033 - (void)testFlutterSwitchSemanticsObjectMatchesUISwitchDisabled {
1034 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
1036 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1041 flutter::SemanticsNode node;
1042 node.flags.isToggled = flutter::SemanticsTristate::kTrue;
1046 UISwitch* nativeSwitch = [[UISwitch alloc] init];
1047 nativeSwitch.on = YES;
1048 nativeSwitch.enabled = NO;
1050 XCTAssertEqual(
object.accessibilityTraits, nativeSwitch.accessibilityTraits);
1051 XCTAssertEqualObjects(
object.accessibilityValue, nativeSwitch.accessibilityValue);
1054 - (void)testSemanticsObjectDeallocated {
1055 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1057 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1065 XCTAssertNil(weakObject);
1068 - (void)testFlutterSemanticsObjectReturnsNilContainerWhenBridgeIsNotAlive {
1073 flutter::SemanticsNode parent;
1075 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1076 parent.label =
"label";
1077 parent.value =
"value";
1078 parent.hint =
"hint";
1080 flutter::SemanticsNode node;
1082 node.flags.hasImplicitScrolling =
true;
1083 node.actions = flutter::kHorizontalScrollSemanticsActions;
1084 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1085 node.label =
"label";
1086 node.value =
"value";
1088 node.scrollExtentMax = 100.0;
1089 node.scrollPosition = 0.0;
1090 parent.childrenInTraversalOrder.push_back(1);
1092 flutter::SemanticsNode node2;
1094 node2.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1095 node2.label =
"label";
1096 node2.value =
"value";
1097 node2.hint =
"hint";
1098 node2.scrollExtentMax = 100.0;
1099 node2.scrollPosition = 0.0;
1100 parent.childrenInTraversalOrder.push_back(2);
1106 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
1107 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1119 parentObject.
children = @[ scrollable, object2 ];
1134 XCTAssertNil(scrollable.accessibilityContainer);
1135 XCTAssertNil(object2.accessibilityContainer);
1138 - (void)testAccessibilityHitTestSearchCanReturnPlatformView {
1139 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1141 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1150 platformView:platformView];
1154 object1.
children = @[ platformViewSemanticsContainer, object3 ];
1157 flutter::SemanticsNode node0;
1159 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1163 flutter::SemanticsNode node1;
1165 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1169 flutter::SemanticsNode node2;
1171 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
1175 flutter::SemanticsNode node3;
1177 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1181 CGPoint point = CGPointMake(10, 10);
1184 XCTAssertEqual(hitTestResult, platformView);
1187 - (void)testFlutterPlatformViewSemanticsContainer {
1188 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
1190 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1195 weakPlatformView = platformView;
1201 platformView:platformView];
1202 weakContainer = container;
1204 XCTAssertNotNil(weakPlatformView);
1205 XCTAssertNotNil(weakContainer);
1209 XCTAssertNotNil(weakPlatformView);
1210 XCTAssertNotNil(weakContainer);
1214 XCTAssertNil(weakPlatformView);
1215 XCTAssertNil(weakContainer);
1218 - (void)testTextInputSemanticsObject {
1219 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1221 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1223 flutter::SemanticsNode node;
1225 node.flags.isTextField =
true;
1226 node.flags.isReadOnly =
true;
1230 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitNone);
1233 - (void)testTextInputSemanticsObject_canPerformAction {
1234 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1236 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1238 flutter::SemanticsNode node;
1240 node.flags.isTextField =
true;
1241 node.flags.isReadOnly =
true;
1246 id textInputSurrogate = OCMClassMock([UIResponder
class]);
1247 id partialSemanticsObject = OCMPartialMock(
object);
1248 OCMStub([partialSemanticsObject textInputSurrogate]).andReturn(textInputSurrogate);
1250 OCMExpect([textInputSurrogate canPerformAction:[OCMArg anySelector] withSender:OCMOCK_ANY])
1252 XCTAssertTrue([partialSemanticsObject canPerformAction:
@selector(copy:) withSender:nil]);
1254 OCMExpect([textInputSurrogate canPerformAction:[OCMArg anySelector] withSender:OCMOCK_ANY])
1256 XCTAssertFalse([partialSemanticsObject canPerformAction:
@selector(copy:) withSender:nil]);
1259 - (void)testTextInputSemanticsObject_editActions {
1260 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1262 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1264 flutter::SemanticsNode node;
1267 node.flags.isTextField =
true;
1268 node.flags.isReadOnly =
true;
1273 id textInputSurrogate = OCMClassMock([UIResponder
class]);
1274 id partialSemanticsObject = OCMPartialMock(
object);
1275 OCMStub([partialSemanticsObject textInputSurrogate]).andReturn(textInputSurrogate);
1277 XCTestExpectation* copyExpectation =
1278 [
self expectationWithDescription:@"Surrogate's copy method is called."];
1279 XCTestExpectation* cutExpectation =
1280 [
self expectationWithDescription:@"Surrogate's cut method is called."];
1281 XCTestExpectation* pasteExpectation =
1282 [
self expectationWithDescription:@"Surrogate's paste method is called."];
1283 XCTestExpectation* selectAllExpectation =
1284 [
self expectationWithDescription:@"Surrogate's selectAll method is called."];
1285 XCTestExpectation* deleteExpectation =
1286 [
self expectationWithDescription:@"Surrogate's delete method is called."];
1288 OCMStub([textInputSurrogate copy:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1289 [copyExpectation fulfill];
1291 OCMStub([textInputSurrogate cut:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1292 [cutExpectation fulfill];
1294 OCMStub([textInputSurrogate paste:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1295 [pasteExpectation fulfill];
1297 OCMStub([textInputSurrogate selectAll:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1298 [selectAllExpectation fulfill];
1300 OCMStub([textInputSurrogate
delete:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1301 [deleteExpectation fulfill];
1304 [partialSemanticsObject copy:nil];
1305 [partialSemanticsObject cut:nil];
1306 [partialSemanticsObject paste:nil];
1307 [partialSemanticsObject selectAll:nil];
1308 [partialSemanticsObject delete:nil];
1310 [
self waitForExpectationsWithTimeout:1 handler:nil];
1313 - (void)testSliderSemanticsObject {
1314 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1316 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1318 flutter::SemanticsNode node;
1319 node.flags.isSlider =
true;
1323 XCTAssertEqual([
object accessibilityActivate], YES);
1326 - (void)testUIFocusItemConformance {
1327 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1329 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1335 XCTAssertTrue([parent.parentFocusEnvironment isKindOfClass:[UIView
class]]);
1336 XCTAssertEqual(child.parentFocusEnvironment, child.
parent);
1339 flutter::SemanticsNode childNode;
1340 childNode.flags.isHidden =
true;
1341 childNode.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
1343 XCTAssertFalse(child.canBecomeFocused);
1344 childNode.flags = flutter::SemanticsFlags{};
1346 XCTAssertTrue(child.canBecomeFocused);
1347 childNode.actions = 0;
1349 XCTAssertFalse(child.canBecomeFocused);
1351 CGFloat scale = ((bridge->view().window.screen ?: UIScreen.mainScreen)).scale;
1353 childNode.rect = SkRect::MakeXYWH(0, 0, 100 * scale, 100 * scale);
1355 flutter::SemanticsNode parentNode;
1356 parentNode.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1359 XCTAssertTrue(CGRectEqualToRect(child.frame, CGRectMake(0, 0, 100, 100)));
1362 - (void)testUIFocusItemContainerConformance {
1363 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1365 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1372 NSArray<id<UIFocusItem>>* itemsInRect = [parent focusItemsInRect:CGRectMake(0, 0, 100, 100)];
1373 XCTAssertEqual(itemsInRect.count, (
unsigned long)2);
1374 XCTAssertTrue([itemsInRect containsObject:child1]);
1375 XCTAssertTrue([itemsInRect containsObject:child2]);
1378 - (void)testUIFocusItemScrollableContainerConformance {
1379 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1381 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1386 CGPoint p = CGPointMake(123.0, 456.0);
1387 [scrollable.scrollView scrollViewWillEndDragging:scrollable.scrollView
1388 withVelocity:CGPointZero
1389 targetContentOffset:&p];
1391 [scrollable.scrollView scrollViewDidEndDecelerating:scrollable.scrollView];
1392 XCTAssertEqual(bridge->observations.size(), (
size_t)1);
1393 XCTAssertEqual(bridge->observations[0].id, 5);
1394 XCTAssertEqual(bridge->observations[0].action, flutter::SemanticsAction::kScrollToOffset);
1396 std::vector<uint8_t> args = bridge->observations[0].args;
1397 XCTAssertEqual(args.size(), 3 *
sizeof(CGFloat));
1399 NSData* encoded = [NSData dataWithBytes:args.data() length:args.size()];
1401 CGPoint point = CGPointZero;
1402 memcpy(&point, decoded.
data.bytes, decoded.
data.length);
1403 XCTAssertTrue(CGPointEqualToPoint(point, p));
1406 - (void)testUIFocusItemScrollableContainerNoFeedbackLoops {
1407 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1409 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1414 const CGPoint p = CGPointMake(0.0, 456.0);
1416 bridge->observations.clear();
1418 const SkScalar scrollPosition = p.y + 0.0000000000000001;
1419 flutter::SemanticsNode node;
1420 node.flags.hasImplicitScrolling =
true;
1421 node.actions = flutter::kVerticalScrollSemanticsActions;
1422 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1423 node.scrollExtentMax = 10000;
1424 node.scrollPosition = scrollPosition;
1425 node.transform = {1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, scrollPosition, 0, 1.0};
1429 XCTAssertEqual(bridge->observations.size(), (
size_t)0);
constexpr float kScrollExtentMaxForInf
FLUTTER_ASSERT_ARC const float kFloatCompareEpsilon
UIView< UITextInput > * textInputSurrogate()
id accessibilityContainer()
bool isVoiceOverRunningValue
SemanticsObject * semanticsObject
id _accessibilityHitTest:withEvent:(CGPoint point,[withEvent] UIEvent *event)
NSArray< SemanticsObject * > * childrenInHitTestOrder
BOOL accessibilityScrollToVisibleWithChild:(id child)
void accessibilityBridgeDidFinishUpdate()
BOOL accessibilityScrollToVisible()
NSArray< SemanticsObject * > * children
void replaceChildAtIndex:withChild:(NSInteger index,[withChild] SemanticsObject *child)
void setSemanticsNode:(const flutter::SemanticsNode *NS_REQUIRES_SUPER)
instancetype sharedInstance()