agent-device 0.17.2 → 0.17.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.2.apk → agent-device-android-multitouch-helper-0.17.4.apk} +0 -0
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.4.apk.sha256 +1 -0
- package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.2.manifest.json → agent-device-android-multitouch-helper-0.17.4.manifest.json} +4 -4
- package/android-snapshot-helper/README.md +3 -0
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.2.apk → agent-device-android-snapshot-helper-0.17.4.apk} +0 -0
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.4.apk.sha256 +1 -0
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.2.manifest.json → agent-device-android-snapshot-helper-0.17.4.manifest.json} +6 -6
- package/dist/src/123.js +1 -1
- package/dist/src/1231.js +1 -1
- package/dist/src/1352.js +1 -1
- package/dist/src/221.js +2 -2
- package/dist/src/2403.js +3 -3
- package/dist/src/2415.js +37 -29
- package/dist/src/4012.js +4 -0
- package/dist/src/5611.js +1 -0
- package/dist/src/5827.js +1 -0
- package/dist/src/6088.js +1 -0
- package/dist/src/6133.js +1 -0
- package/dist/src/7847.js +1 -1
- package/dist/src/9471.js +1 -1
- package/dist/src/9542.js +6 -3
- package/dist/src/9616.js +2 -1
- package/dist/src/9818.js +1 -1
- package/dist/src/android-snapshot-helper.d.ts +0 -1
- package/dist/src/android.js +5 -5
- package/dist/src/apple.js +1 -1
- package/dist/src/apps.js +10 -10
- package/dist/src/args.js +53 -14
- package/dist/src/batch.js +1 -1
- package/dist/src/cli-output.js +30 -0
- package/dist/src/cli.js +15 -16
- package/dist/src/command-surface.js +1 -1
- package/dist/src/contracts.d.ts +52 -0
- package/dist/src/contracts.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/generic.js +5 -5
- package/dist/src/index.d.ts +127 -8
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +1 -1
- package/dist/src/interaction.js +1 -1
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-trace-recording.js +3 -3
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.d.ts +14 -0
- package/dist/src/selectors.js +1 -1
- package/dist/src/server.js +2 -2
- package/dist/src/session.js +8 -10
- package/dist/src/snapshot.js +2 -2
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/AgentDeviceRunnerUITests-Bridging-Header.h +1 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.h +14 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +297 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +327 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +122 -173
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +153 -5
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +171 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +0 -10
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +64 -18
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +200 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +450 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +82 -178
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +425 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +77 -6
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +10 -1
- package/ios-runner/README.md +5 -5
- package/ios-runner/RUNNER_PROTOCOL.md +0 -1
- package/package.json +3 -3
- package/server.json +2 -2
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.2.apk.sha256 +0 -1
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.2.apk.sha256 +0 -1
- package/dist/src/1534.js +0 -1
- package/dist/src/1620.js +0 -1
- package/dist/src/1644.js +0 -2
- package/dist/src/2284.js +0 -1
- package/dist/src/2474.js +0 -1
- package/dist/src/2672.js +0 -1
- package/dist/src/3393.js +0 -1
- package/dist/src/5898.js +0 -1
- package/dist/src/695.js +0 -1
- package/dist/src/7455.js +0 -1
- package/dist/src/8173.js +0 -27
- package/dist/src/8407.js +0 -1
- package/dist/src/8699.js +0 -1
- package/dist/src/9238.js +0 -4
- package/dist/src/9673.js +0 -1
- package/dist/src/9974.js +0 -1
|
@@ -11,21 +11,7 @@ extension RunnerTests {
|
|
|
11
11
|
private static let rawSnapshotMaxNodes = 5_000
|
|
12
12
|
private static let rawSnapshotTooLargeHint =
|
|
13
13
|
"Raw iOS snapshot exceeded the runner payload guard. Use regular snapshot for visible UI, or scope/depth-limit raw snapshot when inspecting a large accessibility tree."
|
|
14
|
-
|
|
15
|
-
.button,
|
|
16
|
-
.link,
|
|
17
|
-
.menuItem,
|
|
18
|
-
.other,
|
|
19
|
-
.staticText
|
|
20
|
-
]
|
|
21
|
-
private static let scrollContainerTypes: Set<XCUIElement.ElementType> = [
|
|
22
|
-
.collectionView,
|
|
23
|
-
.scrollView,
|
|
24
|
-
.table
|
|
25
|
-
]
|
|
26
|
-
private static let flatInteractiveFallbackBudget: TimeInterval = 1.0
|
|
27
|
-
|
|
28
|
-
private struct SnapshotTraversalContext {
|
|
14
|
+
struct SnapshotTraversalContext {
|
|
29
15
|
let queryRoot: XCUIElement
|
|
30
16
|
let rootSnapshot: XCUIElementSnapshot
|
|
31
17
|
let viewport: CGRect
|
|
@@ -44,12 +30,6 @@ extension RunnerTests {
|
|
|
44
30
|
let visible: Bool
|
|
45
31
|
}
|
|
46
32
|
|
|
47
|
-
private enum SnapshotTraversalCapture {
|
|
48
|
-
case context(SnapshotTraversalContext)
|
|
49
|
-
case fallback(DataPayload)
|
|
50
|
-
case empty
|
|
51
|
-
}
|
|
52
|
-
|
|
53
33
|
struct SnapshotCaptureFailure: Error {
|
|
54
34
|
let code: String
|
|
55
35
|
let message: String
|
|
@@ -98,29 +78,45 @@ extension RunnerTests {
|
|
|
98
78
|
}
|
|
99
79
|
}
|
|
100
80
|
|
|
81
|
+
static let structuralOnlyNodeTypes: Set<String> = [
|
|
82
|
+
"Application",
|
|
83
|
+
"Window",
|
|
84
|
+
"Other",
|
|
85
|
+
"ScrollView"
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
private static let collapsedTabCandidateTypes: Set<XCUIElement.ElementType> = [
|
|
89
|
+
.button,
|
|
90
|
+
.link,
|
|
91
|
+
.menuItem,
|
|
92
|
+
.other,
|
|
93
|
+
.staticText
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
static let scrollContainerTypes: Set<XCUIElement.ElementType> = [
|
|
97
|
+
.collectionView,
|
|
98
|
+
.scrollView,
|
|
99
|
+
.table
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
private static let flatInteractiveFallbackBudget: TimeInterval = 1.0
|
|
103
|
+
|
|
101
104
|
func snapshotFast(app: XCUIApplication, options: SnapshotOptions) throws -> DataPayload {
|
|
102
|
-
if options.interactiveOnly && options.compact {
|
|
103
|
-
return snapshotFlatInteractive(app: app, options: options)
|
|
104
|
-
}
|
|
105
105
|
if let blocking = blockingSystemAlertSnapshot() {
|
|
106
106
|
return blocking
|
|
107
107
|
}
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
return try runSnapshotCapturePlan(
|
|
109
|
+
Self.regularVisiblePlan,
|
|
110
110
|
app: app,
|
|
111
111
|
options: options,
|
|
112
|
-
|
|
112
|
+
terminal: .sparseWithFatalOnAXFailure
|
|
113
113
|
)
|
|
114
|
-
|
|
115
|
-
switch capture {
|
|
116
|
-
case .context(let traversalContext):
|
|
117
|
-
context = traversalContext
|
|
118
|
-
case .fallback(let fallback):
|
|
119
|
-
return fallback
|
|
120
|
-
case .empty:
|
|
121
|
-
return DataPayload(nodes: [], truncated: false)
|
|
122
|
-
}
|
|
114
|
+
}
|
|
123
115
|
|
|
116
|
+
func recursiveTreeSnapshotPayload(
|
|
117
|
+
context: SnapshotTraversalContext,
|
|
118
|
+
options: SnapshotOptions
|
|
119
|
+
) -> DataPayload {
|
|
124
120
|
var cachedDescendantElements: [XCUIElement]?
|
|
125
121
|
func collapsedTabDescendants() -> [XCUIElement] {
|
|
126
122
|
if let cachedDescendantElements {
|
|
@@ -253,22 +249,18 @@ extension RunnerTests {
|
|
|
253
249
|
if let blocking = blockingSystemAlertSnapshot() {
|
|
254
250
|
return blocking
|
|
255
251
|
}
|
|
256
|
-
|
|
257
|
-
|
|
252
|
+
return try runSnapshotCapturePlan(
|
|
253
|
+
Self.rawDiagnosticPlan,
|
|
258
254
|
app: app,
|
|
259
255
|
options: options,
|
|
260
|
-
|
|
256
|
+
terminal: .throwOnAXFailure
|
|
261
257
|
)
|
|
262
|
-
|
|
263
|
-
switch capture {
|
|
264
|
-
case .context(let traversalContext):
|
|
265
|
-
context = traversalContext
|
|
266
|
-
case .fallback(let fallback):
|
|
267
|
-
return fallback
|
|
268
|
-
case .empty:
|
|
269
|
-
return DataPayload(nodes: [], truncated: false)
|
|
270
|
-
}
|
|
258
|
+
}
|
|
271
259
|
|
|
260
|
+
func rawTreeSnapshotPayload(
|
|
261
|
+
context: SnapshotTraversalContext,
|
|
262
|
+
options: SnapshotOptions
|
|
263
|
+
) throws -> DataPayload {
|
|
272
264
|
var nodes: [SnapshotNode] = []
|
|
273
265
|
|
|
274
266
|
func walk(_ snapshot: XCUIElementSnapshot, depth: Int, parentIndex: Int?) throws {
|
|
@@ -310,9 +302,9 @@ extension RunnerTests {
|
|
|
310
302
|
return DataPayload(nodes: nodes, truncated: false)
|
|
311
303
|
}
|
|
312
304
|
|
|
313
|
-
|
|
305
|
+
func snapshotFlatInteractive(app: XCUIApplication, options: SnapshotOptions) -> DataPayload {
|
|
314
306
|
var nodes: [SnapshotNode] = [
|
|
315
|
-
|
|
307
|
+
interactiveRootNode(rect: .zero)
|
|
316
308
|
]
|
|
317
309
|
if options.depth == 0 {
|
|
318
310
|
return DataPayload(nodes: nodes, truncated: false)
|
|
@@ -356,7 +348,13 @@ extension RunnerTests {
|
|
|
356
348
|
return left.type < right.type
|
|
357
349
|
}
|
|
358
350
|
|
|
359
|
-
|
|
351
|
+
// The synthetic root doubles as the daemon's viewport (find.ts prefers on-screen matches
|
|
352
|
+
// inside nodes[0].rect): use the real screen viewport when capture produced a finite one,
|
|
353
|
+
// so off-screen candidates can never inflate the root and masquerade as on-screen.
|
|
354
|
+
let rootRect = viewport.isInfinite || viewport.isNull || viewport.isEmpty
|
|
355
|
+
? interactiveRootFrame(for: candidates)
|
|
356
|
+
: viewport
|
|
357
|
+
nodes[0] = interactiveRootNode(rect: rootRect)
|
|
360
358
|
for candidate in candidates {
|
|
361
359
|
nodes.append(
|
|
362
360
|
SnapshotNode(
|
|
@@ -380,78 +378,26 @@ extension RunnerTests {
|
|
|
380
378
|
return DataPayload(nodes: nodes, truncated: truncated)
|
|
381
379
|
}
|
|
382
380
|
|
|
383
|
-
|
|
381
|
+
func snapshotAccessibilityUnavailable(failure: SnapshotCaptureFailure) -> DataPayload {
|
|
384
382
|
NSLog("AGENT_DEVICE_RUNNER_SNAPSHOT_AX_UNAVAILABLE=%@", failure.message)
|
|
385
383
|
invalidateCachedTarget(reason: Self.axSnapshotUnavailableReason)
|
|
384
|
+
// This is a planned terminal result, so it carries the structured verdict like every other
|
|
385
|
+
// planned snapshot — downstream sparse handling keys off the verdict, not node shapes.
|
|
386
386
|
return sparseTruncatedSnapshotPayload(
|
|
387
387
|
message: recoveredSnapshotMessage(failure),
|
|
388
|
+
snapshotQuality: SnapshotQuality(
|
|
389
|
+
state: "sparse",
|
|
390
|
+
backend: SnapshotBackendKind.recursiveTree.rawValue,
|
|
391
|
+
reason: failure.message,
|
|
392
|
+
reasonCode: "ax-rejected",
|
|
393
|
+
effectiveDepth: nil,
|
|
394
|
+
collapsedLeafIndexes: nil
|
|
395
|
+
),
|
|
388
396
|
runnerFatal: true,
|
|
389
397
|
runnerFatalReason: Self.axSnapshotUnavailableReason
|
|
390
398
|
)
|
|
391
399
|
}
|
|
392
400
|
|
|
393
|
-
private func captureSnapshotTraversalContext(
|
|
394
|
-
app: XCUIApplication,
|
|
395
|
-
options: SnapshotOptions,
|
|
396
|
-
allowInteractiveUnavailableFallback: Bool
|
|
397
|
-
) throws -> SnapshotTraversalCapture {
|
|
398
|
-
do {
|
|
399
|
-
guard let context = try makeSnapshotTraversalContext(app: app, options: options) else {
|
|
400
|
-
return .empty
|
|
401
|
-
}
|
|
402
|
-
return .context(context)
|
|
403
|
-
} catch let failure as SnapshotCaptureFailure {
|
|
404
|
-
if let fallback = snapshotDepthLimitedAccessibilityFallback(
|
|
405
|
-
app: app,
|
|
406
|
-
options: options,
|
|
407
|
-
failure: failure
|
|
408
|
-
) {
|
|
409
|
-
return .fallback(fallback)
|
|
410
|
-
}
|
|
411
|
-
if allowInteractiveUnavailableFallback && options.interactiveOnly {
|
|
412
|
-
return .fallback(snapshotAccessibilityUnavailable(failure: failure))
|
|
413
|
-
}
|
|
414
|
-
throw failure
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
private func snapshotDepthLimitedAccessibilityFallback(
|
|
419
|
-
app: XCUIApplication,
|
|
420
|
-
options: SnapshotOptions,
|
|
421
|
-
failure: SnapshotCaptureFailure
|
|
422
|
-
) -> DataPayload? {
|
|
423
|
-
guard let requestedDepth = options.depth else {
|
|
424
|
-
return nil
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
NSLog(
|
|
428
|
-
"AGENT_DEVICE_RUNNER_SNAPSHOT_DEPTH_FALLBACK=%@",
|
|
429
|
-
failure.message
|
|
430
|
-
)
|
|
431
|
-
|
|
432
|
-
if requestedDepth <= 0 {
|
|
433
|
-
return sparseTruncatedSnapshotPayload(message: recoveredSnapshotMessage(failure))
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// Raw depth-limited recovery intentionally falls back to sparse interactive discovery because
|
|
437
|
-
// the raw AX tree is the failed operation.
|
|
438
|
-
let fallback = snapshotFlatInteractive(
|
|
439
|
-
app: app,
|
|
440
|
-
options: SnapshotOptions(
|
|
441
|
-
interactiveOnly: true,
|
|
442
|
-
compact: options.compact,
|
|
443
|
-
depth: requestedDepth,
|
|
444
|
-
scope: options.scope,
|
|
445
|
-
raw: false
|
|
446
|
-
)
|
|
447
|
-
)
|
|
448
|
-
return DataPayload(
|
|
449
|
-
message: recoveredSnapshotMessage(failure),
|
|
450
|
-
nodes: fallback.nodes,
|
|
451
|
-
truncated: true
|
|
452
|
-
)
|
|
453
|
-
}
|
|
454
|
-
|
|
455
401
|
private func recoveredSnapshotMessage(_ failure: SnapshotCaptureFailure) -> String {
|
|
456
402
|
return "\(failure.message) Hint: \(failure.hint)"
|
|
457
403
|
}
|
|
@@ -464,15 +410,17 @@ extension RunnerTests {
|
|
|
464
410
|
)
|
|
465
411
|
}
|
|
466
412
|
|
|
467
|
-
|
|
468
|
-
message: String,
|
|
413
|
+
func sparseTruncatedSnapshotPayload(
|
|
414
|
+
message: String? = nil,
|
|
415
|
+
snapshotQuality: SnapshotQuality? = nil,
|
|
469
416
|
runnerFatal: Bool? = nil,
|
|
470
417
|
runnerFatalReason: String? = nil
|
|
471
418
|
) -> DataPayload {
|
|
472
419
|
return DataPayload(
|
|
473
420
|
message: message,
|
|
474
|
-
nodes: [
|
|
421
|
+
nodes: [interactiveRootNode(rect: .zero)],
|
|
475
422
|
truncated: true,
|
|
423
|
+
snapshotQuality: snapshotQuality,
|
|
476
424
|
runnerFatal: runnerFatal,
|
|
477
425
|
runnerFatalReason: runnerFatalReason
|
|
478
426
|
)
|
|
@@ -521,40 +469,7 @@ extension RunnerTests {
|
|
|
521
469
|
XCTAssertEqual(failure.hint, Self.rawSnapshotTooLargeHint)
|
|
522
470
|
}
|
|
523
471
|
|
|
524
|
-
func
|
|
525
|
-
currentApp = app
|
|
526
|
-
currentBundleId = "com.example.app"
|
|
527
|
-
|
|
528
|
-
let payload = snapshotDepthLimitedAccessibilityFallback(
|
|
529
|
-
app: app,
|
|
530
|
-
options: SnapshotOptions(
|
|
531
|
-
interactiveOnly: false,
|
|
532
|
-
compact: false,
|
|
533
|
-
depth: 0,
|
|
534
|
-
scope: nil,
|
|
535
|
-
raw: false
|
|
536
|
-
),
|
|
537
|
-
failure: SnapshotCaptureFailure(
|
|
538
|
-
code: Self.axSnapshotErrorCode,
|
|
539
|
-
message: "\(Self.axSnapshotFailureMessage) kAXErrorIllegalArgument.",
|
|
540
|
-
hint: Self.axSnapshotHint
|
|
541
|
-
)
|
|
542
|
-
)
|
|
543
|
-
|
|
544
|
-
XCTAssertEqual(
|
|
545
|
-
payload?.message,
|
|
546
|
-
"\(Self.axSnapshotFailureMessage) kAXErrorIllegalArgument. Hint: \(Self.axSnapshotHint)"
|
|
547
|
-
)
|
|
548
|
-
XCTAssertEqual(payload?.nodes?.count, 1)
|
|
549
|
-
XCTAssertEqual(payload?.nodes?.first?.type, "Application")
|
|
550
|
-
XCTAssertEqual(payload?.truncated, true)
|
|
551
|
-
XCTAssertNil(payload?.runnerFatal)
|
|
552
|
-
XCTAssertNil(payload?.runnerFatalReason)
|
|
553
|
-
XCTAssertNotNil(currentApp)
|
|
554
|
-
XCTAssertEqual(currentBundleId, "com.example.app")
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
private func compactInteractiveRootNode(rect: CGRect) -> SnapshotNode {
|
|
472
|
+
private func interactiveRootNode(rect: CGRect) -> SnapshotNode {
|
|
558
473
|
SnapshotNode(
|
|
559
474
|
index: 0,
|
|
560
475
|
type: "Application",
|
|
@@ -573,7 +488,7 @@ extension RunnerTests {
|
|
|
573
488
|
)
|
|
574
489
|
}
|
|
575
490
|
|
|
576
|
-
private func
|
|
491
|
+
private func interactiveRootFrame(for candidates: [SnapshotNode]) -> CGRect {
|
|
577
492
|
guard !candidates.isEmpty else {
|
|
578
493
|
return .zero
|
|
579
494
|
}
|
|
@@ -605,9 +520,6 @@ extension RunnerTests {
|
|
|
605
520
|
) -> Bool {
|
|
606
521
|
let type = snapshot.elementType
|
|
607
522
|
let hasContent = !label.isEmpty || !identifier.isEmpty || (valueText != nil)
|
|
608
|
-
if options.compact && type == .other && !hasContent && !hittable {
|
|
609
|
-
if snapshot.children.count <= 1 { return false }
|
|
610
|
-
}
|
|
611
523
|
if options.interactiveOnly {
|
|
612
524
|
if isScrollableContainer(snapshot, visible: visible) { return true }
|
|
613
525
|
#if os(macOS)
|
|
@@ -620,9 +532,6 @@ extension RunnerTests {
|
|
|
620
532
|
if hasContent { return true }
|
|
621
533
|
return false
|
|
622
534
|
}
|
|
623
|
-
if options.compact {
|
|
624
|
-
return hasContent || hittable
|
|
625
|
-
}
|
|
626
535
|
if regularSnapshot {
|
|
627
536
|
if type == .application || type == .window { return true }
|
|
628
537
|
return visible
|
|
@@ -649,7 +558,7 @@ extension RunnerTests {
|
|
|
649
558
|
return true
|
|
650
559
|
}
|
|
651
560
|
|
|
652
|
-
|
|
561
|
+
func makeSnapshotTraversalContext(
|
|
653
562
|
app: XCUIApplication,
|
|
654
563
|
options: SnapshotOptions
|
|
655
564
|
) throws -> SnapshotTraversalContext? {
|
|
@@ -692,7 +601,7 @@ extension RunnerTests {
|
|
|
692
601
|
return nil
|
|
693
602
|
}
|
|
694
603
|
|
|
695
|
-
|
|
604
|
+
func safeSnapshotViewport(app: XCUIApplication) -> CGRect {
|
|
696
605
|
safely("SNAPSHOT_VIEWPORT", CGRect.infinite) { snapshotViewport(app: app) }
|
|
697
606
|
}
|
|
698
607
|
|
|
@@ -725,6 +634,10 @@ extension RunnerTests {
|
|
|
725
634
|
|| (normalized.contains("illegal argument") && normalized.contains("snapshot"))
|
|
726
635
|
}
|
|
727
636
|
|
|
637
|
+
static func isAxSnapshotFailure(_ failure: SnapshotCaptureFailure) -> Bool {
|
|
638
|
+
failure.code == Self.axSnapshotErrorCode || isAxIllegalArgument(failure.message)
|
|
639
|
+
}
|
|
640
|
+
|
|
728
641
|
private func evaluateSnapshot(
|
|
729
642
|
_ snapshot: XCUIElementSnapshot,
|
|
730
643
|
in context: SnapshotTraversalContext
|
|
@@ -826,15 +739,6 @@ extension RunnerTests {
|
|
|
826
739
|
}
|
|
827
740
|
|
|
828
741
|
private func snapshotViewport(app: XCUIApplication) -> CGRect {
|
|
829
|
-
let windows = app.windows.allElementsBoundByIndex
|
|
830
|
-
let windowFrames = windows
|
|
831
|
-
.filter { $0.exists && !$0.frame.isNull && !$0.frame.isEmpty }
|
|
832
|
-
.map(\.frame)
|
|
833
|
-
if let largestWindowFrame = windowFrames.max(by: { left, right in
|
|
834
|
-
left.width * left.height < right.width * right.height
|
|
835
|
-
}) {
|
|
836
|
-
return largestWindowFrame
|
|
837
|
-
}
|
|
838
742
|
let appFrame = app.frame
|
|
839
743
|
if !appFrame.isNull && !appFrame.isEmpty {
|
|
840
744
|
return appFrame
|
|
@@ -855,7 +759,7 @@ extension RunnerTests {
|
|
|
855
759
|
return nil
|
|
856
760
|
}
|
|
857
761
|
|
|
858
|
-
|
|
762
|
+
func isVisibleInViewport(_ rect: CGRect, _ viewport: CGRect) -> Bool {
|
|
859
763
|
if rect.isNull || rect.isEmpty { return false }
|
|
860
764
|
return rect.intersects(viewport)
|
|
861
765
|
}
|
|
@@ -1191,19 +1095,19 @@ extension RunnerTests {
|
|
|
1191
1095
|
let label = element.label.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
1192
1096
|
let identifier = element.identifier.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
1193
1097
|
let valueText = snapshotValueText(element)
|
|
1194
|
-
let hasContent = !label.isEmpty || !identifier.isEmpty || valueText != nil
|
|
1195
1098
|
let elementType = element.elementType
|
|
1196
1099
|
let enabled = element.isEnabled
|
|
1197
1100
|
let hittable = visible && enabled && element.isHittable
|
|
1198
|
-
|
|
1101
|
+
let filterNode = FlatSnapshotFilterNode(
|
|
1102
|
+
isRoot: false,
|
|
1103
|
+
label: label,
|
|
1104
|
+
identifier: identifier,
|
|
1105
|
+
valueText: valueText,
|
|
1106
|
+
visible: visible
|
|
1107
|
+
)
|
|
1108
|
+
if !flatSnapshotFilterDecision(filterNode, options: options, insideMatchedScope: false).include {
|
|
1199
1109
|
return
|
|
1200
1110
|
}
|
|
1201
|
-
if let scope = options.scope?.trimmingCharacters(in: .whitespacesAndNewlines), !scope.isEmpty {
|
|
1202
|
-
let haystack = [label, identifier, valueText ?? ""].joined(separator: "\n")
|
|
1203
|
-
if !haystack.localizedCaseInsensitiveContains(scope) {
|
|
1204
|
-
return
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
1111
|
|
|
1208
1112
|
node = SnapshotNode(
|
|
1209
1113
|
index: index,
|