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)testSetChildren {
45 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
47 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
51 XCTAssertEqual(parent, child.
parent);
53 XCTAssertNil(child.
parent);
56 - (void)testAccessibilityHitTestFocusAtLeaf {
57 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
59 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
66 object1.
children = @[ object2, object3 ];
69 flutter::SemanticsNode node0;
71 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
75 flutter::SemanticsNode node1;
77 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
81 flutter::SemanticsNode node2;
83 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
87 flutter::SemanticsNode node3;
89 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
93 CGPoint point = CGPointMake(10, 10);
97 XCTAssertEqual(hitTestResult, object2);
100 - (void)testAccessibilityHitTestNoFocusableItem {
101 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
103 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
110 object1.
children = @[ object2, object3 ];
113 flutter::SemanticsNode node0;
115 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
118 flutter::SemanticsNode node1;
120 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
123 flutter::SemanticsNode node2;
125 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
128 flutter::SemanticsNode node3;
130 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
133 CGPoint point = CGPointMake(10, 10);
136 XCTAssertNil(hitTestResult);
139 - (void)testAccessibilityScrollToVisible {
140 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
142 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
145 flutter::SemanticsNode node3;
147 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
152 XCTAssertTrue(bridge->observations.size() == 1);
153 XCTAssertTrue(bridge->observations[0].id == 3);
154 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
157 - (void)testFlutterScrollableSemanticsObjectIsNotAccessibilityElementWhenVoiceOverIsRunning {
160 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
161 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
163 flutter::SemanticsNode node;
164 node.flags.hasImplicitScrolling =
true;
166 node.actions = flutter::kHorizontalScrollSemanticsActions |
167 static_cast<int32_t
>(flutter::SemanticsAction::kCustomAction);
169 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
170 node.scrollExtentMax = 100.0;
171 node.scrollPosition = 0.0;
180 XCTAssertFalse(scrollView.isAccessibilityElement);
183 - (void)testAccessibilityScrollToVisibleWithChild {
184 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
186 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
189 flutter::SemanticsNode node3;
191 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
196 XCTAssertTrue(bridge->observations.size() == 1);
197 XCTAssertTrue(bridge->observations[0].id == 3);
198 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
201 - (void)testAccessibilityHitTestOutOfRect {
202 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
204 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
211 object1.
children = @[ object2, object3 ];
214 flutter::SemanticsNode node0;
216 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
220 flutter::SemanticsNode node1;
222 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
226 flutter::SemanticsNode node2;
228 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
232 flutter::SemanticsNode node3;
234 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
238 CGPoint point = CGPointMake(300, 300);
241 XCTAssertNil(hitTestResult);
244 - (void)testReplaceChildAtIndex {
245 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
247 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
253 XCTAssertNil(child1.
parent);
254 XCTAssertEqual(parent, child2.
parent);
255 XCTAssertEqualObjects(parent.
children, @[ child2 ]);
258 - (void)testPlainSemanticsObjectWithLabelHasStaticTextTrait {
259 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
261 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
262 flutter::SemanticsNode node;
266 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitStaticText);
269 - (void)testNodeWithImplicitScrollIsAnAccessibilityElementWhenItisHidden {
270 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
272 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
273 flutter::SemanticsNode node;
275 node.flags.hasImplicitScrolling =
true;
276 node.flags.isHidden =
true;
279 XCTAssertEqual(
object.isAccessibilityElement, YES);
282 - (void)testNodeWithImplicitScrollIsNotAnAccessibilityElementWhenItisNotHidden {
283 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
285 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
286 flutter::SemanticsNode node;
287 node.flags.hasImplicitScrolling =
true;
290 XCTAssertEqual(
object.isAccessibilityElement, NO);
293 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait {
294 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
296 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
297 flutter::SemanticsNode node;
303 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitNone);
306 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait1 {
307 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
309 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
310 flutter::SemanticsNode node;
312 node.flags.isTextField =
true;
315 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitNone);
318 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait2 {
319 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
321 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
322 flutter::SemanticsNode node;
325 node.flags.isButton =
true;
328 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitButton);
331 - (void)testVerticalFlutterScrollableSemanticsObject {
332 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
334 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
336 float transformScale = 0.5f;
337 float screenScale = [[bridge->view() window] screen].scale;
338 float effectivelyScale = transformScale / screenScale;
343 float scrollExtentMax = 500.0;
344 float scrollPosition = 150.0;
346 flutter::SemanticsNode node;
347 node.flags.hasImplicitScrolling =
true;
348 node.actions = flutter::kVerticalScrollSemanticsActions;
349 node.rect = SkRect::MakeXYWH(x, y, w, h);
350 node.scrollExtentMax = scrollExtentMax;
351 node.scrollPosition = scrollPosition;
353 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
360 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
361 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
362 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
364 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
367 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
369 XCTAssertEqualWithAccuracy(scrollView.contentSize.height,
372 XCTAssertEqual(scrollView.contentOffset.x, 0);
373 XCTAssertEqualWithAccuracy(scrollView.contentOffset.y, scrollPosition * effectivelyScale,
377 - (void)testVerticalFlutterScrollableSemanticsObjectNoWindowDoesNotCrash {
378 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
380 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
382 float transformScale = 0.5f;
387 float scrollExtentMax = 500.0;
388 float scrollPosition = 150.0;
390 flutter::SemanticsNode node;
391 node.flags.hasImplicitScrolling =
true;
392 node.actions = flutter::kVerticalScrollSemanticsActions;
393 node.rect = SkRect::MakeXYWH(x, y, w, h);
394 node.scrollExtentMax = scrollExtentMax;
395 node.scrollPosition = scrollPosition;
397 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
402 XCTAssertNoThrow([scrollable accessibilityBridgeDidFinishUpdate]);
405 - (void)testHorizontalFlutterScrollableSemanticsObject {
406 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
408 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
410 float transformScale = 0.5f;
411 float screenScale = [[bridge->view() window] screen].scale;
412 float effectivelyScale = transformScale / screenScale;
417 float scrollExtentMax = 500.0;
418 float scrollPosition = 150.0;
420 flutter::SemanticsNode node;
421 node.flags.hasImplicitScrolling =
true;
422 node.actions = flutter::kHorizontalScrollSemanticsActions;
423 node.rect = SkRect::MakeXYWH(x, y, w, h);
424 node.scrollExtentMax = scrollExtentMax;
425 node.scrollPosition = scrollPosition;
427 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
434 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
435 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
436 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
438 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
441 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, (w + scrollExtentMax) * effectivelyScale,
443 XCTAssertEqualWithAccuracy(scrollView.contentSize.height, h * effectivelyScale,
446 XCTAssertEqualWithAccuracy(scrollView.contentOffset.x, scrollPosition * effectivelyScale,
448 XCTAssertEqual(scrollView.contentOffset.y, 0);
451 - (void)testCanHandleInfiniteScrollExtent {
452 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
454 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
456 float transformScale = 0.5f;
457 float screenScale = [[bridge->view() window] screen].scale;
458 float effectivelyScale = transformScale / screenScale;
463 float scrollExtentMax = INFINITY;
464 float scrollPosition = 150.0;
466 flutter::SemanticsNode node;
467 node.flags.hasImplicitScrolling =
true;
468 node.actions = flutter::kVerticalScrollSemanticsActions;
469 node.rect = SkRect::MakeXYWH(x, y, w, h);
470 node.scrollExtentMax = scrollExtentMax;
471 node.scrollPosition = scrollPosition;
473 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
479 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
480 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
481 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
483 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
486 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
488 XCTAssertEqualWithAccuracy(scrollView.contentSize.height,
492 XCTAssertEqual(scrollView.contentOffset.x, 0);
493 XCTAssertEqualWithAccuracy(scrollView.contentOffset.y, scrollPosition * effectivelyScale,
497 - (void)testCanHandleNaNScrollExtentAndScrollPoisition {
498 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
500 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
502 float transformScale = 0.5f;
503 float screenScale = [[bridge->view() window] screen].scale;
504 float effectivelyScale = transformScale / screenScale;
509 float scrollExtentMax = std::nan(
"");
510 float scrollPosition = std::nan(
"");
512 flutter::SemanticsNode node;
513 node.flags.hasImplicitScrolling =
true;
514 node.actions = flutter::kVerticalScrollSemanticsActions;
515 node.rect = SkRect::MakeXYWH(x, y, w, h);
516 node.scrollExtentMax = scrollExtentMax;
517 node.scrollPosition = scrollPosition;
519 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
526 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
527 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
528 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
530 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
534 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
536 XCTAssertEqualWithAccuracy(scrollView.contentSize.height, h * effectivelyScale,
539 XCTAssertEqual(scrollView.contentOffset.x, 0);
540 XCTAssertEqual(scrollView.contentOffset.y, 0);
543 - (void)testFlutterScrollableSemanticsObjectIsNotHittestable {
544 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
546 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
548 flutter::SemanticsNode node;
549 node.flags.hasImplicitScrolling =
true;
550 node.actions = flutter::kHorizontalScrollSemanticsActions;
551 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
552 node.scrollExtentMax = 100.0;
553 node.scrollPosition = 0.0;
560 XCTAssertEqual([scrollView hitTest:CGPointMake(10, 10) withEvent:nil], nil);
563 - (void)testFlutterScrollableSemanticsObjectIsHiddenWhenVoiceOverIsRunning {
566 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
567 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
569 flutter::SemanticsNode node;
570 node.flags.hasImplicitScrolling =
true;
571 node.actions = flutter::kHorizontalScrollSemanticsActions;
572 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
573 node.scrollExtentMax = 100.0;
574 node.scrollPosition = 0.0;
581 XCTAssertTrue(scrollView.isAccessibilityElement);
583 XCTAssertFalse(scrollView.isAccessibilityElement);
586 - (void)testFlutterSemanticsObjectHasIdentifier {
589 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
590 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
592 flutter::SemanticsNode node;
593 node.identifier =
"identifier";
597 XCTAssertTrue([
object.accessibilityIdentifier isEqualToString:
@"identifier"]);
600 - (void)testFlutterSemanticsObjectHasLocale {
603 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
604 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
606 flutter::SemanticsNode node;
607 node.locale =
"es-MX";
611 XCTAssertTrue([
object.accessibilityLanguage isEqualToString:
@"es-MX"]);
614 - (void)testFlutterSemanticsObjectUseDefaultLocale {
617 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
618 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
620 flutter::SemanticsNode node;
625 XCTAssertTrue([
object.accessibilityLanguage isEqualToString:
@"es-MX"]);
628 - (void)testFlutterSemanticsObjectPrioritizedSectionLocale {
631 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
632 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
634 flutter::SemanticsNode node;
637 node.locale =
"zh-TW";
642 XCTAssertTrue([
object.accessibilityLanguage isEqualToString:
@"zh-TW"]);
645 - (void)testFlutterSemanticsObjectLocaleNil {
648 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
649 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
651 flutter::SemanticsNode node;
655 XCTAssertTrue(
object.accessibilityLanguage == nil);
658 - (void)testFlutterScrollableSemanticsObjectWithLabelValueHintIsNotHiddenWhenVoiceOverIsRunning {
661 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
662 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
664 flutter::SemanticsNode node;
665 node.flags.hasImplicitScrolling =
true;
666 node.actions = flutter::kHorizontalScrollSemanticsActions;
667 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
668 node.label =
"label";
669 node.value =
"value";
671 node.scrollExtentMax = 100.0;
672 node.scrollPosition = 0.0;
679 XCTAssertTrue(scrollView.isAccessibilityElement);
681 [scrollView.accessibilityLabel isEqualToString:NSLocalizedString(
@"label",
@"test")]);
683 [scrollView.accessibilityValue isEqualToString:NSLocalizedString(
@"value",
@"test")]);
684 XCTAssertTrue([scrollView.accessibilityHint isEqualToString:NSLocalizedString(
@"hint",
@"test")]);
687 - (void)testFlutterSemanticsObjectMergeTooltipToLabel {
690 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
691 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
693 flutter::SemanticsNode node;
694 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
695 node.label =
"label";
696 node.tooltip =
"tooltip";
699 XCTAssertTrue(
object.isAccessibilityElement);
700 XCTAssertTrue([
object.accessibilityLabel isEqualToString:
@"label\ntooltip"]);
703 - (void)testSemanticsObjectContainerAccessibilityFrameCoversEntireScreen {
706 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
707 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
709 flutter::SemanticsNode parent;
711 parent.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
713 flutter::SemanticsNode child;
715 child.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
716 child.rect = SkRect::MakeXYWH(0, 0, 100, 100);
717 parent.childrenInTraversalOrder.push_back(1);
727 parentObject.
children = @[ childObject ];
734 XCTAssertTrue(childObject.accessibilityRespondsToUserInteraction);
735 XCTAssertTrue(CGRectEqualToRect(container.accessibilityFrame, UIScreen.mainScreen.bounds));
738 - (void)testFlutterSemanticsObjectAttributedStringsDoNotCrashWhenEmpty {
741 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
742 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
744 flutter::SemanticsNode node;
745 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
748 XCTAssertTrue(
object.accessibilityAttributedLabel == nil);
751 - (void)testFlutterScrollableSemanticsObjectReturnsParentContainerIfNoChildren {
754 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
755 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
757 flutter::SemanticsNode parent;
759 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
760 parent.label =
"label";
761 parent.value =
"value";
762 parent.hint =
"hint";
764 flutter::SemanticsNode node;
766 node.flags.hasImplicitScrolling =
true;
767 node.actions = flutter::kHorizontalScrollSemanticsActions;
768 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
769 node.label =
"label";
770 node.value =
"value";
772 node.scrollExtentMax = 100.0;
773 node.scrollPosition = 0.0;
774 parent.childrenInTraversalOrder.push_back(1);
785 parentObject.
children = @[ scrollable ];
788 XCTAssertTrue(scrollView.isAccessibilityElement);
794 - (void)testFlutterScrollableSemanticsObjectNoScrollBarOrContentInsets {
795 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
797 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
799 flutter::SemanticsNode node;
800 node.flags.hasImplicitScrolling =
true;
801 node.actions = flutter::kHorizontalScrollSemanticsActions;
802 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
803 node.scrollExtentMax = 100.0;
804 node.scrollPosition = 0.0;
812 XCTAssertFalse(scrollView.showsHorizontalScrollIndicator);
813 XCTAssertFalse(scrollView.showsVerticalScrollIndicator);
814 XCTAssertEqual(scrollView.contentInsetAdjustmentBehavior,
815 UIScrollViewContentInsetAdjustmentNever);
816 XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(scrollView.contentInset, UIEdgeInsetsZero));
819 - (void)testSemanticsObjectBuildsAttributedString {
820 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
822 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
823 flutter::SemanticsNode node;
824 node.label =
"label";
825 std::shared_ptr<flutter::SpellOutStringAttribute> attribute =
826 std::make_shared<flutter::SpellOutStringAttribute>();
827 attribute->start = 1;
829 attribute->type = flutter::StringAttributeType::kSpellOut;
830 node.labelAttributes.push_back(attribute);
831 node.value =
"value";
832 attribute = std::make_shared<flutter::SpellOutStringAttribute>();
833 attribute->start = 2;
835 attribute->type = flutter::StringAttributeType::kSpellOut;
836 node.valueAttributes.push_back(attribute);
838 std::shared_ptr<flutter::LocaleStringAttribute> local_attribute =
839 std::make_shared<flutter::LocaleStringAttribute>();
840 local_attribute->start = 3;
841 local_attribute->end = 4;
842 local_attribute->type = flutter::StringAttributeType::kLocale;
843 local_attribute->locale =
"en-MX";
844 node.hintAttributes.push_back(local_attribute);
847 NSMutableAttributedString* expectedAttributedLabel =
848 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"label", @"test")];
849 NSDictionary* attributeDict = @{
850 UIAccessibilitySpeechAttributeSpellOut : @YES,
852 [expectedAttributedLabel setAttributes:attributeDict range:NSMakeRange(1, 1)];
854 [
object.accessibilityAttributedLabel isEqualToAttributedString:expectedAttributedLabel]);
856 NSMutableAttributedString* expectedAttributedValue =
857 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"value", @"test")];
859 UIAccessibilitySpeechAttributeSpellOut : @YES,
861 [expectedAttributedValue setAttributes:attributeDict range:NSMakeRange(2, 1)];
863 [
object.accessibilityAttributedValue isEqualToAttributedString:expectedAttributedValue]);
865 NSMutableAttributedString* expectedAttributedHint =
866 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"hint", @"test")];
868 UIAccessibilitySpeechAttributeLanguage :
@"en-MX",
870 [expectedAttributedHint setAttributes:attributeDict range:NSMakeRange(3, 1)];
872 [
object.accessibilityAttributedHint isEqualToAttributedString:expectedAttributedHint]);
875 - (void)testShouldTriggerAnnouncement {
876 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
878 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
882 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:nil]);
885 flutter::SemanticsNode node;
886 node.flags.isLiveRegion =
true;
888 XCTAssertTrue([
object nodeShouldTriggerAnnouncement:&node]);
892 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:nil]);
895 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:&node]);
898 flutter::SemanticsNode updatedNode;
899 updatedNode.flags.isLiveRegion =
true;
900 updatedNode.label =
"bar";
901 XCTAssertTrue([
object nodeShouldTriggerAnnouncement:&updatedNode]);
904 updatedNode.flags = flutter::SemanticsFlags{};
905 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:&updatedNode]);
908 updatedNode.label =
"foo";
910 XCTAssertTrue([
object nodeShouldTriggerAnnouncement:&node]);
913 - (void)testShouldDispatchShowOnScreenActionForHeader {
914 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
916 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
920 flutter::SemanticsNode node;
921 node.flags.isHeader =
true;
927 [object accessibilityElementDidBecomeFocused];
929 XCTAssertTrue(bridge->observations.size() == 1);
930 XCTAssertTrue(bridge->observations[0].id == 1);
931 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
934 - (void)testShouldDispatchShowOnScreenActionForHidden {
935 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
937 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
941 flutter::SemanticsNode node;
942 node.flags.isHidden =
true;
948 [object accessibilityElementDidBecomeFocused];
950 XCTAssertTrue(bridge->observations.size() == 1);
951 XCTAssertTrue(bridge->observations[0].id == 1);
952 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
955 - (void)testFlutterSwitchSemanticsObjectMatchesUISwitch {
956 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
958 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
963 flutter::SemanticsNode node;
964 node.flags.isToggled = flutter::SemanticsTristate::kTrue;
965 node.flags.isEnabled = flutter::SemanticsTristate::kTrue;
969 UISwitch* nativeSwitch = [[UISwitch alloc] init];
970 nativeSwitch.on = YES;
972 XCTAssertEqual(
object.accessibilityTraits, nativeSwitch.accessibilityTraits);
973 XCTAssertEqualObjects(
object.accessibilityValue, nativeSwitch.accessibilityValue);
976 flutter::SemanticsNode update;
977 update.flags.isToggled = flutter::SemanticsTristate::kFalse;
978 update.flags.isEnabled = flutter::SemanticsTristate::kTrue;
980 update.label =
"foo";
983 nativeSwitch.on = NO;
985 XCTAssertEqual(
object.accessibilityTraits, nativeSwitch.accessibilityTraits);
986 XCTAssertEqualObjects(
object.accessibilityValue, nativeSwitch.accessibilityValue);
989 - (void)testFlutterSemanticsObjectOfRadioButton {
990 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
992 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
996 flutter::SemanticsNode node;
997 node.flags.isInMutuallyExclusiveGroup =
true;
998 node.flags.isChecked = flutter::SemanticsCheckState::kFalse;
999 node.flags.isEnabled = flutter::SemanticsTristate::kTrue;
1002 XCTAssertTrue((
object.accessibilityTraits & UIAccessibilityTraitButton) > 0);
1003 XCTAssertNil(
object.accessibilityValue);
1006 - (void)testFlutterSwitchSemanticsObjectMatchesUISwitchDisabled {
1007 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
1009 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1014 flutter::SemanticsNode node;
1015 node.flags.isToggled = flutter::SemanticsTristate::kTrue;
1019 UISwitch* nativeSwitch = [[UISwitch alloc] init];
1020 nativeSwitch.on = YES;
1021 nativeSwitch.enabled = NO;
1023 XCTAssertEqual(
object.accessibilityTraits, nativeSwitch.accessibilityTraits);
1024 XCTAssertEqualObjects(
object.accessibilityValue, nativeSwitch.accessibilityValue);
1027 - (void)testSemanticsObjectDeallocated {
1028 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1030 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1038 XCTAssertNil(weakObject);
1041 - (void)testFlutterSemanticsObjectReturnsNilContainerWhenBridgeIsNotAlive {
1046 flutter::SemanticsNode parent;
1048 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1049 parent.label =
"label";
1050 parent.value =
"value";
1051 parent.hint =
"hint";
1053 flutter::SemanticsNode node;
1055 node.flags.hasImplicitScrolling =
true;
1056 node.actions = flutter::kHorizontalScrollSemanticsActions;
1057 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1058 node.label =
"label";
1059 node.value =
"value";
1061 node.scrollExtentMax = 100.0;
1062 node.scrollPosition = 0.0;
1063 parent.childrenInTraversalOrder.push_back(1);
1065 flutter::SemanticsNode node2;
1067 node2.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1068 node2.label =
"label";
1069 node2.value =
"value";
1070 node2.hint =
"hint";
1071 node2.scrollExtentMax = 100.0;
1072 node2.scrollPosition = 0.0;
1073 parent.childrenInTraversalOrder.push_back(2);
1079 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
1080 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1092 parentObject.
children = @[ scrollable, object2 ];
1107 XCTAssertNil(scrollable.accessibilityContainer);
1108 XCTAssertNil(object2.accessibilityContainer);
1111 - (void)testAccessibilityHitTestSearchCanReturnPlatformView {
1112 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1114 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1123 platformView:platformView];
1127 object1.
children = @[ platformViewSemanticsContainer, object3 ];
1130 flutter::SemanticsNode node0;
1132 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1136 flutter::SemanticsNode node1;
1138 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1142 flutter::SemanticsNode node2;
1144 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
1148 flutter::SemanticsNode node3;
1150 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1154 CGPoint point = CGPointMake(10, 10);
1157 XCTAssertEqual(hitTestResult, platformView);
1160 - (void)testFlutterPlatformViewSemanticsContainer {
1161 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
1163 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1168 weakPlatformView = platformView;
1174 platformView:platformView];
1175 weakContainer = container;
1177 XCTAssertNotNil(weakPlatformView);
1178 XCTAssertNotNil(weakContainer);
1182 XCTAssertNotNil(weakPlatformView);
1183 XCTAssertNotNil(weakContainer);
1187 XCTAssertNil(weakPlatformView);
1188 XCTAssertNil(weakContainer);
1191 - (void)testTextInputSemanticsObject {
1192 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1194 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1196 flutter::SemanticsNode node;
1198 node.flags.isTextField =
true;
1199 node.flags.isReadOnly =
true;
1203 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitNone);
1206 - (void)testTextInputSemanticsObject_canPerformAction {
1207 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1209 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1211 flutter::SemanticsNode node;
1213 node.flags.isTextField =
true;
1214 node.flags.isReadOnly =
true;
1219 id textInputSurrogate = OCMClassMock([UIResponder
class]);
1220 id partialSemanticsObject = OCMPartialMock(
object);
1221 OCMStub([partialSemanticsObject textInputSurrogate]).andReturn(textInputSurrogate);
1223 OCMExpect([textInputSurrogate canPerformAction:[OCMArg anySelector] withSender:OCMOCK_ANY])
1225 XCTAssertTrue([partialSemanticsObject canPerformAction:
@selector(copy:) withSender:nil]);
1227 OCMExpect([textInputSurrogate canPerformAction:[OCMArg anySelector] withSender:OCMOCK_ANY])
1229 XCTAssertFalse([partialSemanticsObject canPerformAction:
@selector(copy:) withSender:nil]);
1232 - (void)testTextInputSemanticsObject_editActions {
1233 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1235 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1237 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 XCTestExpectation* copyExpectation =
1251 [
self expectationWithDescription:@"Surrogate's copy method is called."];
1252 XCTestExpectation* cutExpectation =
1253 [
self expectationWithDescription:@"Surrogate's cut method is called."];
1254 XCTestExpectation* pasteExpectation =
1255 [
self expectationWithDescription:@"Surrogate's paste method is called."];
1256 XCTestExpectation* selectAllExpectation =
1257 [
self expectationWithDescription:@"Surrogate's selectAll method is called."];
1258 XCTestExpectation* deleteExpectation =
1259 [
self expectationWithDescription:@"Surrogate's delete method is called."];
1261 OCMStub([textInputSurrogate copy:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1262 [copyExpectation fulfill];
1264 OCMStub([textInputSurrogate cut:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1265 [cutExpectation fulfill];
1267 OCMStub([textInputSurrogate paste:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1268 [pasteExpectation fulfill];
1270 OCMStub([textInputSurrogate selectAll:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1271 [selectAllExpectation fulfill];
1273 OCMStub([textInputSurrogate
delete:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1274 [deleteExpectation fulfill];
1277 [partialSemanticsObject copy:nil];
1278 [partialSemanticsObject cut:nil];
1279 [partialSemanticsObject paste:nil];
1280 [partialSemanticsObject selectAll:nil];
1281 [partialSemanticsObject delete:nil];
1283 [
self waitForExpectationsWithTimeout:1 handler:nil];
1286 - (void)testSliderSemanticsObject {
1287 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1289 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1291 flutter::SemanticsNode node;
1292 node.flags.isSlider =
true;
1296 XCTAssertEqual([
object accessibilityActivate], YES);
1299 - (void)testUIFocusItemConformance {
1300 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1302 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1308 XCTAssertTrue([parent.parentFocusEnvironment isKindOfClass:[UIView
class]]);
1309 XCTAssertEqual(child.parentFocusEnvironment, child.
parent);
1312 flutter::SemanticsNode childNode;
1313 childNode.flags.isHidden =
true;
1314 childNode.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
1316 XCTAssertFalse(child.canBecomeFocused);
1317 childNode.flags = flutter::SemanticsFlags{};
1319 XCTAssertTrue(child.canBecomeFocused);
1320 childNode.actions = 0;
1322 XCTAssertFalse(child.canBecomeFocused);
1324 CGFloat scale = ((bridge->view().window.screen ?: UIScreen.mainScreen)).scale;
1326 childNode.rect = SkRect::MakeXYWH(0, 0, 100 * scale, 100 * scale);
1328 flutter::SemanticsNode parentNode;
1329 parentNode.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1332 XCTAssertTrue(CGRectEqualToRect(child.frame, CGRectMake(0, 0, 100, 100)));
1335 - (void)testUIFocusItemContainerConformance {
1336 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1338 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1345 NSArray<id<UIFocusItem>>* itemsInRect = [parent focusItemsInRect:CGRectMake(0, 0, 100, 100)];
1346 XCTAssertEqual(itemsInRect.count, (
unsigned long)2);
1347 XCTAssertTrue([itemsInRect containsObject:child1]);
1348 XCTAssertTrue([itemsInRect containsObject:child2]);
1351 - (void)testUIFocusItemScrollableContainerConformance {
1352 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1354 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1359 CGPoint p = CGPointMake(123.0, 456.0);
1360 [scrollable.scrollView scrollViewWillEndDragging:scrollable.scrollView
1361 withVelocity:CGPointZero
1362 targetContentOffset:&p];
1364 [scrollable.scrollView scrollViewDidEndDecelerating:scrollable.scrollView];
1365 XCTAssertEqual(bridge->observations.size(), (
size_t)1);
1366 XCTAssertEqual(bridge->observations[0].id, 5);
1367 XCTAssertEqual(bridge->observations[0].action, flutter::SemanticsAction::kScrollToOffset);
1369 std::vector<uint8_t> args = bridge->observations[0].args;
1370 XCTAssertEqual(args.size(), 3 *
sizeof(CGFloat));
1372 NSData* encoded = [NSData dataWithBytes:args.data() length:args.size()];
1374 CGPoint point = CGPointZero;
1375 memcpy(&point, decoded.
data.bytes, decoded.
data.length);
1376 XCTAssertTrue(CGPointEqualToPoint(point, p));
1379 - (void)testUIFocusItemScrollableContainerNoFeedbackLoops {
1380 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1382 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1387 const CGPoint p = CGPointMake(0.0, 456.0);
1389 bridge->observations.clear();
1391 const SkScalar scrollPosition = p.y + 0.0000000000000001;
1392 flutter::SemanticsNode node;
1393 node.flags.hasImplicitScrolling =
true;
1394 node.actions = flutter::kVerticalScrollSemanticsActions;
1395 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1396 node.scrollExtentMax = 10000;
1397 node.scrollPosition = scrollPosition;
1398 node.transform = {1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, scrollPosition, 0, 1.0};
1402 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()