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)testAccessibilityScrollToVisibleWithChild {
158 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
160 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
163 flutter::SemanticsNode node3;
165 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
170 XCTAssertTrue(bridge->observations.size() == 1);
171 XCTAssertTrue(bridge->observations[0].id == 3);
172 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
175 - (void)testAccessibilityHitTestOutOfRect {
176 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
178 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
185 object1.
children = @[ object2, object3 ];
188 flutter::SemanticsNode node0;
190 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
194 flutter::SemanticsNode node1;
196 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
200 flutter::SemanticsNode node2;
202 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
206 flutter::SemanticsNode node3;
208 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
212 CGPoint point = CGPointMake(300, 300);
215 XCTAssertNil(hitTestResult);
218 - (void)testReplaceChildAtIndex {
219 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
221 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
227 XCTAssertNil(child1.
parent);
228 XCTAssertEqual(parent, child2.
parent);
229 XCTAssertEqualObjects(parent.
children, @[ child2 ]);
232 - (void)testPlainSemanticsObjectWithLabelHasStaticTextTrait {
233 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
235 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
236 flutter::SemanticsNode node;
240 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitStaticText);
243 - (void)testNodeWithImplicitScrollIsAnAccessibilityElementWhenItisHidden {
244 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
246 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
247 flutter::SemanticsNode node;
249 node.flags.hasImplicitScrolling =
true;
250 node.flags.isHidden =
true;
253 XCTAssertEqual(
object.isAccessibilityElement, YES);
256 - (void)testNodeWithImplicitScrollIsNotAnAccessibilityElementWhenItisNotHidden {
257 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
259 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
260 flutter::SemanticsNode node;
261 node.flags.hasImplicitScrolling =
true;
264 XCTAssertEqual(
object.isAccessibilityElement, NO);
267 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait {
268 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
270 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
271 flutter::SemanticsNode node;
277 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitNone);
280 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait1 {
281 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
283 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
284 flutter::SemanticsNode node;
286 node.flags.isTextField =
true;
289 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitNone);
292 - (void)testIntresetingSemanticsObjectWithLabelHasStaticTextTrait2 {
293 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
295 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
296 flutter::SemanticsNode node;
299 node.flags.isButton =
true;
302 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitButton);
305 - (void)testVerticalFlutterScrollableSemanticsObject {
306 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
308 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
310 float transformScale = 0.5f;
311 float screenScale = [[bridge->view() window] screen].scale;
312 float effectivelyScale = transformScale / screenScale;
317 float scrollExtentMax = 500.0;
318 float scrollPosition = 150.0;
320 flutter::SemanticsNode node;
321 node.flags.hasImplicitScrolling =
true;
322 node.actions = flutter::kVerticalScrollSemanticsActions;
323 node.rect = SkRect::MakeXYWH(x, y, w, h);
324 node.scrollExtentMax = scrollExtentMax;
325 node.scrollPosition = scrollPosition;
327 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
334 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
335 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
336 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
338 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
341 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
343 XCTAssertEqualWithAccuracy(scrollView.contentSize.height,
346 XCTAssertEqual(scrollView.contentOffset.x, 0);
347 XCTAssertEqualWithAccuracy(scrollView.contentOffset.y, scrollPosition * effectivelyScale,
351 - (void)testVerticalFlutterScrollableSemanticsObjectNoWindowDoesNotCrash {
352 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
354 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
356 float transformScale = 0.5f;
361 float scrollExtentMax = 500.0;
362 float scrollPosition = 150.0;
364 flutter::SemanticsNode node;
365 node.flags.hasImplicitScrolling =
true;
366 node.actions = flutter::kVerticalScrollSemanticsActions;
367 node.rect = SkRect::MakeXYWH(x, y, w, h);
368 node.scrollExtentMax = scrollExtentMax;
369 node.scrollPosition = scrollPosition;
371 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
376 XCTAssertNoThrow([scrollable accessibilityBridgeDidFinishUpdate]);
379 - (void)testHorizontalFlutterScrollableSemanticsObject {
380 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
382 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
384 float transformScale = 0.5f;
385 float screenScale = [[bridge->view() window] screen].scale;
386 float effectivelyScale = transformScale / screenScale;
391 float scrollExtentMax = 500.0;
392 float scrollPosition = 150.0;
394 flutter::SemanticsNode node;
395 node.flags.hasImplicitScrolling =
true;
396 node.actions = flutter::kHorizontalScrollSemanticsActions;
397 node.rect = SkRect::MakeXYWH(x, y, w, h);
398 node.scrollExtentMax = scrollExtentMax;
399 node.scrollPosition = scrollPosition;
401 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
408 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
409 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
410 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
412 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
415 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, (w + scrollExtentMax) * effectivelyScale,
417 XCTAssertEqualWithAccuracy(scrollView.contentSize.height, h * effectivelyScale,
420 XCTAssertEqualWithAccuracy(scrollView.contentOffset.x, scrollPosition * effectivelyScale,
422 XCTAssertEqual(scrollView.contentOffset.y, 0);
425 - (void)testCanHandleInfiniteScrollExtent {
426 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
428 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
430 float transformScale = 0.5f;
431 float screenScale = [[bridge->view() window] screen].scale;
432 float effectivelyScale = transformScale / screenScale;
437 float scrollExtentMax = INFINITY;
438 float scrollPosition = 150.0;
440 flutter::SemanticsNode node;
441 node.flags.hasImplicitScrolling =
true;
442 node.actions = flutter::kVerticalScrollSemanticsActions;
443 node.rect = SkRect::MakeXYWH(x, y, w, h);
444 node.scrollExtentMax = scrollExtentMax;
445 node.scrollPosition = scrollPosition;
447 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
453 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
454 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
455 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
457 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
460 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
462 XCTAssertEqualWithAccuracy(scrollView.contentSize.height,
466 XCTAssertEqual(scrollView.contentOffset.x, 0);
467 XCTAssertEqualWithAccuracy(scrollView.contentOffset.y, scrollPosition * effectivelyScale,
471 - (void)testCanHandleNaNScrollExtentAndScrollPoisition {
472 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
474 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
476 float transformScale = 0.5f;
477 float screenScale = [[bridge->view() window] screen].scale;
478 float effectivelyScale = transformScale / screenScale;
483 float scrollExtentMax = std::nan(
"");
484 float scrollPosition = std::nan(
"");
486 flutter::SemanticsNode node;
487 node.flags.hasImplicitScrolling =
true;
488 node.actions = flutter::kVerticalScrollSemanticsActions;
489 node.rect = SkRect::MakeXYWH(x, y, w, h);
490 node.scrollExtentMax = scrollExtentMax;
491 node.scrollPosition = scrollPosition;
493 transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, transformScale, 0, 0, 0, 0, 1.0};
500 XCTAssertEqualWithAccuracy(scrollView.frame.origin.x, x * effectivelyScale,
kFloatCompareEpsilon);
501 XCTAssertEqualWithAccuracy(scrollView.frame.origin.y, y * effectivelyScale,
kFloatCompareEpsilon);
502 XCTAssertEqualWithAccuracy(scrollView.frame.size.width, w * effectivelyScale,
504 XCTAssertEqualWithAccuracy(scrollView.frame.size.height, h * effectivelyScale,
508 XCTAssertEqualWithAccuracy(scrollView.contentSize.width, w * effectivelyScale,
510 XCTAssertEqualWithAccuracy(scrollView.contentSize.height, h * effectivelyScale,
513 XCTAssertEqual(scrollView.contentOffset.x, 0);
514 XCTAssertEqual(scrollView.contentOffset.y, 0);
517 - (void)testFlutterScrollableSemanticsObjectIsNotHittestable {
518 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
520 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
522 flutter::SemanticsNode node;
523 node.flags.hasImplicitScrolling =
true;
524 node.actions = flutter::kHorizontalScrollSemanticsActions;
525 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
526 node.scrollExtentMax = 100.0;
527 node.scrollPosition = 0.0;
534 XCTAssertEqual([scrollView hitTest:CGPointMake(10, 10) withEvent:nil], nil);
537 - (void)testFlutterScrollableSemanticsObjectIsHiddenWhenVoiceOverIsRunning {
540 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
541 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
543 flutter::SemanticsNode node;
544 node.flags.hasImplicitScrolling =
true;
545 node.actions = flutter::kHorizontalScrollSemanticsActions;
546 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
547 node.scrollExtentMax = 100.0;
548 node.scrollPosition = 0.0;
555 XCTAssertTrue(scrollView.isAccessibilityElement);
557 XCTAssertFalse(scrollView.isAccessibilityElement);
560 - (void)testFlutterSemanticsObjectHasIdentifier {
563 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
564 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
566 flutter::SemanticsNode node;
567 node.identifier =
"identifier";
571 XCTAssertTrue([
object.accessibilityIdentifier isEqualToString:
@"identifier"]);
574 - (void)testFlutterScrollableSemanticsObjectWithLabelValueHintIsNotHiddenWhenVoiceOverIsRunning {
577 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
578 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
580 flutter::SemanticsNode node;
581 node.flags.hasImplicitScrolling =
true;
582 node.actions = flutter::kHorizontalScrollSemanticsActions;
583 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
584 node.label =
"label";
585 node.value =
"value";
587 node.scrollExtentMax = 100.0;
588 node.scrollPosition = 0.0;
595 XCTAssertTrue(scrollView.isAccessibilityElement);
597 [scrollView.accessibilityLabel isEqualToString:NSLocalizedString(
@"label",
@"test")]);
599 [scrollView.accessibilityValue isEqualToString:NSLocalizedString(
@"value",
@"test")]);
600 XCTAssertTrue([scrollView.accessibilityHint isEqualToString:NSLocalizedString(
@"hint",
@"test")]);
603 - (void)testFlutterSemanticsObjectMergeTooltipToLabel {
606 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
607 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
609 flutter::SemanticsNode node;
610 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
611 node.label =
"label";
612 node.tooltip =
"tooltip";
615 XCTAssertTrue(
object.isAccessibilityElement);
616 XCTAssertTrue([
object.accessibilityLabel isEqualToString:
@"label\ntooltip"]);
619 - (void)testSemanticsObjectContainerAccessibilityFrameCoversEntireScreen {
622 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
623 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
625 flutter::SemanticsNode parent;
627 parent.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
629 flutter::SemanticsNode child;
631 child.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
632 child.rect = SkRect::MakeXYWH(0, 0, 100, 100);
633 parent.childrenInTraversalOrder.push_back(1);
643 parentObject.
children = @[ childObject ];
650 XCTAssertTrue(childObject.accessibilityRespondsToUserInteraction);
651 XCTAssertTrue(CGRectEqualToRect(container.accessibilityFrame, UIScreen.mainScreen.bounds));
654 - (void)testFlutterSemanticsObjectAttributedStringsDoNotCrashWhenEmpty {
657 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
658 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
660 flutter::SemanticsNode node;
661 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
664 XCTAssertTrue(
object.accessibilityAttributedLabel == nil);
667 - (void)testFlutterScrollableSemanticsObjectReturnsParentContainerIfNoChildren {
670 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
671 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
673 flutter::SemanticsNode parent;
675 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
676 parent.label =
"label";
677 parent.value =
"value";
678 parent.hint =
"hint";
680 flutter::SemanticsNode node;
682 node.flags.hasImplicitScrolling =
true;
683 node.actions = flutter::kHorizontalScrollSemanticsActions;
684 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
685 node.label =
"label";
686 node.value =
"value";
688 node.scrollExtentMax = 100.0;
689 node.scrollPosition = 0.0;
690 parent.childrenInTraversalOrder.push_back(1);
701 parentObject.
children = @[ scrollable ];
704 XCTAssertTrue(scrollView.isAccessibilityElement);
710 - (void)testFlutterScrollableSemanticsObjectNoScrollBarOrContentInsets {
711 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
713 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
715 flutter::SemanticsNode node;
716 node.flags.hasImplicitScrolling =
true;
717 node.actions = flutter::kHorizontalScrollSemanticsActions;
718 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
719 node.scrollExtentMax = 100.0;
720 node.scrollPosition = 0.0;
728 XCTAssertFalse(scrollView.showsHorizontalScrollIndicator);
729 XCTAssertFalse(scrollView.showsVerticalScrollIndicator);
730 XCTAssertEqual(scrollView.contentInsetAdjustmentBehavior,
731 UIScrollViewContentInsetAdjustmentNever);
732 XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(scrollView.contentInset, UIEdgeInsetsZero));
735 - (void)testSemanticsObjectBuildsAttributedString {
736 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
738 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
739 flutter::SemanticsNode node;
740 node.label =
"label";
741 std::shared_ptr<flutter::SpellOutStringAttribute> attribute =
742 std::make_shared<flutter::SpellOutStringAttribute>();
743 attribute->start = 1;
745 attribute->type = flutter::StringAttributeType::kSpellOut;
746 node.labelAttributes.push_back(attribute);
747 node.value =
"value";
748 attribute = std::make_shared<flutter::SpellOutStringAttribute>();
749 attribute->start = 2;
751 attribute->type = flutter::StringAttributeType::kSpellOut;
752 node.valueAttributes.push_back(attribute);
754 std::shared_ptr<flutter::LocaleStringAttribute> local_attribute =
755 std::make_shared<flutter::LocaleStringAttribute>();
756 local_attribute->start = 3;
757 local_attribute->end = 4;
758 local_attribute->type = flutter::StringAttributeType::kLocale;
759 local_attribute->locale =
"en-MX";
760 node.hintAttributes.push_back(local_attribute);
763 NSMutableAttributedString* expectedAttributedLabel =
764 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"label", @"test")];
765 NSDictionary* attributeDict = @{
766 UIAccessibilitySpeechAttributeSpellOut : @YES,
768 [expectedAttributedLabel setAttributes:attributeDict range:NSMakeRange(1, 1)];
770 [
object.accessibilityAttributedLabel isEqualToAttributedString:expectedAttributedLabel]);
772 NSMutableAttributedString* expectedAttributedValue =
773 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"value", @"test")];
775 UIAccessibilitySpeechAttributeSpellOut : @YES,
777 [expectedAttributedValue setAttributes:attributeDict range:NSMakeRange(2, 1)];
779 [
object.accessibilityAttributedValue isEqualToAttributedString:expectedAttributedValue]);
781 NSMutableAttributedString* expectedAttributedHint =
782 [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"hint", @"test")];
784 UIAccessibilitySpeechAttributeLanguage :
@"en-MX",
786 [expectedAttributedHint setAttributes:attributeDict range:NSMakeRange(3, 1)];
788 [
object.accessibilityAttributedHint isEqualToAttributedString:expectedAttributedHint]);
791 - (void)testShouldTriggerAnnouncement {
792 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
794 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
798 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:nil]);
801 flutter::SemanticsNode node;
802 node.flags.isLiveRegion =
true;
804 XCTAssertTrue([
object nodeShouldTriggerAnnouncement:&node]);
808 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:nil]);
811 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:&node]);
814 flutter::SemanticsNode updatedNode;
815 updatedNode.flags.isLiveRegion =
true;
816 updatedNode.label =
"bar";
817 XCTAssertTrue([
object nodeShouldTriggerAnnouncement:&updatedNode]);
820 updatedNode.flags = flutter::SemanticsFlags{};
821 XCTAssertFalse([
object nodeShouldTriggerAnnouncement:&updatedNode]);
824 updatedNode.label =
"foo";
826 XCTAssertTrue([
object nodeShouldTriggerAnnouncement:&node]);
829 - (void)testShouldDispatchShowOnScreenActionForHeader {
830 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
832 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
836 flutter::SemanticsNode node;
837 node.flags.isHeader =
true;
843 [object accessibilityElementDidBecomeFocused];
845 XCTAssertTrue(bridge->observations.size() == 1);
846 XCTAssertTrue(bridge->observations[0].id == 1);
847 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
850 - (void)testShouldDispatchShowOnScreenActionForHidden {
851 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
853 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
857 flutter::SemanticsNode node;
858 node.flags.isHidden =
true;
864 [object accessibilityElementDidBecomeFocused];
866 XCTAssertTrue(bridge->observations.size() == 1);
867 XCTAssertTrue(bridge->observations[0].id == 1);
868 XCTAssertTrue(bridge->observations[0].action == flutter::SemanticsAction::kShowOnScreen);
871 - (void)testFlutterSwitchSemanticsObjectMatchesUISwitch {
872 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
874 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
879 flutter::SemanticsNode node;
880 node.flags.isToggled = flutter::SemanticsTristate::kTrue;
881 node.flags.isEnabled = flutter::SemanticsTristate::kTrue;
885 UISwitch* nativeSwitch = [[UISwitch alloc] init];
886 nativeSwitch.on = YES;
888 XCTAssertEqual(
object.accessibilityTraits, nativeSwitch.accessibilityTraits);
889 XCTAssertEqualObjects(
object.accessibilityValue, nativeSwitch.accessibilityValue);
892 flutter::SemanticsNode update;
893 update.flags.isToggled = flutter::SemanticsTristate::kFalse;
894 update.flags.isEnabled = flutter::SemanticsTristate::kTrue;
896 update.label =
"foo";
899 nativeSwitch.on = NO;
901 XCTAssertEqual(
object.accessibilityTraits, nativeSwitch.accessibilityTraits);
902 XCTAssertEqualObjects(
object.accessibilityValue, nativeSwitch.accessibilityValue);
905 - (void)testFlutterSemanticsObjectOfRadioButton {
906 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
908 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
912 flutter::SemanticsNode node;
913 node.flags.isInMutuallyExclusiveGroup =
true;
914 node.flags.isChecked = flutter::SemanticsCheckState::kFalse;
915 node.flags.isEnabled = flutter::SemanticsTristate::kTrue;
918 XCTAssertTrue((
object.accessibilityTraits & UIAccessibilityTraitButton) > 0);
919 XCTAssertNil(
object.accessibilityValue);
922 - (void)testFlutterSwitchSemanticsObjectMatchesUISwitchDisabled {
923 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
925 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
930 flutter::SemanticsNode node;
931 node.flags.isToggled = flutter::SemanticsTristate::kTrue;
935 UISwitch* nativeSwitch = [[UISwitch alloc] init];
936 nativeSwitch.on = YES;
937 nativeSwitch.enabled = NO;
939 XCTAssertEqual(
object.accessibilityTraits, nativeSwitch.accessibilityTraits);
940 XCTAssertEqualObjects(
object.accessibilityValue, nativeSwitch.accessibilityValue);
943 - (void)testSemanticsObjectDeallocated {
944 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
946 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
954 XCTAssertNil(weakObject);
957 - (void)testFlutterSemanticsObjectReturnsNilContainerWhenBridgeIsNotAlive {
962 flutter::SemanticsNode parent;
964 parent.rect = SkRect::MakeXYWH(0, 0, 100, 200);
965 parent.label =
"label";
966 parent.value =
"value";
967 parent.hint =
"hint";
969 flutter::SemanticsNode node;
971 node.flags.hasImplicitScrolling =
true;
972 node.actions = flutter::kHorizontalScrollSemanticsActions;
973 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
974 node.label =
"label";
975 node.value =
"value";
977 node.scrollExtentMax = 100.0;
978 node.scrollPosition = 0.0;
979 parent.childrenInTraversalOrder.push_back(1);
981 flutter::SemanticsNode node2;
983 node2.rect = SkRect::MakeXYWH(0, 0, 100, 200);
984 node2.label =
"label";
985 node2.value =
"value";
987 node2.scrollExtentMax = 100.0;
988 node2.scrollPosition = 0.0;
989 parent.childrenInTraversalOrder.push_back(2);
995 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(mock);
996 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1008 parentObject.
children = @[ scrollable, object2 ];
1023 XCTAssertNil(scrollable.accessibilityContainer);
1024 XCTAssertNil(object2.accessibilityContainer);
1027 - (void)testAccessibilityHitTestSearchCanReturnPlatformView {
1028 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1030 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1039 platformView:platformView];
1043 object1.
children = @[ platformViewSemanticsContainer, object3 ];
1046 flutter::SemanticsNode node0;
1048 node0.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1052 flutter::SemanticsNode node1;
1054 node1.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1058 flutter::SemanticsNode node2;
1060 node2.rect = SkRect::MakeXYWH(0, 0, 100, 100);
1064 flutter::SemanticsNode node3;
1066 node3.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1070 CGPoint point = CGPointMake(10, 10);
1073 XCTAssertEqual(hitTestResult, platformView);
1076 - (void)testFlutterPlatformViewSemanticsContainer {
1077 fml::WeakPtrFactory<flutter::testing::MockAccessibilityBridge> factory(
1079 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1084 weakPlatformView = platformView;
1090 platformView:platformView];
1091 weakContainer = container;
1093 XCTAssertNotNil(weakPlatformView);
1094 XCTAssertNotNil(weakContainer);
1098 XCTAssertNotNil(weakPlatformView);
1099 XCTAssertNotNil(weakContainer);
1103 XCTAssertNil(weakPlatformView);
1104 XCTAssertNil(weakContainer);
1107 - (void)testTextInputSemanticsObject {
1108 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1110 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1112 flutter::SemanticsNode node;
1114 node.flags.isTextField =
true;
1115 node.flags.isReadOnly =
true;
1119 XCTAssertEqual([
object accessibilityTraits], UIAccessibilityTraitNone);
1122 - (void)testTextInputSemanticsObject_canPerformAction {
1123 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1125 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1127 flutter::SemanticsNode node;
1129 node.flags.isTextField =
true;
1130 node.flags.isReadOnly =
true;
1135 id textInputSurrogate = OCMClassMock([UIResponder
class]);
1136 id partialSemanticsObject = OCMPartialMock(
object);
1137 OCMStub([partialSemanticsObject textInputSurrogate]).andReturn(textInputSurrogate);
1139 OCMExpect([textInputSurrogate canPerformAction:[OCMArg anySelector] withSender:OCMOCK_ANY])
1141 XCTAssertTrue([partialSemanticsObject canPerformAction:
@selector(copy:) withSender:nil]);
1143 OCMExpect([textInputSurrogate canPerformAction:[OCMArg anySelector] withSender:OCMOCK_ANY])
1145 XCTAssertFalse([partialSemanticsObject canPerformAction:
@selector(copy:) withSender:nil]);
1148 - (void)testTextInputSemanticsObject_editActions {
1149 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1151 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1153 flutter::SemanticsNode node;
1156 node.flags.isTextField =
true;
1157 node.flags.isReadOnly =
true;
1162 id textInputSurrogate = OCMClassMock([UIResponder
class]);
1163 id partialSemanticsObject = OCMPartialMock(
object);
1164 OCMStub([partialSemanticsObject textInputSurrogate]).andReturn(textInputSurrogate);
1166 XCTestExpectation* copyExpectation =
1167 [
self expectationWithDescription:@"Surrogate's copy method is called."];
1168 XCTestExpectation* cutExpectation =
1169 [
self expectationWithDescription:@"Surrogate's cut method is called."];
1170 XCTestExpectation* pasteExpectation =
1171 [
self expectationWithDescription:@"Surrogate's paste method is called."];
1172 XCTestExpectation* selectAllExpectation =
1173 [
self expectationWithDescription:@"Surrogate's selectAll method is called."];
1174 XCTestExpectation* deleteExpectation =
1175 [
self expectationWithDescription:@"Surrogate's delete method is called."];
1177 OCMStub([textInputSurrogate copy:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1178 [copyExpectation fulfill];
1180 OCMStub([textInputSurrogate cut:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1181 [cutExpectation fulfill];
1183 OCMStub([textInputSurrogate paste:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1184 [pasteExpectation fulfill];
1186 OCMStub([textInputSurrogate selectAll:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1187 [selectAllExpectation fulfill];
1189 OCMStub([textInputSurrogate
delete:OCMOCK_ANY]).andDo(^(NSInvocation* invocation) {
1190 [deleteExpectation fulfill];
1193 [partialSemanticsObject copy:nil];
1194 [partialSemanticsObject cut:nil];
1195 [partialSemanticsObject paste:nil];
1196 [partialSemanticsObject selectAll:nil];
1197 [partialSemanticsObject delete:nil];
1199 [
self waitForExpectationsWithTimeout:1 handler:nil];
1202 - (void)testSliderSemanticsObject {
1203 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1205 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1207 flutter::SemanticsNode node;
1208 node.flags.isSlider =
true;
1212 XCTAssertEqual([
object accessibilityActivate], YES);
1215 - (void)testUIFocusItemConformance {
1216 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1218 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1224 XCTAssertTrue([parent.parentFocusEnvironment isKindOfClass:[UIView
class]]);
1225 XCTAssertEqual(child.parentFocusEnvironment, child.
parent);
1228 flutter::SemanticsNode childNode;
1229 childNode.flags.isHidden =
true;
1230 childNode.actions =
static_cast<int32_t
>(flutter::SemanticsAction::kTap);
1232 XCTAssertFalse(child.canBecomeFocused);
1233 childNode.flags = flutter::SemanticsFlags{};
1235 XCTAssertTrue(child.canBecomeFocused);
1236 childNode.actions = 0;
1238 XCTAssertFalse(child.canBecomeFocused);
1240 CGFloat scale = ((bridge->view().window.screen ?: UIScreen.mainScreen)).scale;
1242 childNode.rect = SkRect::MakeXYWH(0, 0, 100 * scale, 100 * scale);
1244 flutter::SemanticsNode parentNode;
1245 parentNode.rect = SkRect::MakeXYWH(0, 0, 200, 200);
1248 XCTAssertTrue(CGRectEqualToRect(child.frame, CGRectMake(0, 0, 100, 100)));
1251 - (void)testUIFocusItemContainerConformance {
1252 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1254 fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
1261 NSArray<id<UIFocusItem>>* itemsInRect = [parent focusItemsInRect:CGRectMake(0, 0, 100, 100)];
1262 XCTAssertEqual(itemsInRect.count, (
unsigned long)2);
1263 XCTAssertTrue([itemsInRect containsObject:child1]);
1264 XCTAssertTrue([itemsInRect containsObject:child2]);
1267 - (void)testUIFocusItemScrollableContainerConformance {
1268 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1270 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1275 CGPoint p = CGPointMake(123.0, 456.0);
1276 [scrollable.scrollView scrollViewWillEndDragging:scrollable.scrollView
1277 withVelocity:CGPointZero
1278 targetContentOffset:&p];
1280 [scrollable.scrollView scrollViewDidEndDecelerating:scrollable.scrollView];
1281 XCTAssertEqual(bridge->observations.size(), (
size_t)1);
1282 XCTAssertEqual(bridge->observations[0].id, 5);
1283 XCTAssertEqual(bridge->observations[0].action, flutter::SemanticsAction::kScrollToOffset);
1285 std::vector<uint8_t> args = bridge->observations[0].args;
1286 XCTAssertEqual(args.size(), 3 *
sizeof(CGFloat));
1288 NSData* encoded = [NSData dataWithBytes:args.data() length:args.size()];
1290 CGPoint point = CGPointZero;
1291 memcpy(&point, decoded.
data.bytes, decoded.
data.length);
1292 XCTAssertTrue(CGPointEqualToPoint(point, p));
1295 - (void)testUIFocusItemScrollableContainerNoFeedbackLoops {
1296 fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
1298 fml::WeakPtr<flutter::testing::MockAccessibilityBridge> bridge = factory.GetWeakPtr();
1303 const CGPoint p = CGPointMake(0.0, 456.0);
1305 bridge->observations.clear();
1307 const SkScalar scrollPosition = p.y + 0.0000000000000001;
1308 flutter::SemanticsNode node;
1309 node.flags.hasImplicitScrolling =
true;
1310 node.actions = flutter::kVerticalScrollSemanticsActions;
1311 node.rect = SkRect::MakeXYWH(0, 0, 100, 200);
1312 node.scrollExtentMax = 10000;
1313 node.scrollPosition = scrollPosition;
1314 node.transform = {1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, scrollPosition, 0, 1.0};
1318 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()