@@ -538,3 +538,167 @@ test('a toolbar host enclosing a plain content sibling still covers it, so the e
538538
539539 assert . deepEqual ( coveredLabels ( nodes ) , [ 'Other' , 'Barless primary' ] ) ;
540540} ) ;
541+
542+ // `snapshot -i` of a SwiftUI `fullScreenCover` presented from a `.large` sheet over the Home tab on an
543+ // iOS 27 simulator, cells trimmed. All three presentations are listed as siblings of the root, each
544+ // ending with its toolbar host. The sheet's host encloses Home's bar and list and the cover's.
545+ const COVER_OVER_SHEET_ROWS : CapturedNode [ ] = [
546+ [ 0 , undefined , 'Other' , 'SwiftUIApplication' , 'SheetRepro' , [ 0 , 0 , 402 , 874 ] ] ,
547+ [ 1 , 0 , 'NavigationBar' , 'SwiftUI.UIKitNavigationBar' , undefined , [ 0 , 62 , 402 , 106 ] ] ,
548+ [ 2 , 1 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Edit' , [ 328.67 , 66 , 53.33 , 36 ] ] ,
549+ [ 4 , 0 , 'CollectionView' , 'SwiftUI.UpdateCoalescingCollectionView' , undefined , [ 0 , 116 , 402 , 675 ] ] ,
550+ [ 6 , 4 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Open medium sheet' , [ 16 , 168 , 370 , 52 ] ] ,
551+ [ 16 , 0 , 'Toolbar' , '_UIFloatingBarContainerView' , 'Toolbar' , [ 0 , 0 , 402 , 874 ] ] ,
552+ [ 17 , 0 , 'TabBar' , 'UITabBar' , 'Tab Bar' , [ 0 , 791 , 402 , 83 ] ] ,
553+ [ 18 , 17 , 'Button' , '_UITabButton' , 'Home' , [ 68 , 795 , 94 , 54 ] ] ,
554+ [ 21 , 0 , 'NavigationBar' , 'SwiftUI.UIKitNavigationBar' , undefined , [ 0 , 78 , 402 , 106 ] ] ,
555+ [ 22 , 21 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Close' , [ 20 , 82 , 67 , 36 ] ] ,
556+ [
557+ 26 ,
558+ 0 ,
559+ 'CollectionView' ,
560+ 'SwiftUI.UpdateCoalescingCollectionView' ,
561+ undefined ,
562+ [ 0 , 132 , 402 , 680 ] ,
563+ ] ,
564+ [ 28 , 26 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Primary action' , [ 16 , 184 , 370 , 52 ] ] ,
565+ [ 43 , 26 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Row 1' , [ 16 , 733 , 370 , 52 ] ] ,
566+ [ 46 , 0 , 'Toolbar' , '_UIFloatingBarContainerView' , 'Toolbar' , [ 0 , 62 , 402 , 812 ] ] ,
567+ [ 47 , 46 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Bottom' , [ 162 , 804 , 78 , 36 ] ] ,
568+ [ 48 , 0 , 'NavigationBar' , 'SwiftUI.UIKitNavigationBar' , undefined , [ 0 , 62 , 402 , 54 ] ] ,
569+ [ 49 , 48 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper close' , [ 20 , 66 , 116 , 36 ] ] ,
570+ [ 51 , 48 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper save' , [ 268 , 66 , 114 , 36 ] ] ,
571+ [
572+ 52 ,
573+ 0 ,
574+ 'CollectionView' ,
575+ 'SwiftUI.UpdateCoalescingCollectionView' ,
576+ undefined ,
577+ [ 0 , 116 , 402 , 696 ] ,
578+ ] ,
579+ [ 54 , 52 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper primary' , [ 16 , 151 , 370 , 52 ] ] ,
580+ [ 57 , 52 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper row 0' , [ 16 , 255 , 370 , 52 ] ] ,
581+ [ 68 , 0 , 'Toolbar' , '_UIFloatingBarContainerView' , 'Toolbar' , [ 0 , 0 , 402 , 874 ] ] ,
582+ [ 69 , 68 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper bottom' , [ 136.67 , 804 , 128.67 , 36 ] ] ,
583+ ] ;
584+
585+ const HOME_ROW_INDEXES = new Set ( [ 1 , 2 , 4 , 6 , 16 , 17 , 18 ] ) ;
586+ const COVER_ROW_INDEXES = new Set ( [ 48 , 49 , 51 , 52 , 54 , 57 , 68 , 69 ] ) ;
587+ const COVER_CONTROLS = [
588+ 'Upper close' ,
589+ 'Upper save' ,
590+ 'Upper primary' ,
591+ 'Upper row 0' ,
592+ 'Upper bottom' ,
593+ ] ;
594+
595+ test ( 'a full-screen cover over a sheet leaves the sheet beneath covered and the cover pressable' , ( ) => {
596+ const covered = coveredLabels ( capturedTree ( COVER_OVER_SHEET_ROWS ) ) ;
597+
598+ for ( const label of [ 'Edit' , 'Open medium sheet' , 'Close' , 'Primary action' , 'Row 1' ] ) {
599+ assert . ok ( covered . includes ( label ) , `${ label } sits beneath the cover` ) ;
600+ }
601+ for ( const label of COVER_CONTROLS ) {
602+ assert . ok ( ! covered . includes ( label ) , `${ label } is on the cover` ) ;
603+ }
604+ } ) ;
605+
606+ test ( 'a toolbar host enclosing the bars of a presentation stacked over it keeps covering' , ( ) => {
607+ // The capture without Home: only the cover's bar and list, listed after the sheet's host, tell it
608+ // apart from a lone sheet.
609+ const rows = COVER_OVER_SHEET_ROWS . filter ( ( [ index ] ) => ! HOME_ROW_INDEXES . has ( index ) ) ;
610+ const covered = coveredLabels ( capturedTree ( rows ) ) ;
611+
612+ assert . ok ( covered . includes ( 'Primary action' ) ) ;
613+ assert . ok ( covered . includes ( 'Row 1' ) ) ;
614+ for ( const label of COVER_CONTROLS ) assert . ok ( ! covered . includes ( label ) ) ;
615+ } ) ;
616+
617+ test ( 'a toolbar host enclosing the bars of a presentation beneath it keeps covering' , ( ) => {
618+ // The capture without the cover: a sheet host enclosing Home's bar and list, which sit before Home's
619+ // own host, covers Home. It covers the sheet too, failing closed; iOS publishes no presentation
620+ // beneath a sheet, so this shape is not captured live.
621+ const rows = COVER_OVER_SHEET_ROWS . filter ( ( [ index ] ) => ! COVER_ROW_INDEXES . has ( index ) ) ;
622+ const covered = coveredLabels ( capturedTree ( rows ) ) ;
623+
624+ assert . ok ( covered . includes ( 'Edit' ) ) ;
625+ assert . ok ( covered . includes ( 'Open medium sheet' ) ) ;
626+ } ) ;
627+
628+ test . for ( [
629+ {
630+ name : 'a sheet over a sheet' ,
631+ rows : [
632+ [ 0 , undefined , 'Other' , 'SwiftUIApplication' , 'SheetRepro' , [ 0 , 0 , 402 , 874 ] ] ,
633+ [ 1 , 0 , 'NavigationBar' , 'SwiftUI.UIKitNavigationBar' , undefined , [ 0 , 88 , 402 , 54 ] ] ,
634+ [ 2 , 1 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper close' , [ 20 , 92 , 116 , 36 ] ] ,
635+ [ 4 , 1 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper save' , [ 268 , 92 , 114 , 36 ] ] ,
636+ [
637+ 5 ,
638+ 0 ,
639+ 'CollectionView' ,
640+ 'SwiftUI.UpdateCoalescingCollectionView' ,
641+ undefined ,
642+ [ 0 , 142 , 402 , 670 ] ,
643+ ] ,
644+ [ 7 , 5 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper primary' , [ 16 , 177 , 370 , 52 ] ] ,
645+ [ 20 , 5 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper row 5' , [ 16 , 541 , 370 , 52 ] ] ,
646+ [ 21 , 0 , 'Toolbar' , '_UIFloatingBarContainerView' , 'Toolbar' , [ 0 , 72 , 402 , 802 ] ] ,
647+ [ 22 , 21 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper bottom' , [ 136.67 , 804 , 128.67 , 36 ] ] ,
648+ ] ,
649+ } ,
650+ {
651+ name : 'a sheet over a plain screen' ,
652+ rows : [
653+ [ 0 , undefined , 'Other' , 'SwiftUIApplication' , 'SheetRepro' , [ 0 , 0 , 402 , 874 ] ] ,
654+ [ 1 , 0 , 'NavigationBar' , 'SwiftUI.UIKitNavigationBar' , undefined , [ 0 , 78 , 402 , 54 ] ] ,
655+ [ 2 , 1 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper close' , [ 20 , 82 , 116 , 36 ] ] ,
656+ [ 4 , 1 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper save' , [ 268 , 82 , 114 , 36 ] ] ,
657+ [
658+ 5 ,
659+ 0 ,
660+ 'CollectionView' ,
661+ 'SwiftUI.UpdateCoalescingCollectionView' ,
662+ undefined ,
663+ [ 0 , 132 , 402 , 680 ] ,
664+ ] ,
665+ [ 7 , 5 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper primary' , [ 16 , 167 , 370 , 52 ] ] ,
666+ [ 20 , 5 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper row 5' , [ 16 , 531 , 370 , 52 ] ] ,
667+ [ 21 , 0 , 'Toolbar' , '_UIFloatingBarContainerView' , 'Toolbar' , [ 0 , 62 , 402 , 812 ] ] ,
668+ [ 22 , 21 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Upper bottom' , [ 136.67 , 804 , 128.67 , 36 ] ] ,
669+ ] ,
670+ } ,
671+ ] satisfies { name : string ; rows : CapturedNode [ ] } [ ] ) (
672+ 'the captured iOS 27 $name publishes only the top sheet, and none of it is covered' ,
673+ ( { rows } ) => {
674+ // iOS drops the presentation beneath a sheet from the capture, so no lower control gets a ref.
675+ assert . deepEqual ( coveredLabels ( capturedTree ( rows ) ) , [ ] ) ;
676+ } ,
677+ ) ;
678+
679+ test ( 'a toolbar host enclosing only a scroll indicator still covers, so the scroll evidence is a container' , ( ) => {
680+ const nodes = capturedTree ( [
681+ [ 0 , undefined , 'Other' , 'SwiftUIApplication' , 'SheetRepro' , [ 0 , 0 , 402 , 874 ] ] ,
682+ [ 1 , 0 , 'Other' , 'UIView' , undefined , [ 0 , 100 , 402 , 712 ] ] ,
683+ [ 3 , 1 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Barless primary' , [ 16 , 100 , 370 , 49 ] ] ,
684+ [ 4 , 0 , 'ScrollBar' , '_UIScrollViewScrollIndicator' , undefined , [ 396 , 100 , 3 , 712 ] ] ,
685+ [ 17 , 0 , 'Toolbar' , '_UIFloatingBarContainerView' , 'Toolbar' , [ 0 , 62 , 402 , 812 ] ] ,
686+ ] ) ;
687+
688+ assert . ok ( coveredLabels ( nodes ) . includes ( 'Barless primary' ) ) ;
689+ } ) ;
690+
691+ test ( 'a control the exempt toolbar host really hosts still covers the row it overlaps' , ( ) => {
692+ // The host is exempt for the list it encloses, but a bar-kind strip it hosts is judged by its own
693+ // rect: it covers the row beneath it and leaves the row above it alone.
694+ const nodes = capturedTree ( [
695+ [ 0 , undefined , 'Other' , 'SwiftUIApplication' , 'SheetRepro' , [ 0 , 0 , 402 , 874 ] ] ,
696+ [ 1 , 0 , 'CollectionView' , 'SwiftUI.CollectionView' , undefined , [ 0 , 100 , 402 , 712 ] ] ,
697+ [ 3 , 1 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Barless primary' , [ 16 , 100 , 370 , 49 ] ] ,
698+ [ 16 , 1 , 'Button' , 'SwiftUI.AccessibilityNode' , 'Barless row 12' , [ 16 , 773 , 370 , 39 ] ] ,
699+ [ 17 , 0 , 'Toolbar' , '_UIFloatingBarContainerView' , 'Toolbar' , [ 0 , 62 , 402 , 812 ] ] ,
700+ [ 18 , 17 , 'Toolbar' , '_UIBarPlatterView' , 'Bottom bar' , [ 16 , 760 , 370 , 60 ] ] ,
701+ ] ) ;
702+
703+ assert . deepEqual ( coveredLabels ( nodes ) , [ 'Barless row 12' ] ) ;
704+ } ) ;
0 commit comments