@@ -1320,6 +1320,7 @@ final class RunnerTests: XCTestCase {
13201320 let rootLabel = aggregatedLabel ( for: rootSnapshot) ?? rootSnapshot. label. trimmingCharacters ( in: . whitespacesAndNewlines)
13211321 let rootIdentifier = rootSnapshot. identifier. trimmingCharacters ( in: . whitespacesAndNewlines)
13221322 let rootValue = snapshotValueText ( rootSnapshot)
1323+ let rootHittable = computedSnapshotHittable ( rootSnapshot, viewport: viewport, laterSiblings: [ ] )
13231324 nodes. append (
13241325 SnapshotNode (
13251326 index: 0 ,
@@ -1334,15 +1335,21 @@ final class RunnerTests: XCTestCase {
13341335 height: Double ( rootSnapshot. frame. size. height) ,
13351336 ) ,
13361337 enabled: rootSnapshot. isEnabled,
1337- hittable: snapshotHittable ( rootSnapshot ) ,
1338+ hittable: rootHittable ,
13381339 depth: 0 ,
13391340 )
13401341 )
13411342
13421343 var seen = Set < String > ( )
1343- var stack : [ ( XCUIElementSnapshot , Int , Int ) ] = rootSnapshot. children. map { ( $0, 1 , 1 ) }
1344+ var stack : [ ( XCUIElementSnapshot , Int , Int , ArraySlice < XCUIElementSnapshot > ) ] = [ ]
1345+ let rootChildren = rootSnapshot. children
1346+ if !rootChildren. isEmpty {
1347+ for index in stride ( from: rootChildren. count - 1 , through: 0 , by: - 1 ) {
1348+ stack. append ( ( rootChildren [ index] , 1 , 1 , rootChildren. suffix ( from: index + 1 ) ) )
1349+ }
1350+ }
13441351
1345- while let ( snapshot, depth, visibleDepth) = stack. popLast ( ) {
1352+ while let ( snapshot, depth, visibleDepth, laterSiblings ) = stack. popLast ( ) {
13461353 if nodes. count >= fastSnapshotLimit {
13471354 truncated = true
13481355 break
@@ -1352,6 +1359,7 @@ final class RunnerTests: XCTestCase {
13521359 let label = aggregatedLabel ( for: snapshot) ?? snapshot. label. trimmingCharacters ( in: . whitespacesAndNewlines)
13531360 let identifier = snapshot. identifier. trimmingCharacters ( in: . whitespacesAndNewlines)
13541361 let valueText = snapshotValueText ( snapshot)
1362+ let hittable = computedSnapshotHittable ( snapshot, viewport: viewport, laterSiblings: laterSiblings)
13551363 let hasContent = !label. isEmpty || !identifier. isEmpty || ( valueText != nil )
13561364 if !isVisibleInViewport( snapshot. frame, viewport) && !hasContent {
13571365 continue
@@ -1362,7 +1370,8 @@ final class RunnerTests: XCTestCase {
13621370 label: label,
13631371 identifier: identifier,
13641372 valueText: valueText,
1365- options: options
1373+ options: options,
1374+ hittable: hittable
13661375 )
13671376
13681377 let key = " \( snapshot. elementType) - \( label) - \( identifier) - \( snapshot. frame. origin. x) - \( snapshot. frame. origin. y) "
@@ -1373,8 +1382,11 @@ final class RunnerTests: XCTestCase {
13731382
13741383 if depth < maxDepth {
13751384 let nextVisibleDepth = include && !isDuplicate ? visibleDepth + 1 : visibleDepth
1376- for child in snapshot. children. reversed ( ) {
1377- stack. append ( ( child, depth + 1 , nextVisibleDepth) )
1385+ let children = snapshot. children
1386+ if !children. isEmpty {
1387+ for childIndex in stride ( from: children. count - 1 , through: 0 , by: - 1 ) {
1388+ stack. append ( ( children [ childIndex] , depth + 1 , nextVisibleDepth, children. suffix ( from: childIndex + 1 ) ) )
1389+ }
13781390 }
13791391 }
13801392
@@ -1394,7 +1406,7 @@ final class RunnerTests: XCTestCase {
13941406 height: Double ( snapshot. frame. size. height) ,
13951407 ) ,
13961408 enabled: snapshot. isEnabled,
1397- hittable: snapshotHittable ( snapshot ) ,
1409+ hittable: hittable ,
13981410 depth: min ( maxDepth, visibleDepth) ,
13991411 )
14001412 )
@@ -1439,7 +1451,7 @@ final class RunnerTests: XCTestCase {
14391451 identifier: identifier,
14401452 valueText: valueText,
14411453 options: options,
1442- hittableOverride : hittable
1454+ hittable : hittable
14431455 ) {
14441456 nodes. append (
14451457 SnapshotNode (
@@ -1697,10 +1709,9 @@ final class RunnerTests: XCTestCase {
16971709 identifier: String ,
16981710 valueText: String ? ,
16991711 options: SnapshotOptions ,
1700- hittableOverride : Bool ? = nil
1712+ hittable : Bool
17011713 ) -> Bool {
17021714 let type = snapshot. elementType
1703- let hittable = hittableOverride ?? snapshotHittable ( snapshot)
17041715 let hasContent = !label. isEmpty || !identifier. isEmpty || ( valueText != nil )
17051716 if options. compact && type == . other && !hasContent && !hittable {
17061717 if snapshot. children. count <= 1 { return false }
@@ -1741,11 +1752,6 @@ final class RunnerTests: XCTestCase {
17411752 return text. isEmpty ? nil : text
17421753 }
17431754
1744- private func snapshotHittable( _ snapshot: XCUIElementSnapshot ) -> Bool {
1745- // XCUIElementSnapshot does not expose isHittable; use enabled as a lightweight proxy.
1746- return snapshot. isEnabled
1747- }
1748-
17491755 private func aggregatedLabel( for snapshot: XCUIElementSnapshot , depth: Int = 0 ) -> String ? {
17501756 if depth > 4 { return nil }
17511757 let text = snapshot. label. trimmingCharacters ( in: . whitespacesAndNewlines)
0 commit comments