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)testOldParentDoesNotDetachReparentedChild {
73 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
75 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
88 XCTAssertEqual(child.
parent, newParent);
91 - (void)testSetChildrenInHitTestOrderDoesNotModifyParent {
92 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
94 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
99 traversalParent.
children = @[ child ];
100 XCTAssertEqual(child.
parent, traversalParent);
103 XCTAssertEqual(child.
parent, traversalParent);
106 XCTAssertEqual(child.
parent, traversalParent);
109 - (void)testAccessibilityHitTestFocusAtLeaf {
110 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
112 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
119 object1.
children = @[ object2, object3 ];
122 flutter::SemanticsNode node0;
124 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
128 flutter::SemanticsNode node1;
130 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
134 flutter::SemanticsNode node2;
136 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
140 flutter::SemanticsNode node3;
142 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
146 CGPoint point = CGPointMake(10, 10);
150 XCTAssertEqual(hitTestResult, object2);
153 - (void)testAccessibilityHitTestNoFocusableItem {
154 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
156 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
163 object1.
children = @[ object2, object3 ];
166 flutter::SemanticsNode node0;
168 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
171 flutter::SemanticsNode node1;
173 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
176 flutter::SemanticsNode node2;
178 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
181 flutter::SemanticsNode node3;
183 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
186 CGPoint point = CGPointMake(10, 10);
189 XCTAssertNil(hitTestResult);
192 - (void)testAccessibilityScrollToVisible {
193 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
195 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
198 flutter::SemanticsNode node3;
200 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
205 XCTAssertTrue(bridge->observations.size() == 1);
206 XCTAssertTrue(bridge->observations[0].id == 3);
207 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
210 - (void)testFlutterScrollableSemanticsObjectIsNotAccessibilityElementWhenVoiceOverIsRunning {
213 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
214 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
216 flutter::SemanticsNode node;
217 node.flags.hasImplicitScrolling =
true;
219 node.actions = flutter::kHorizontalScrollSemanticsActions |
220 static_cast<int32_t
>(flutter::SemanticsAction::kCustomAction);
222 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
223 node.scrollExtentMax = 100.0;
224 node.scrollPosition = 0.0;
233 XCTAssertFalse(scrollView.isAccessibilityElement);
236 - (void)testAccessibilityScrollToVisibleWithChild {
237 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
239 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
242 flutter::SemanticsNode node3;
244 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
249 XCTAssertTrue(bridge->observations.size() == 1);
250 XCTAssertTrue(bridge->observations[0].id == 3);
251 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
254 - (void)testAccessibilityHitTestOutOfRect {
255 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
257 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
264 object1.
children = @[ object2, object3 ];
267 flutter::SemanticsNode node0;
269 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
273 flutter::SemanticsNode node1;
275 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
279 flutter::SemanticsNode node2;
281 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
285 flutter::SemanticsNode node3;
287 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
291 CGPoint point = CGPointMake(300, 300);
294 XCTAssertNil(hitTestResult);
297 - (void)testReplaceChildAtIndex {
298 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
300 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
306 XCTAssertNil(child1.
parent);
307 XCTAssertEqual(parent, child2.
parent);
308 XCTAssertEqualObjects(parent.
children, @[ child2 ]);
311 - (void)testPlainSemanticsObjectWithLabelHasStaticTextTrait {
312 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
314 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
315 flutter::SemanticsNode node;
319 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitStaticText);
322 - (void)testPlainSemanticsObjectWithHeadingLevelHasHeaderTrait {
323 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
325 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
326 flutter::SemanticsNode node;
327 node.headingLevel = 2;
330 XCTAssertTrue(([
object accessibilityTraits] & UIAccessibilityTraitHeader) > 0);
333 - (void)testNodeWithImplicitScrollIsAnAccessibilityElementWhenItisHidden {
334 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
336 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
337 flutter::SemanticsNode node;
339 node.flags.hasImplicitScrolling =
true;
340 node.flags.isHidden =
true;
343 XCTAssertEqual(
object.isAccessibilityElement, YES);
346 - (void)testNodeWithImplicitScrollIsNotAnAccessibilityElementWhenItisNotHidden {
347 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
349 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
350 flutter::SemanticsNode node;
351 node.flags.hasImplicitScrolling =
true;
354 XCTAssertEqual(
object.isAccessibilityElement, NO);
357 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait {
358 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
360 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
361 flutter::SemanticsNode node;
367 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitNone);
370 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait1 {
371 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
373 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
374 flutter::SemanticsNode node;
376 node.flags.isTextField =
true;
379 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitNone);
382 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait2 {
383 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
385 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
386 flutter::SemanticsNode node;
389 node.flags.isButton =
true;
392 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitButton);
395 - (void)testVerticalFlutterScrollableSemanticsObject {
396 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
398 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
400 float transformScale = 0.5f;
401 float screenScale = [[bridge->view() window] screen].scale;
402 float effectivelyScale = transformScale / screenScale;
407 float scrollExtentMax = 500.0;
408 float scrollPosition = 150.0;
410 flutter::SemanticsNode node;
411 node.flags.hasImplicitScrolling =
true;
412 node.actions = flutter::kVerticalScrollSemanticsActions;
413 node.rect = SkRect::MakeXYWH(x, y, w, h);
414 node.scrollExtentMax = scrollExtentMax;
415 node.scrollPosition = scrollPosition;
417 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
424 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
425 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
426 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
428 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
431 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
433 XCTAssertEqualWithAccuracy(scrollView.contentSize.height,
436 XCTAssertEqual(scrollView.contentOffset.x, 0);
437 XCTAssertEqualWithAccuracy(scrollView.contentOffset.y, scrollPosition * effectivelyScale,
441 - (void)testVerticalFlutterScrollableSemanticsObjectNoWindowDoesNotCrash {
442 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
444 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
446 float transformScale = 0.5f;
451 float scrollExtentMax = 500.0;
452 float scrollPosition = 150.0;
454 flutter::SemanticsNode node;
455 node.flags.hasImplicitScrolling =
true;
456 node.actions = flutter::kVerticalScrollSemanticsActions;
457 node.rect = SkRect::MakeXYWH(x, y, w, h);
458 node.scrollExtentMax = scrollExtentMax;
459 node.scrollPosition = scrollPosition;
461 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
466 XCTAssertNoThrow([scrollable accessibilityBridgeDidFinishUpdate]);
469 - (void)testHorizontalFlutterScrollableSemanticsObject {
470 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
472 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
474 float transformScale = 0.5f;
475 float screenScale = [[bridge->view() window] screen].scale;
476 float effectivelyScale = transformScale / screenScale;
481 float scrollExtentMax = 500.0;
482 float scrollPosition = 150.0;
484 flutter::SemanticsNode node;
485 node.flags.hasImplicitScrolling =
true;
486 node.actions = flutter::kHorizontalScrollSemanticsActions;
487 node.rect = SkRect::MakeXYWH(x, y, w, h);
488 node.scrollExtentMax = scrollExtentMax;
489 node.scrollPosition = scrollPosition;
491 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
498 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
499 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
500 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
502 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
505 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, (w + scrollExtentMax) * effectivelyScale,
507 XCTAssertEqualWithAccuracy(scrollView.contentSize.height, h * effectivelyScale,
510 XCTAssertEqualWithAccuracy(scrollView.contentOffset.x, scrollPosition * effectivelyScale,
512 XCTAssertEqual(scrollView.contentOffset.y, 0);
515 - (void)testCanHandleInfiniteScrollExtent {
516 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
518 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
520 float transformScale = 0.5f;
521 float screenScale = [[bridge->view() window] screen].scale;
522 float effectivelyScale = transformScale / screenScale;
527 float scrollExtentMax = INFINITY;
528 float scrollPosition = 150.0;
530 flutter::SemanticsNode node;
531 node.flags.hasImplicitScrolling =
true;
532 node.actions = flutter::kVerticalScrollSemanticsActions;
533 node.rect = SkRect::MakeXYWH(x, y, w, h);
534 node.scrollExtentMax = scrollExtentMax;
535 node.scrollPosition = scrollPosition;
537 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
543 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
544 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
545 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
547 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
550 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
552 XCTAssertEqualWithAccuracy(scrollView.contentSize.height,
556 XCTAssertEqual(scrollView.contentOffset.x, 0);
557 XCTAssertEqualWithAccuracy(scrollView.contentOffset.y, scrollPosition * effectivelyScale,
561 - (void)testCanHandleNaNScrollExtentAndScrollPoisition {
562 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
564 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
566 float transformScale = 0.5f;
567 float screenScale = [[bridge->view() window] screen].scale;
568 float effectivelyScale = transformScale / screenScale;
573 float scrollExtentMax = std::nan(
"");
574 float scrollPosition = std::nan(
"");
576 flutter::SemanticsNode node;
577 node.flags.hasImplicitScrolling =
true;
578 node.actions = flutter::kVerticalScrollSemanticsActions;
579 node.rect = SkRect::MakeXYWH(x, y, w, h);
580 node.scrollExtentMax = scrollExtentMax;
581 node.scrollPosition = scrollPosition;
583 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
590 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
591 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
592 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
594 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
598 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
600 XCTAssertEqualWithAccuracy(scrollView.contentSize.height, h * effectivelyScale,
603 XCTAssertEqual(scrollView.contentOffset.x, 0);
604 XCTAssertEqual(scrollView.contentOffset.y, 0);
607 - (void)testFlutterScrollableSemanticsObjectIsNotHittestable {
608 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
610 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
612 flutter::SemanticsNode node;
613 node.flags.hasImplicitScrolling =
true;
614 node.actions = flutter::kHorizontalScrollSemanticsActions;
615 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
616 node.scrollExtentMax = 100.0;
617 node.scrollPosition = 0.0;
624 XCTAssertEqual([scrollView hitTest:CGPointMake(10, 10) withEvent:nil], nil);
627 - (void)testFlutterScrollableSemanticsObjectIsHiddenWhenVoiceOverIsRunning {
630 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
631 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
633 flutter::SemanticsNode node;
634 node.flags.hasImplicitScrolling =
true;
635 node.actions = flutter::kHorizontalScrollSemanticsActions;
636 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
637 node.scrollExtentMax = 100.0;
638 node.scrollPosition = 0.0;
645 XCTAssertTrue(scrollView.isAccessibilityElement);
647 XCTAssertFalse(scrollView.isAccessibilityElement);
650 - (void)testFlutterSemanticsObjectHasIdentifier {
653 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
654 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
656 flutter::SemanticsNode node;
657 node.identifier =
"identifier";
661 XCTAssertTrue([
object.accessibilityIdentifier isEqualToString:
@"identifier"]);
664 - (void)testFlutterSemanticsObjectHasLocale {
667 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
668 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
670 flutter::SemanticsNode node;
671 node.locale =
"es-MX";
675 XCTAssertTrue([
object.accessibilityLanguage isEqualToString:
@"es-MX"]);
678 - (void)testFlutterSemanticsObjectUseDefaultLocale {
681 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
682 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
684 flutter::SemanticsNode node;
689 XCTAssertTrue([
object.accessibilityLanguage isEqualToString:
@"es-MX"]);
692 - (void)testFlutterSemanticsObjectPrioritizedSectionLocale {
695 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
696 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
698 flutter::SemanticsNode node;
701 node.locale =
"zh-TW";
706 XCTAssertTrue([
object.accessibilityLanguage isEqualToString:
@"zh-TW"]);
709 - (void)testFlutterSemanticsObjectLocaleNil {
712 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
713 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
715 flutter::SemanticsNode node;
719 XCTAssertTrue(
object.accessibilityLanguage == nil);
722 - (void)testFlutterScrollableSemanticsObjectWithLabelValueHintIsNotHiddenWhenVoiceOverIsRunning {
725 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
726 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
728 flutter::SemanticsNode node;
729 node.flags.hasImplicitScrolling =
true;
730 node.actions = flutter::kHorizontalScrollSemanticsActions;
731 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
732 node.label =
"label";
733 node.value =
"value";
735 node.scrollExtentMax = 100.0;
736 node.scrollPosition = 0.0;
743 XCTAssertTrue(scrollView.isAccessibilityElement);
745 [scrollView.accessibilityLabel isEqualToString:NSLocalizedString(
@"label",
@"test")]);
747 [scrollView.accessibilityValue isEqualToString:NSLocalizedString(
@"value",
@"test")]);
748 XCTAssertTrue([scrollView.accessibilityHint isEqualToString:NSLocalizedString(
@"hint",
@"test")]);
751 - (void)testFlutterSemanticsObjectMergeTooltipToLabel {
754 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
755 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
757 flutter::SemanticsNode node;
758 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
759 node.label =
"label";
760 node.tooltip =
"tooltip";
763 XCTAssertTrue(
object.isAccessibilityElement);
764 XCTAssertTrue([
object.accessibilityLabel isEqualToString:
@"label\ntooltip"]);
767 - (void)testSemanticsObjectContainerAccessibilityFrameCoversEntireScreen {
770 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
771 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
773 flutter::SemanticsNode parent;
775 parent.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
777 flutter::SemanticsNode child;
779 child.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
780 child.rect = SkRect::MakeXYWH(0, 0, 100, 100);
781 parent.childrenInTraversalOrder.push_back(1);
791 parentObject.
children = @[ childObject ];
798 XCTAssertTrue(childObject.accessibilityRespondsToUserInteraction);
799 XCTAssertTrue(CGRectEqualToRect(container.accessibilityFrame, UIScreen.mainScreen.bounds));
802 - (void)testFlutterSemanticsObjectAttributedStringsDoNotCrashWhenEmpty {
805 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
806 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
808 flutter::SemanticsNode node;
809 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
812 XCTAssertTrue(
object.accessibilityAttributedLabel == nil);
815 - (void)testFlutterScrollableSemanticsObjectReturnsParentContainerIfNoChildren {
818 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
819 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
821 flutter::SemanticsNode parent;
823 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
824 parent.label =
"label";
825 parent.value =
"value";
826 parent.hint =
"hint";
828 flutter::SemanticsNode node;
830 node.flags.hasImplicitScrolling =
true;
831 node.actions = flutter::kHorizontalScrollSemanticsActions;
832 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
833 node.label =
"label";
834 node.value =
"value";
836 node.scrollExtentMax = 100.0;
837 node.scrollPosition = 0.0;
838 parent.childrenInTraversalOrder.push_back(1);
849 parentObject.
children = @[ scrollable ];
852 XCTAssertTrue(scrollView.isAccessibilityElement);
858 - (void)testFlutterScrollableSemanticsObjectNoScrollBarOrContentInsets {
859 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
861 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
863 flutter::SemanticsNode node;
864 node.flags.hasImplicitScrolling =
true;
865 node.actions = flutter::kHorizontalScrollSemanticsActions;
866 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
867 node.scrollExtentMax = 100.0;
868 node.scrollPosition = 0.0;
876 XCTAssertFalse(scrollView.showsHorizontalScrollIndicator);
877 XCTAssertFalse(scrollView.showsVerticalScrollIndicator);
878 XCTAssertEqual(scrollView.contentInsetAdjustmentBehavior,
879 UIScrollViewContentInsetAdjustmentNever);
880 XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(scrollView.contentInset, UIEdgeInsetsZero));
883 - (void)testSemanticsObjectBuildsAttributedString {
884 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
886 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
887 flutter::SemanticsNode node;
888 node.label =
"label";
889 std::shared_ptr<flutter::SpellOutStringAttribute> attribute =
890 std::make_shared<flutter::SpellOutStringAttribute>();
891 attribute->start = 1;
893 attribute->type = flutter::StringAttributeType::kSpellOut;
894 node.labelAttributes.push_back(attribute);
895 node.value =
"value";
896 attribute = std::make_shared<flutter::SpellOutStringAttribute>();
897 attribute->start = 2;
899 attribute->type = flutter::StringAttributeType::kSpellOut;
900 node.valueAttributes.push_back(attribute);
902 std::shared_ptr<flutter::LocaleStringAttribute> local_attribute =
903 std::make_shared<flutter::LocaleStringAttribute>();
904 local_attribute->start = 3;
905 local_attribute->end = 4;
906 local_attribute->type = flutter::StringAttributeType::kLocale;
907 local_attribute->locale =
"en-MX";
908 node.hintAttributes.push_back(local_attribute);
911 NSMutableAttributedString* expectedAttributedLabel =
912 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"label", @"test")];
913 NSDictionary* attributeDict = @{
914 UIAccessibilitySpeechAttributeSpellOut : @YES,
916 [expectedAttributedLabel setAttributes:attributeDict range:NSMakeRange(1, 1)];
918 [
object.accessibilityAttributedLabel isEqualToAttributedString:expectedAttributedLabel]);
920 NSMutableAttributedString* expectedAttributedValue =
921 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"value", @"test")];
923 UIAccessibilitySpeechAttributeSpellOut : @YES,
925 [expectedAttributedValue setAttributes:attributeDict range:NSMakeRange(2, 1)];
927 [
object.accessibilityAttributedValue isEqualToAttributedString:expectedAttributedValue]);
929 NSMutableAttributedString* expectedAttributedHint =
930 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"hint", @"test")];
932 UIAccessibilitySpeechAttributeLanguage :
@"en-MX",
934 [expectedAttributedHint setAttributes:attributeDict range:NSMakeRange(3, 1)];
936 [
object.accessibilityAttributedHint isEqualToAttributedString:expectedAttributedHint]);
939 - (void)testShouldTriggerAnnouncement {
940 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
942 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
946 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:nil]);
949 flutter::SemanticsNode node;
950 node.flags.isLiveRegion =
true;
952 XCTAssertTrue([
object nodeShouldTriggerAnnouncement:&node]);
956 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:nil]);
959 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:&node]);
962 flutter::SemanticsNode updatedNode;
963 updatedNode.flags.isLiveRegion =
true;
964 updatedNode.label =
"bar";
965 XCTAssertTrue([
object nodeShouldTriggerAnnouncement:&updatedNode]);
968 updatedNode.flags = flutter::SemanticsFlags{};
969 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:&updatedNode]);
972 updatedNode.label =
"foo";
974 XCTAssertTrue([
object nodeShouldTriggerAnnouncement:&node]);
977 - (void)testShouldDispatchShowOnScreenActionForHeader {
978 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
980 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
984 flutter::SemanticsNode node;
985 node.flags.isHeader =
true;
991 [object accessibilityElementDidBecomeFocused];
993 XCTAssertTrue(bridge->observations.size() == 1);
994 XCTAssertTrue(bridge->observations[0].id == 1);
995 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
998 - (void)testShouldDispatchShowOnScreenActionForHidden {
999 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
1001 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1005 flutter::SemanticsNode node;
1006 node.flags.isHidden =
true;
1012 [object accessibilityElementDidBecomeFocused];
1014 XCTAssertTrue(bridge->observations.size() == 1);
1015 XCTAssertTrue(bridge->observations[0].id == 1);
1016 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
1019 - (void)testFlutterSwitchSemanticsObjectMatchesUISwitch {
1020 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
1022 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1027 flutter::SemanticsNode node;
1028 node.flags.isToggled = flutter::SemanticsTristate::kTrue;
1029 node.flags.isEnabled = flutter::SemanticsTristate::kTrue;
1033 UISwitch* nativeSwitch = [[UISwitch alloc] init];
1034 nativeSwitch.on = YES;
1036 XCTAssertEqual(
object.accessibilityTraits, nativeSwitch.accessibilityTraits);
1037 XCTAssertEqualObjects(
object.accessibilityValue, nativeSwitch.accessibilityValue);
1040 flutter::SemanticsNode update;
1041 update.flags.isToggled = flutter::SemanticsTristate::kFalse;
1042 update.flags.isEnabled = flutter::SemanticsTristate::kTrue;
1044 update.label =
"foo";
1047 nativeSwitch.on = NO;
1049 XCTAssertEqual(
object.accessibilityTraits, nativeSwitch.accessibilityTraits);
1050 XCTAssertEqualObjects(
object.accessibilityValue, nativeSwitch.accessibilityValue);
1053 - (void)testFlutterSemanticsObjectOfRadioButton {
1054 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
1056 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1060 flutter::SemanticsNode node;
1061 node.flags.isInMutuallyExclusiveGroup =
true;
1062 node.flags.isChecked = flutter::SemanticsCheckState::kFalse;
1063 node.flags.isEnabled = flutter::SemanticsTristate::kTrue;
1066 XCTAssertTrue((
object.accessibilityTraits & UIAccessibilityTraitButton) > 0);
1067 XCTAssertNil(
object.accessibilityValue);
1070 - (void)testFlutterSwitchSemanticsObjectMatchesUISwitchDisabled {
1071 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
1073 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1078 flutter::SemanticsNode node;
1079 node.flags.isToggled = flutter::SemanticsTristate::kTrue;
1083 UISwitch* nativeSwitch = [[UISwitch alloc] init];
1084 nativeSwitch.on = YES;
1085 nativeSwitch.enabled = NO;
1087 XCTAssertEqual(
object.accessibilityTraits, nativeSwitch.accessibilityTraits);
1088 XCTAssertEqualObjects(
object.accessibilityValue, nativeSwitch.accessibilityValue);
1091 - (void)testSemanticsObjectDeallocated {
1092 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1094 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1102 XCTAssertNil(weakObject);
1105 - (void)testFlutterSemanticsObjectReturnsNilContainerWhenBridgeIsNotAlive {
1110 flutter::SemanticsNode parent;
1112 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1113 parent.label =
"label";
1114 parent.value =
"value";
1115 parent.hint =
"hint";
1117 flutter::SemanticsNode node;
1119 node.flags.hasImplicitScrolling =
true;
1120 node.actions = flutter::kHorizontalScrollSemanticsActions;
1121 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1122 node.label =
"label";
1123 node.value =
"value";
1125 node.scrollExtentMax = 100.0;
1126 node.scrollPosition = 0.0;
1127 parent.childrenInTraversalOrder.push_back(1);
1129 flutter::SemanticsNode node2;
1131 node2.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1132 node2.label =
"label";
1133 node2.value =
"value";
1134 node2.hint =
"hint";
1135 node2.scrollExtentMax = 100.0;
1136 node2.scrollPosition = 0.0;
1137 parent.childrenInTraversalOrder.push_back(2);
1143 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
1144 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1156 parentObject.
children = @[ scrollable, object2 ];
1171 XCTAssertNil(scrollable.accessibilityContainer);
1172 XCTAssertNil(object2.accessibilityContainer);
1175 - (void)testAccessibilityHitTestSearchCanReturnPlatformView {
1176 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1178 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1187 platformView:platformView];
1191 object1.
children = @[ platformViewSemanticsContainer, object3 ];
1194 flutter::SemanticsNode node0;
1196 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1200 flutter::SemanticsNode node1;
1202 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1206 flutter::SemanticsNode node2;
1208 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
1212 flutter::SemanticsNode node3;
1214 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1218 CGPoint point = CGPointMake(10, 10);
1221 XCTAssertEqual(hitTestResult, platformView);
1224 - (void)testFlutterPlatformViewSemanticsContainer {
1225 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
1227 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1232 weakPlatformView = platformView;
1238 platformView:platformView];
1239 weakContainer = container;
1241 XCTAssertNotNil(weakPlatformView);
1242 XCTAssertNotNil(weakContainer);
1246 XCTAssertNotNil(weakPlatformView);
1247 XCTAssertNotNil(weakContainer);
1251 XCTAssertNil(weakPlatformView);
1252 XCTAssertNil(weakContainer);
1255 - (void)testTextInputSemanticsObject {
1256 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1258 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1260 flutter::SemanticsNode node;
1262 node.flags.isTextField =
true;
1263 node.flags.isReadOnly =
true;
1267 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitNone);
1270 - (void)testTextInputSemanticsObject_canPerformAction {
1271 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1273 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1275 flutter::SemanticsNode node;
1277 node.flags.isTextField =
true;
1278 node.flags.isReadOnly =
true;
1283 id textInputSurrogate = OCMClassMock([UIResponder
class]);
1284 id partialSemanticsObject = OCMPartialMock(
object);
1285 OCMStub([partialSemanticsObject textInputSurrogate]).andReturn(textInputSurrogate);
1287 OCMExpect([textInputSurrogate canPerformAction:[OCMArg anySelector] withSender:OCMOCK_ANY])
1289 XCTAssertTrue([partialSemanticsObject canPerformAction:
@selector(copy:) withSender:nil]);
1291 OCMExpect([textInputSurrogate canPerformAction:[OCMArg anySelector] withSender:OCMOCK_ANY])
1293 XCTAssertFalse([partialSemanticsObject canPerformAction:
@selector(copy:) withSender:nil]);
1296 - (void)testTextInputSemanticsObject_editActions {
1297 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1299 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1301 flutter::SemanticsNode node;
1304 node.flags.isTextField =
true;
1305 node.flags.isReadOnly =
true;
1310 id textInputSurrogate = OCMClassMock([UIResponder
class]);
1311 id partialSemanticsObject = OCMPartialMock(
object);
1312 OCMStub([partialSemanticsObject textInputSurrogate]).andReturn(textInputSurrogate);
1314 XCTestExpectation* copyExpectation =
1315 [
self expectationWithDescription:@"Surrogate's copy method is called."];
1316 XCTestExpectation* cutExpectation =
1317 [
self expectationWithDescription:@"Surrogate's cut method is called."];
1318 XCTestExpectation* pasteExpectation =
1319 [
self expectationWithDescription:@"Surrogate's paste method is called."];
1320 XCTestExpectation* selectAllExpectation =
1321 [
self expectationWithDescription:@"Surrogate's selectAll method is called."];
1322 XCTestExpectation* deleteExpectation =
1323 [
self expectationWithDescription:@"Surrogate's delete method is called."];
1325 OCMStub([textInputSurrogate copy:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1326 [copyExpectation fulfill];
1328 OCMStub([textInputSurrogate cut:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1329 [cutExpectation fulfill];
1331 OCMStub([textInputSurrogate paste:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1332 [pasteExpectation fulfill];
1334 OCMStub([textInputSurrogate selectAll:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1335 [selectAllExpectation fulfill];
1337 OCMStub([textInputSurrogate
delete:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1338 [deleteExpectation fulfill];
1341 [partialSemanticsObject copy:nil];
1342 [partialSemanticsObject cut:nil];
1343 [partialSemanticsObject paste:nil];
1344 [partialSemanticsObject selectAll:nil];
1345 [partialSemanticsObject delete:nil];
1347 [
self waitForExpectationsWithTimeout:1 handler:nil];
1350 - (void)testSliderSemanticsObject {
1351 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1353 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1355 flutter::SemanticsNode node;
1356 node.flags.isSlider =
true;
1360 XCTAssertEqual([
object accessibilityActivate], YES);
1363 - (void)testUIFocusItemConformance {
1364 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1366 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1372 XCTAssertTrue([parent.parentFocusEnvironment isKindOfClass:[UIView
class]]);
1373 XCTAssertEqual(child.parentFocusEnvironment, child.
parent);
1376 flutter::SemanticsNode childNode;
1377 childNode.flags.isHidden =
true;
1378 childNode.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
1380 XCTAssertFalse(child.canBecomeFocused);
1381 childNode.flags = flutter::SemanticsFlags{};
1383 XCTAssertTrue(child.canBecomeFocused);
1384 childNode.actions = 0;
1386 XCTAssertFalse(child.canBecomeFocused);
1388 CGFloat scale = ((bridge->view().window.screen ?: UIScreen.mainScreen)).scale;
1390 childNode.rect = SkRect::MakeXYWH(0, 0, 100 * scale, 100 * scale);
1392 flutter::SemanticsNode parentNode;
1393 parentNode.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1396 XCTAssertTrue(CGRectEqualToRect(child.frame, CGRectMake(0, 0, 100, 100)));
1399 - (void)testUIFocusItemContainerConformance {
1400 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1402 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1409 NSArray<id<UIFocusItem>>* itemsInRect = [parent focusItemsInRect:CGRectMake(0, 0, 100, 100)];
1410 XCTAssertEqual(itemsInRect.count, (
unsigned long)2);
1411 XCTAssertTrue([itemsInRect containsObject:child1]);
1412 XCTAssertTrue([itemsInRect containsObject:child2]);
1415 - (void)testUIFocusItemScrollableContainerConformance {
1416 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1418 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1423 CGPoint p = CGPointMake(123.0, 456.0);
1424 [scrollable.scrollView scrollViewWillEndDragging:scrollable.scrollView
1425 withVelocity:CGPointZero
1426 targetContentOffset:&p];
1428 [scrollable.scrollView scrollViewDidEndDecelerating:scrollable.scrollView];
1429 XCTAssertEqual(bridge->observations.size(), (
size_t)1);
1430 XCTAssertEqual(bridge->observations[0].id, 5);
1431 XCTAssertEqual(bridge->observations[0].action, flutter::SemanticsAction::kScrollToOffset);
1433 std::vector<uint8_t> args = bridge->observations[0].args;
1434 XCTAssertEqual(args.size(), 3 *
sizeof(CGFloat));
1436 NSData* encoded = [NSData dataWithBytes:args.data() length:args.size()];
1438 CGPoint point = CGPointZero;
1439 memcpy(&point, decoded.
data.bytes, decoded.
data.length);
1440 XCTAssertTrue(CGPointEqualToPoint(point, p));
1443 - (void)testUIFocusItemScrollableContainerNoFeedbackLoops {
1444 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1446 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1451 const CGPoint p = CGPointMake(0.0, 456.0);
1453 bridge->observations.clear();
1455 const SkScalar scrollPosition = p.y + 0.0000000000000001;
1456 flutter::SemanticsNode node;
1457 node.flags.hasImplicitScrolling =
true;
1458 node.actions = flutter::kVerticalScrollSemanticsActions;
1459 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1460 node.scrollExtentMax = 10000;
1461 node.scrollPosition = scrollPosition;
1462 node.transform = {1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, scrollPosition, 0, 1.0};
1466 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()