agent-device 0.20.9 → 0.20.10
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/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.9.apk → agent-device-android-ime-helper-0.20.10.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.10.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.9.manifest.json → agent-device-android-ime-helper-0.20.10.manifest.json} +4 -4
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.9.apk → agent-device-android-snapshot-helper-0.20.10.apk} +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.10.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.9.manifest.json → agent-device-android-snapshot-helper-0.20.10.manifest.json} +6 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +6 -5
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +4 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +94 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +22 -23
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +3 -23
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +10 -11
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +30 -12
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +8 -5
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +133 -63
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +13 -12
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentation.swift +183 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentationTests.swift +0 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +20 -18
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputCandidatePolicy.swift +19 -0
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/ai-sdk.d.ts +61 -0
- package/dist/src/ai-sdk.js +1 -0
- package/dist/src/android-adb.d.ts +1 -1
- package/dist/src/app-lifecycle.js +1 -1
- package/dist/src/app-log-reconnect.js +1 -1
- package/dist/src/app-log-runtime.js +3 -3
- package/dist/src/app-resolution.js +2 -2
- package/dist/src/apps.js +5 -5
- package/dist/src/audio-probe.js +1 -1
- package/dist/src/boot-diagnostics.js +2 -2
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +30 -23
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +7 -7
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-types.d.ts +1582 -0
- package/dist/src/command-tools.js +2 -0
- package/dist/src/connection-runtime.js +1 -1
- package/dist/src/contracts.d.ts +1 -1
- package/dist/src/contracts.js +1 -1
- package/dist/src/daemon-shutdown-report.js +1 -1
- package/dist/src/daemon.js +1 -1
- package/dist/src/debug-symbols.js +1 -1
- package/dist/src/device-input-state.js +1 -1
- package/dist/src/dispatch.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/finders.js +1 -1
- package/dist/src/generic-settle.js +1 -1
- package/dist/src/generic.js +1 -1
- package/dist/src/helper-package-install.js +1 -1
- package/dist/src/helper.js +1 -1
- package/dist/src/ime-lifecycle.js +1 -1
- package/dist/src/ime-recovery-marker.js +1 -1
- package/dist/src/index.d.ts +2 -1578
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +1 -1
- package/dist/src/input-actions3.js +1 -1
- package/dist/src/install-source2.js +1 -1
- package/dist/src/interaction-common.js +1 -1
- package/dist/src/interaction-runtime.js +1 -1
- package/dist/src/interaction-snapshot.js +1 -1
- package/dist/src/interaction.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor.js +2 -2
- package/dist/src/interactor2.js +1 -1
- package/dist/src/interactors.js +1 -1
- package/dist/src/internal/bin.js +2 -2
- package/dist/src/internal/daemon.js +4 -4
- package/dist/src/internal/png-worker.js +1 -1
- package/dist/src/lease-context.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/limrun.d.ts +10 -2
- package/dist/src/linux.js +1 -1
- package/dist/src/location-coordinates.js +1 -1
- package/dist/src/{screenshot-geometry.js → mobile-snapshot-semantics.js} +1 -1
- package/dist/src/perf.js +1 -1
- package/dist/src/platform-runtime-open-target.js +1 -1
- package/dist/src/platform-runtime-operation-host.js +4 -4
- package/dist/src/platform-runtime.js +1 -1
- package/dist/src/platform-runtime2.js +1 -1
- package/dist/src/png-resize.js +1 -1
- package/dist/src/provider.js +1 -1
- package/dist/src/proxy.js +1 -1
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-runtime.js +1 -1
- package/dist/src/registry.js +27 -27
- package/dist/src/remote-config2.js +1 -1
- package/dist/src/replay.js +2 -2
- package/dist/src/reporting.js +5 -5
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-disposal.js +1 -1
- package/dist/src/runner-sequence.js +1 -1
- package/dist/src/runtime.js +3 -3
- package/dist/src/runtime2.js +4 -4
- package/dist/src/runtime3.js +1 -1
- package/dist/src/runtime4.js +3 -3
- package/dist/src/runtime5.js +1 -1
- package/dist/src/runtime6.js +1 -1
- package/dist/src/runtime7.js +1 -1
- package/dist/src/runtime8.js +1 -1
- package/dist/src/runtime9.js +1 -1
- package/dist/src/screenshot-result.js +4 -4
- package/dist/src/screenshot.js +1 -1
- package/dist/src/script-source-bundle.js +16 -0
- package/dist/src/sdk-android-adb.d.ts +40 -40
- package/dist/src/sdk-android-adb.js +4 -4
- package/dist/src/sdk-batch-runner.js +3 -3
- package/dist/src/sdk-contracts.d.ts +122 -85
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-finders.d.ts +1 -1
- package/dist/src/sdk-finders.js +1 -1
- package/dist/src/sdk-selectors.d.ts +89 -77
- package/dist/src/sdk-selectors.js +1 -1
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.js +1 -1
- package/dist/src/server.js +10 -3
- package/dist/src/session-target-evidence.js +1 -1
- package/dist/src/session2.js +7 -8
- package/dist/src/shared.js +1 -1
- package/dist/src/snapshot-runtime.js +1 -1
- package/dist/src/snapshot-scope.js +1 -0
- package/dist/src/snapshot.js +6 -6
- package/dist/src/snapshot2.js +1 -1
- package/dist/src/snapshot3.js +1 -1
- package/dist/src/src.js +1 -1
- package/dist/src/src2.js +1 -1
- package/dist/src/src3.js +1 -1
- package/dist/src/src4.js +1 -0
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/tool-provider3.js +1 -0
- package/dist/src/verified-file.js +1 -1
- package/dist/src/web.js +1 -1
- package/package.json +21 -8
- package/server.json +2 -2
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.9.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.9.apk.sha256 +0 -1
- package/dist/src/cancel.js +0 -1
- package/dist/src/prepare-kind.js +0 -15
- package/dist/src/selector-vocabulary.js +0 -1
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift
CHANGED
|
@@ -30,6 +30,15 @@ extension RunnerTests {
|
|
|
30
30
|
let visible: Bool
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
private struct SnapshotTraversalEntry {
|
|
34
|
+
let snapshot: XCUIElementSnapshot
|
|
35
|
+
let depth: Int
|
|
36
|
+
let visibleDepth: Int
|
|
37
|
+
let parentIndex: Int?
|
|
38
|
+
let nearestScrollAnchor: (index: Int, rect: CGRect)?
|
|
39
|
+
let projectionCursor: FlatSnapshotProjectionCursor
|
|
40
|
+
}
|
|
41
|
+
|
|
33
42
|
struct SnapshotCaptureFailure: Error {
|
|
34
43
|
let code: String
|
|
35
44
|
let message: String
|
|
@@ -108,7 +117,7 @@ extension RunnerTests {
|
|
|
108
117
|
// `boundedBlockingSystemAlertSnapshot`'s probe closure (see `systemModalProbeOverrideForTesting`
|
|
109
118
|
// in RunnerTests.swift), so reverting this entry point to bypass the bounded probe fails the
|
|
110
119
|
// regression test.
|
|
111
|
-
func snapshotFast(app: XCUIApplication, options:
|
|
120
|
+
func snapshotFast(app: XCUIApplication, options: PresentationOptions) throws -> DataPayload {
|
|
112
121
|
let deadline = Date().addingTimeInterval(Self.snapshotPlanBudget)
|
|
113
122
|
if let blocking = boundedBlockingSystemAlertSnapshot(deadline: deadline) {
|
|
114
123
|
return blocking
|
|
@@ -122,10 +131,10 @@ extension RunnerTests {
|
|
|
122
131
|
)
|
|
123
132
|
}
|
|
124
133
|
|
|
125
|
-
func
|
|
134
|
+
func recursiveTreeSnapshotAcquisition(
|
|
126
135
|
context: SnapshotTraversalContext,
|
|
127
|
-
options:
|
|
128
|
-
) ->
|
|
136
|
+
options: PresentationOptions
|
|
137
|
+
) -> SnapshotAcquisition {
|
|
129
138
|
var cachedDescendantElements: [XCUIElement]?
|
|
130
139
|
func collapsedTabDescendants() -> [XCUIElement] {
|
|
131
140
|
if let cachedDescendantElements {
|
|
@@ -138,7 +147,7 @@ extension RunnerTests {
|
|
|
138
147
|
return result.elements
|
|
139
148
|
}
|
|
140
149
|
|
|
141
|
-
var nodes: [
|
|
150
|
+
var nodes: [RawAXNode] = []
|
|
142
151
|
var hiddenContentHintsByNodeIndex: [Int: (above: Bool, below: Bool)] = [:]
|
|
143
152
|
let rootEvaluation = evaluateSnapshot(context.rootSnapshot, in: context)
|
|
144
153
|
nodes.append(
|
|
@@ -166,35 +175,79 @@ extension RunnerTests {
|
|
|
166
175
|
visible: rootEvaluation.visible,
|
|
167
176
|
nodeIndex: 0
|
|
168
177
|
)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
178
|
+
#if os(iOS)
|
|
179
|
+
let rootProjection = flatSnapshotProjectionTransition(
|
|
180
|
+
frame: context.rootSnapshot.frame,
|
|
181
|
+
intersectsViewportAndScrollClip: rootEvaluation.visible,
|
|
182
|
+
elementType: context.rootSnapshot.elementType,
|
|
183
|
+
hasChildren: !context.rootSnapshot.children.isEmpty,
|
|
184
|
+
cursor: .root
|
|
185
|
+
)
|
|
186
|
+
let rootDescendantProjectionCursor = rootProjection.decision.descendants
|
|
187
|
+
#else
|
|
188
|
+
let rootDescendantProjectionCursor = FlatSnapshotProjectionCursor.root
|
|
189
|
+
#endif
|
|
190
|
+
var stack: [SnapshotTraversalEntry] = context.rootSnapshot.children.map {
|
|
191
|
+
SnapshotTraversalEntry(
|
|
192
|
+
snapshot: $0,
|
|
193
|
+
depth: 1,
|
|
194
|
+
visibleDepth: 1,
|
|
195
|
+
parentIndex: 0,
|
|
196
|
+
nearestScrollAnchor: rootScrollAnchor,
|
|
197
|
+
projectionCursor: rootDescendantProjectionCursor
|
|
198
|
+
)
|
|
199
|
+
}
|
|
173
200
|
|
|
174
|
-
while let
|
|
201
|
+
while let entry = stack.popLast() {
|
|
202
|
+
let snapshot = entry.snapshot
|
|
203
|
+
let depth = entry.depth
|
|
204
|
+
let visibleDepth = entry.visibleDepth
|
|
205
|
+
let parentIndex = entry.parentIndex
|
|
206
|
+
let nearestScrollAnchor = entry.nearestScrollAnchor
|
|
207
|
+
let projectionCursor = entry.projectionCursor
|
|
175
208
|
if let limit = options.depth, depth > limit { continue }
|
|
176
209
|
|
|
177
210
|
let evaluation = evaluateSnapshot(snapshot, in: context)
|
|
178
|
-
let
|
|
211
|
+
let intersectsViewportAndScrollClip = isVisibleInRegularSnapshot(
|
|
179
212
|
snapshot.frame,
|
|
180
213
|
viewport: context.viewport,
|
|
181
214
|
scrollContainerAnchor: nearestScrollAnchor
|
|
182
215
|
)
|
|
183
|
-
if
|
|
216
|
+
#if os(iOS)
|
|
217
|
+
let projectionTransition = flatSnapshotProjectionTransition(
|
|
218
|
+
frame: snapshot.frame,
|
|
219
|
+
intersectsViewportAndScrollClip: intersectsViewportAndScrollClip,
|
|
220
|
+
elementType: snapshot.elementType,
|
|
221
|
+
hasChildren: !snapshot.children.isEmpty,
|
|
222
|
+
cursor: projectionCursor
|
|
223
|
+
)
|
|
224
|
+
let projection = projectionTransition.decision
|
|
225
|
+
#else
|
|
226
|
+
let projectionTransition = FlatSnapshotProjectionTransition(
|
|
227
|
+
decision: FlatSnapshotProjectionDecision(
|
|
228
|
+
presentationVisible: intersectsViewportAndScrollClip,
|
|
229
|
+
descendants: .root
|
|
230
|
+
),
|
|
231
|
+
hiddenContentFrame: !intersectsViewportAndScrollClip ? snapshot.frame : nil
|
|
232
|
+
)
|
|
233
|
+
let projection = projectionTransition.decision
|
|
234
|
+
#endif
|
|
235
|
+
if let hiddenFrame = projectionTransition.hiddenContentFrame, let nearestScrollAnchor
|
|
236
|
+
{
|
|
184
237
|
rememberHiddenContentHint(
|
|
185
|
-
for:
|
|
238
|
+
for: hiddenFrame,
|
|
186
239
|
relativeTo: nearestScrollAnchor,
|
|
187
240
|
hints: &hiddenContentHintsByNodeIndex
|
|
188
241
|
)
|
|
189
242
|
}
|
|
190
|
-
let include =
|
|
243
|
+
let include = shouldAcquireSnapshotNode(
|
|
191
244
|
snapshot: snapshot,
|
|
192
245
|
label: evaluation.label,
|
|
193
246
|
identifier: evaluation.identifier,
|
|
194
247
|
valueText: evaluation.valueText,
|
|
195
248
|
options: options,
|
|
196
249
|
hittable: evaluation.hittable,
|
|
197
|
-
visible:
|
|
250
|
+
visible: projection.presentationVisible,
|
|
198
251
|
regularSnapshot: true
|
|
199
252
|
)
|
|
200
253
|
|
|
@@ -217,7 +270,7 @@ extension RunnerTests {
|
|
|
217
270
|
nextScrollContainerAnchor =
|
|
218
271
|
scrollContainerAnchor(
|
|
219
272
|
for: snapshot,
|
|
220
|
-
visible:
|
|
273
|
+
visible: intersectsViewportAndScrollClip,
|
|
221
274
|
nodeIndex: currentIndex
|
|
222
275
|
)
|
|
223
276
|
?? nearestScrollAnchor
|
|
@@ -225,7 +278,16 @@ extension RunnerTests {
|
|
|
225
278
|
nextScrollContainerAnchor = nearestScrollAnchor
|
|
226
279
|
}
|
|
227
280
|
for child in snapshot.children.reversed() {
|
|
228
|
-
stack.append(
|
|
281
|
+
stack.append(
|
|
282
|
+
SnapshotTraversalEntry(
|
|
283
|
+
snapshot: child,
|
|
284
|
+
depth: depth + 1,
|
|
285
|
+
visibleDepth: nextVisibleDepth,
|
|
286
|
+
parentIndex: currentIndex,
|
|
287
|
+
nearestScrollAnchor: nextScrollContainerAnchor,
|
|
288
|
+
projectionCursor: projection.descendants
|
|
289
|
+
)
|
|
290
|
+
)
|
|
229
291
|
}
|
|
230
292
|
}
|
|
231
293
|
|
|
@@ -253,14 +315,15 @@ extension RunnerTests {
|
|
|
253
315
|
|
|
254
316
|
}
|
|
255
317
|
|
|
256
|
-
return
|
|
318
|
+
return SnapshotAcquisition(
|
|
257
319
|
nodes: applyHiddenContentHints(hiddenContentHintsByNodeIndex, to: nodes),
|
|
258
|
-
truncated: false
|
|
320
|
+
truncated: false,
|
|
321
|
+
effectiveDepth: nil
|
|
259
322
|
)
|
|
260
323
|
}
|
|
261
324
|
|
|
262
325
|
// See `snapshotFast` above: the single production entry point, no unit-test overload.
|
|
263
|
-
func snapshotRaw(app: XCUIApplication, options:
|
|
326
|
+
func snapshotRaw(app: XCUIApplication, options: PresentationOptions) throws -> DataPayload {
|
|
264
327
|
let deadline = Date().addingTimeInterval(Self.snapshotPlanBudget)
|
|
265
328
|
if let blocking = boundedBlockingSystemAlertSnapshot(deadline: deadline) {
|
|
266
329
|
return blocking
|
|
@@ -351,17 +414,17 @@ extension RunnerTests {
|
|
|
351
414
|
return min(budget, deadlineRemaining)
|
|
352
415
|
}
|
|
353
416
|
|
|
354
|
-
func
|
|
417
|
+
func rawTreeSnapshotAcquisition(
|
|
355
418
|
context: SnapshotTraversalContext,
|
|
356
|
-
options:
|
|
357
|
-
) throws ->
|
|
358
|
-
var nodes: [
|
|
419
|
+
options: PresentationOptions
|
|
420
|
+
) throws -> SnapshotAcquisition {
|
|
421
|
+
var nodes: [RawAXNode] = []
|
|
359
422
|
|
|
360
423
|
func walk(_ snapshot: XCUIElementSnapshot, depth: Int, parentIndex: Int?) throws {
|
|
361
424
|
if let limit = options.depth, depth > limit { return }
|
|
362
425
|
|
|
363
426
|
let evaluation = evaluateSnapshot(snapshot, in: context)
|
|
364
|
-
let include =
|
|
427
|
+
let include = shouldAcquireSnapshotNode(
|
|
365
428
|
snapshot: snapshot,
|
|
366
429
|
label: evaluation.label,
|
|
367
430
|
identifier: evaluation.identifier,
|
|
@@ -393,19 +456,19 @@ extension RunnerTests {
|
|
|
393
456
|
}
|
|
394
457
|
|
|
395
458
|
try walk(context.rootSnapshot, depth: 0, parentIndex: nil)
|
|
396
|
-
return
|
|
459
|
+
return SnapshotAcquisition(nodes: nodes, truncated: false, effectiveDepth: nil)
|
|
397
460
|
}
|
|
398
461
|
|
|
399
|
-
func
|
|
462
|
+
func querySweepSnapshotAcquisition(
|
|
400
463
|
app: XCUIApplication,
|
|
401
|
-
options:
|
|
464
|
+
options: PresentationOptions,
|
|
402
465
|
planDeadline: Date = .distantFuture
|
|
403
|
-
) ->
|
|
404
|
-
var nodes: [
|
|
466
|
+
) -> SnapshotAcquisition {
|
|
467
|
+
var nodes: [RawAXNode] = [
|
|
405
468
|
interactiveRootNode(rect: .zero)
|
|
406
469
|
]
|
|
407
470
|
if options.depth == 0 {
|
|
408
|
-
return
|
|
471
|
+
return SnapshotAcquisition(nodes: nodes, truncated: false, effectiveDepth: nil)
|
|
409
472
|
}
|
|
410
473
|
|
|
411
474
|
// Bounded by both its own sweep budget and the umbrella capture-plan deadline, so a
|
|
@@ -416,7 +479,7 @@ extension RunnerTests {
|
|
|
416
479
|
let deadline = min(sweepDeadline, planDeadline)
|
|
417
480
|
let viewport = safeSnapshotViewport(app: app)
|
|
418
481
|
var seen = Set<String>()
|
|
419
|
-
var candidates: [
|
|
482
|
+
var candidates: [RawAXNode] = []
|
|
420
483
|
let flatElements = flatInteractiveElements(app: app, deadline: deadline)
|
|
421
484
|
var truncated = flatElements.truncated
|
|
422
485
|
for element in flatElements.elements {
|
|
@@ -458,7 +521,7 @@ extension RunnerTests {
|
|
|
458
521
|
nodes[0] = interactiveRootNode(rect: rootRect)
|
|
459
522
|
for candidate in candidates {
|
|
460
523
|
nodes.append(
|
|
461
|
-
|
|
524
|
+
RawAXNode(
|
|
462
525
|
index: nodes.count,
|
|
463
526
|
type: candidate.type,
|
|
464
527
|
label: candidate.label,
|
|
@@ -476,7 +539,7 @@ extension RunnerTests {
|
|
|
476
539
|
)
|
|
477
540
|
)
|
|
478
541
|
}
|
|
479
|
-
return
|
|
542
|
+
return SnapshotAcquisition(nodes: nodes, truncated: truncated, effectiveDepth: nil)
|
|
480
543
|
}
|
|
481
544
|
|
|
482
545
|
func snapshotAccessibilityUnavailable(failure: SnapshotCaptureFailure) -> DataPayload {
|
|
@@ -521,7 +584,7 @@ extension RunnerTests {
|
|
|
521
584
|
) -> DataPayload {
|
|
522
585
|
return DataPayload(
|
|
523
586
|
message: message,
|
|
524
|
-
nodes: [interactiveRootNode(rect: .zero)],
|
|
587
|
+
nodes: [SnapshotPresentation.singleElementRead(interactiveRootNode(rect: .zero))],
|
|
525
588
|
truncated: true,
|
|
526
589
|
snapshotQuality: snapshotQuality,
|
|
527
590
|
runnerFatal: runnerFatal,
|
|
@@ -530,8 +593,8 @@ extension RunnerTests {
|
|
|
530
593
|
}
|
|
531
594
|
|
|
532
595
|
|
|
533
|
-
private func interactiveRootNode(rect: CGRect) ->
|
|
534
|
-
|
|
596
|
+
private func interactiveRootNode(rect: CGRect) -> RawAXNode {
|
|
597
|
+
RawAXNode(
|
|
535
598
|
index: 0,
|
|
536
599
|
type: "Application",
|
|
537
600
|
label: nil,
|
|
@@ -549,7 +612,7 @@ extension RunnerTests {
|
|
|
549
612
|
)
|
|
550
613
|
}
|
|
551
614
|
|
|
552
|
-
private func interactiveRootFrame(for candidates: [
|
|
615
|
+
private func interactiveRootFrame(for candidates: [RawAXNode]) -> CGRect {
|
|
553
616
|
guard !candidates.isEmpty else {
|
|
554
617
|
return .zero
|
|
555
618
|
}
|
|
@@ -569,34 +632,41 @@ extension RunnerTests {
|
|
|
569
632
|
|
|
570
633
|
// MARK: - Snapshot Filtering
|
|
571
634
|
|
|
572
|
-
|
|
635
|
+
/// Conservative acquisition gate. Regular capture keeps every node its visibility policy can
|
|
636
|
+
/// supply; `SnapshotPresentation` alone decides eligibility after the backend returns.
|
|
637
|
+
private func shouldAcquireSnapshotNode(
|
|
573
638
|
snapshot: XCUIElementSnapshot,
|
|
574
639
|
label: String,
|
|
575
640
|
identifier: String,
|
|
576
641
|
valueText: String?,
|
|
577
|
-
options:
|
|
642
|
+
options: PresentationOptions,
|
|
578
643
|
hittable: Bool,
|
|
579
644
|
visible: Bool,
|
|
580
645
|
regularSnapshot: Bool = false
|
|
581
646
|
) -> Bool {
|
|
582
647
|
let type = snapshot.elementType
|
|
583
648
|
let hasContent = !label.isEmpty || !identifier.isEmpty || (valueText != nil)
|
|
584
|
-
if
|
|
585
|
-
if
|
|
649
|
+
#if os(iOS)
|
|
650
|
+
if regularSnapshot && !visible && type != .application && type != .window {
|
|
651
|
+
return false
|
|
652
|
+
}
|
|
653
|
+
#endif
|
|
654
|
+
if regularSnapshot {
|
|
586
655
|
#if os(macOS)
|
|
587
|
-
if !visible && type != .application {
|
|
656
|
+
if options.interactiveOnly && !visible && type != .application {
|
|
588
657
|
return false
|
|
589
658
|
}
|
|
590
659
|
#endif
|
|
660
|
+
if type == .application || type == .window { return true }
|
|
661
|
+
return visible
|
|
662
|
+
}
|
|
663
|
+
if options.interactiveOnly {
|
|
664
|
+
if isScrollableContainer(snapshot, visible: visible) { return true }
|
|
591
665
|
if interactiveTypes.contains(type) { return true }
|
|
592
666
|
if hittable && type != .other { return true }
|
|
593
667
|
if hasContent { return true }
|
|
594
668
|
return false
|
|
595
669
|
}
|
|
596
|
-
if regularSnapshot {
|
|
597
|
-
if type == .application || type == .window { return true }
|
|
598
|
-
return visible
|
|
599
|
-
}
|
|
600
670
|
return true
|
|
601
671
|
}
|
|
602
672
|
|
|
@@ -621,7 +691,7 @@ extension RunnerTests {
|
|
|
621
691
|
|
|
622
692
|
func makeSnapshotTraversalContext(
|
|
623
693
|
app: XCUIApplication,
|
|
624
|
-
options:
|
|
694
|
+
options: PresentationOptions,
|
|
625
695
|
captureDeadline: Date = .distantFuture,
|
|
626
696
|
treeCaptureSliceBudgetOverride: TimeInterval? = nil
|
|
627
697
|
) throws -> SnapshotTraversalContext? {
|
|
@@ -815,8 +885,8 @@ extension RunnerTests {
|
|
|
815
885
|
depth: Int,
|
|
816
886
|
index: Int,
|
|
817
887
|
parentIndex: Int?
|
|
818
|
-
) ->
|
|
819
|
-
return
|
|
888
|
+
) -> RawAXNode {
|
|
889
|
+
return RawAXNode(
|
|
820
890
|
index: index,
|
|
821
891
|
type: elementTypeName(snapshot.elementType),
|
|
822
892
|
label: evaluation.label.isEmpty ? nil : evaluation.label,
|
|
@@ -936,7 +1006,7 @@ extension RunnerTests {
|
|
|
936
1006
|
}
|
|
937
1007
|
|
|
938
1008
|
private func appendCollapsedTabFallbackNodes(
|
|
939
|
-
to nodes: inout [
|
|
1009
|
+
to nodes: inout [RawAXNode],
|
|
940
1010
|
containerSnapshot: XCUIElementSnapshot,
|
|
941
1011
|
resolveElements: () -> [XCUIElement],
|
|
942
1012
|
depth: Int,
|
|
@@ -1001,14 +1071,14 @@ extension RunnerTests {
|
|
|
1001
1071
|
|
|
1002
1072
|
func applyHiddenContentHints(
|
|
1003
1073
|
_ hints: [Int: (above: Bool, below: Bool)],
|
|
1004
|
-
to nodes: [
|
|
1005
|
-
) -> [
|
|
1074
|
+
to nodes: [RawAXNode]
|
|
1075
|
+
) -> [RawAXNode] {
|
|
1006
1076
|
if hints.isEmpty { return nodes }
|
|
1007
1077
|
return nodes.map { node in
|
|
1008
1078
|
guard let hint = hints[node.index] else { return node }
|
|
1009
1079
|
let hiddenContentAbove: Bool? = (node.hiddenContentAbove == true || hint.above) ? true : nil
|
|
1010
1080
|
let hiddenContentBelow: Bool? = (node.hiddenContentBelow == true || hint.below) ? true : nil
|
|
1011
|
-
return
|
|
1081
|
+
return RawAXNode(
|
|
1012
1082
|
index: node.index,
|
|
1013
1083
|
type: node.type,
|
|
1014
1084
|
label: node.label,
|
|
@@ -1034,7 +1104,7 @@ extension RunnerTests {
|
|
|
1034
1104
|
startingIndex: Int,
|
|
1035
1105
|
depth: Int,
|
|
1036
1106
|
parentIndex: Int
|
|
1037
|
-
) -> [
|
|
1107
|
+
) -> [RawAXNode] {
|
|
1038
1108
|
if !containerSnapshot.children.isEmpty { return [] }
|
|
1039
1109
|
guard shouldExpandCollapsedTabContainer(containerSnapshot) else { return [] }
|
|
1040
1110
|
let containerFrame = containerSnapshot.frame
|
|
@@ -1073,7 +1143,7 @@ extension RunnerTests {
|
|
|
1073
1143
|
if uniqueCandidates.count < 2 { return [] }
|
|
1074
1144
|
|
|
1075
1145
|
return uniqueCandidates.enumerated().map { offset, node in
|
|
1076
|
-
|
|
1146
|
+
RawAXNode(
|
|
1077
1147
|
index: startingIndex + offset,
|
|
1078
1148
|
type: node.type,
|
|
1079
1149
|
label: node.label,
|
|
@@ -1096,8 +1166,8 @@ extension RunnerTests {
|
|
|
1096
1166
|
element: XCUIElement,
|
|
1097
1167
|
containerSnapshot: XCUIElementSnapshot,
|
|
1098
1168
|
containerFrame: CGRect
|
|
1099
|
-
) ->
|
|
1100
|
-
var node:
|
|
1169
|
+
) -> RawAXNode? {
|
|
1170
|
+
var node: RawAXNode?
|
|
1101
1171
|
let exceptionMessage = RunnerObjCExceptionCatcher.catchException({
|
|
1102
1172
|
if !element.exists { return }
|
|
1103
1173
|
let elementType = element.elementType
|
|
@@ -1125,7 +1195,7 @@ extension RunnerTests {
|
|
|
1125
1195
|
return
|
|
1126
1196
|
}
|
|
1127
1197
|
|
|
1128
|
-
node =
|
|
1198
|
+
node = RawAXNode(
|
|
1129
1199
|
index: 0,
|
|
1130
1200
|
type: elementTypeName(elementType),
|
|
1131
1201
|
label: label.isEmpty ? nil : label,
|
|
@@ -1262,9 +1332,9 @@ extension RunnerTests {
|
|
|
1262
1332
|
index: Int,
|
|
1263
1333
|
parentIndex: Int?,
|
|
1264
1334
|
viewport: CGRect,
|
|
1265
|
-
options:
|
|
1266
|
-
) ->
|
|
1267
|
-
var node:
|
|
1335
|
+
options: PresentationOptions
|
|
1336
|
+
) -> RawAXNode? {
|
|
1337
|
+
var node: RawAXNode?
|
|
1268
1338
|
let exceptionMessage = RunnerObjCExceptionCatcher.catchException({
|
|
1269
1339
|
if !element.exists { return }
|
|
1270
1340
|
let frame = element.frame
|
|
@@ -1296,7 +1366,7 @@ extension RunnerTests {
|
|
|
1296
1366
|
return
|
|
1297
1367
|
}
|
|
1298
1368
|
|
|
1299
|
-
node =
|
|
1369
|
+
node = RawAXNode(
|
|
1300
1370
|
index: index,
|
|
1301
1371
|
type: elementTypeName(elementType),
|
|
1302
1372
|
label: label.isEmpty ? nil : label,
|
|
@@ -250,7 +250,7 @@ extension RunnerTests {
|
|
|
250
250
|
func runSnapshotCapturePlan(
|
|
251
251
|
_ plan: [SnapshotBackendKind],
|
|
252
252
|
app: XCUIApplication,
|
|
253
|
-
options:
|
|
253
|
+
options: PresentationOptions,
|
|
254
254
|
terminal: SnapshotCaptureTerminalPolicy,
|
|
255
255
|
deadline: Date? = nil
|
|
256
256
|
) throws -> DataPayload {
|
|
@@ -452,10 +452,11 @@ extension RunnerTests {
|
|
|
452
452
|
private func captureWithBackend(
|
|
453
453
|
_ kind: SnapshotBackendKind,
|
|
454
454
|
app: XCUIApplication,
|
|
455
|
-
options:
|
|
455
|
+
options: PresentationOptions,
|
|
456
456
|
deadline: Date,
|
|
457
457
|
treeCaptureSliceBudgetOverride: TimeInterval?
|
|
458
458
|
) throws -> SnapshotBackendCapture? {
|
|
459
|
+
let acquisition: SnapshotAcquisition?
|
|
459
460
|
switch kind {
|
|
460
461
|
case .recursiveTree:
|
|
461
462
|
guard
|
|
@@ -468,28 +469,28 @@ extension RunnerTests {
|
|
|
468
469
|
else {
|
|
469
470
|
return nil
|
|
470
471
|
}
|
|
471
|
-
|
|
472
|
+
acquisition = try runMainThreadWork(
|
|
472
473
|
command: nil,
|
|
473
474
|
timeout: min(treeCaptureSliceBudget, max(0.5, deadline.timeIntervalSinceNow)),
|
|
474
475
|
timeoutError: snapshotMainThreadTimeoutError("processing tree snapshot")
|
|
475
476
|
) {
|
|
476
477
|
options.raw
|
|
477
|
-
? try self.
|
|
478
|
-
: self.
|
|
478
|
+
? try self.rawTreeSnapshotAcquisition(context: context, options: options)
|
|
479
|
+
: self.recursiveTreeSnapshotAcquisition(context: context, options: options)
|
|
479
480
|
}
|
|
480
|
-
return SnapshotBackendCapture(payload: payload, effectiveDepth: nil)
|
|
481
481
|
case .querySweep:
|
|
482
|
-
|
|
482
|
+
acquisition = try runMainThreadWork(
|
|
483
483
|
command: nil,
|
|
484
484
|
timeout: min(Self.flatInteractiveFallbackBudget, max(0.1, deadline.timeIntervalSinceNow)),
|
|
485
485
|
timeoutError: snapshotMainThreadTimeoutError("running query-sweep snapshot")
|
|
486
486
|
) {
|
|
487
|
-
self.
|
|
487
|
+
self.querySweepSnapshotAcquisition(app: app, options: options, planDeadline: deadline)
|
|
488
488
|
}
|
|
489
|
-
return SnapshotBackendCapture(payload: payload, effectiveDepth: nil)
|
|
490
489
|
case .privateAX:
|
|
491
|
-
|
|
490
|
+
acquisition = privateAXSnapshotAcquisition(app: app, options: options, deadline: deadline)
|
|
492
491
|
}
|
|
492
|
+
guard let acquisition else { return nil }
|
|
493
|
+
return SnapshotPresentation.present(acquisition, options: options)
|
|
493
494
|
}
|
|
494
495
|
|
|
495
496
|
// MARK: Quality classifier (the single source of "is this snapshot degraded")
|
|
@@ -529,7 +530,7 @@ extension RunnerTests {
|
|
|
529
530
|
}
|
|
530
531
|
}
|
|
531
532
|
|
|
532
|
-
static func isSparseApplicationWindowTree(_ nodes: [
|
|
533
|
+
static func isSparseApplicationWindowTree(_ nodes: [PresentedNode]) -> Bool {
|
|
533
534
|
guard !nodes.isEmpty else { return false }
|
|
534
535
|
let rootRects = nodes.compactMap { node in
|
|
535
536
|
node.type == "Application" || node.type == "Window" ? node.rect : nil
|
|
@@ -564,7 +565,7 @@ extension RunnerTests {
|
|
|
564
565
|
/// A leaf whose label joins many short segments is a container marked as an accessibility
|
|
565
566
|
/// element: the platform folds every descendant into one merged node. Nothing below it can
|
|
566
567
|
/// be addressed — by automation or by assistive tech. This is app-side; no backend recovers it.
|
|
567
|
-
static func collapsedLeafIndexes(_ nodes: [
|
|
568
|
+
static func collapsedLeafIndexes(_ nodes: [PresentedNode]) -> [Int]? {
|
|
568
569
|
let parents = Set(nodes.compactMap { $0.parentIndex })
|
|
569
570
|
let collapsed = nodes.filter { node in
|
|
570
571
|
guard !parents.contains(node.index) else { return false }
|