agent-device 0.21.12 → 0.21.13
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.21.12.apk → agent-device-android-ime-helper-0.21.13.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.13.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.12.manifest.json → agent-device-android-ime-helper-0.21.13.manifest.json} +4 -4
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.12.apk → agent-device-android-snapshot-helper-0.21.13.apk} +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.13.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.12.manifest.json → agent-device-android-snapshot-helper-0.21.13.manifest.json} +6 -6
- package/apple/macos-helper/Package.swift +4 -0
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/main.swift +3 -6
- package/apple/macos-helper/Tests/AgentDeviceMacOSHelperTests/ScreenshotResponseTests.swift +15 -0
- package/apple/snapshot-bridge/SnapshotBridgeRuntime.m +47 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +99 -42
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/Info.plist +23 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +17 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAppScreenCapture.swift +21 -13
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerScrollViewportPolicy.swift +1 -162
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +0 -9
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +0 -56
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSystemSurfaceHostPolicy.swift +0 -48
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift +0 -50
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +22 -568
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +21 -9
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+BlockingSystemModalResolution.swift +0 -36
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandDispatch.swift +630 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +18 -2236
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -338
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Environment.swift +0 -12
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+GestureExecution.swift +165 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +0 -24
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Keyboard.swift +0 -142
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +90 -39
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+MainThreadWork.swift +78 -106
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +23 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +147 -95
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +0 -209
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +86 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollDragExecution.swift +287 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +1 -200
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +0 -185
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +75 -285
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotAcquisition.swift +23 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotBackendCapabilities.swift +0 -78
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +83 -578
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCaptureTarget.swift +106 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotExecution.swift +142 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTiming.swift +49 -78
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedCommitDeadline.swift +0 -44
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +27 -97
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedInteraction.swift +1 -11
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +11 -87
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +2 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +1 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +0 -35
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputCandidatePolicy.swift +0 -31
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +2 -18
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +34 -52
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +0 -22
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TypeExecution.swift +142 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +22 -6
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +140 -20
- package/dist/src/absence-observation-errors.js +1 -1
- package/dist/src/adapter.js +1 -1
- package/dist/src/agent-device-client.js +1 -1
- package/dist/src/alert-runtime.js +1 -1
- package/dist/src/android-adb.d.ts +1 -1
- package/dist/src/app-launch.js +2 -2
- package/dist/src/app-log-runtime2.js +3 -3
- package/dist/src/app-resolution.js +2 -2
- package/dist/src/back-mode.js +1 -1
- package/dist/src/capture-disclosure.js +1 -1
- package/dist/src/capture.js +1 -1
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +6 -5
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +1 -1
- package/dist/src/client-types.d.ts +4 -5
- package/dist/src/code-signature.js +1 -1
- package/dist/src/command-schema.js +3 -3
- package/dist/src/command-tools.js +3 -3
- package/dist/src/connection.js +1 -1
- package/dist/src/daemon-client-lifecycle.js +1 -1
- package/dist/src/daemon-resolution.js +1 -1
- package/dist/src/device-claim-rule.js +2 -2
- package/dist/src/device-input-state.d.ts +1 -1
- package/dist/src/device-session.js +1 -1
- package/dist/src/devicectl.js +1 -1
- package/dist/src/display-inventory.js +1 -1
- package/dist/src/doctor-facade.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/gesture-plan-types.d.ts +38 -0
- package/dist/src/harmonyos.js +1 -1
- package/dist/src/helper.js +1 -1
- package/dist/src/host.js +1 -1
- package/dist/src/install-source-network-transport.js +1 -1
- package/dist/src/install-source2.js +1 -1
- package/dist/src/interaction-ref-policy.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor-operation-catalog.js +1 -1
- package/dist/src/interactor.js +4 -4
- package/dist/src/interactor2.js +1 -1
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +2 -2
- package/dist/src/inventory2.js +1 -1
- package/dist/src/ios-snapshot-acquisition.js +1 -1
- package/dist/src/ios-snapshot-runtime.js +1 -1
- package/dist/src/limrun-runtime-dependencies.js +1 -1
- package/dist/src/limrun.d.ts +435 -4
- package/dist/src/linux.js +1 -1
- package/dist/src/local-interactor-operation-set.js +1 -1
- package/dist/src/managed-device-scope.js +1 -1
- package/dist/src/mechanics.js +4 -4
- package/dist/src/mobile-snapshot-semantics.js +1 -1
- package/dist/src/perf-facade.js +1 -2
- package/dist/src/perf-runtime-plan.js +1 -1
- package/dist/src/perf-target.js +2 -0
- package/dist/src/physical-device-apps.js +1 -0
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/platform-request-scope.js +1 -1
- package/dist/src/platform-runtime-operation-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
- package/dist/src/platform-runtime-unavailable.js +1 -1
- package/dist/src/platform-runtime.js +1 -1
- package/dist/src/platform-runtime2.js +1 -1
- package/dist/src/provider-webdriver.js +1 -1
- package/dist/src/proxy.js +1 -1
- package/dist/src/quality-warnings.js +1 -1
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-runtime.js +1 -1
- package/dist/src/registry.js +35 -35
- package/dist/src/request-admission.js +1 -1
- package/dist/src/request-runtime-binding.js +1 -1
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-dev-tools-security.js +1 -1
- package/dist/src/runner-device-readiness.js +1 -1
- package/dist/src/runner-disposal.js +1 -1
- package/dist/src/runner-error-classification.js +3 -0
- package/dist/src/runner-operations-facade.js +1 -1
- package/dist/src/runner-presentation.js +1 -1
- package/dist/src/runner.js +1 -1
- package/dist/src/runtime.js +3 -3
- package/dist/src/runtime10.js +1 -1
- package/dist/src/runtime2.js +2 -2
- package/dist/src/runtime4.js +5 -5
- 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/screen-recording-admission-ledger.js +1 -1
- package/dist/src/screen-recording-resource-recovery.js +1 -1
- package/dist/src/screen-recording-transport.js +1 -1
- package/dist/src/screenshot-runtime.js +1 -1
- package/dist/src/screenshot3.js +1 -1
- package/dist/src/script.js +1 -1
- package/dist/src/scroll-command.d.ts +377 -0
- package/dist/src/scroll-command.js +1 -1
- package/dist/src/sdk-batch.js +2 -2
- package/dist/src/sdk-contracts.d.ts +9 -0
- package/dist/src/sdk-device.js +1 -1
- package/dist/src/sdk-selectors.d.ts +23 -726
- package/dist/src/selection.js +0 -0
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/semantic-index.js +1 -1
- package/dist/src/server.js +1 -1
- package/dist/src/session-observation.js +1 -1
- package/dist/src/session-snapshot.js +1 -1
- package/dist/src/session2.js +2 -2
- package/dist/src/simctl-facade.js +1 -1
- package/dist/src/simctl.js +1 -1
- package/dist/src/simulator-state.js +1 -1
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-runtime-binding.js +1 -1
- package/dist/src/snapshot-runtime.js +1 -1
- package/dist/src/snapshot-state.js +1 -1
- package/dist/src/snapshot4.js +1 -1
- package/dist/src/src7.js +1 -1
- package/dist/src/text-entry-focus.js +1 -1
- package/dist/src/tool-provider.js +1 -1
- package/dist/src/touch-runtime.js +1 -1
- package/dist/src/tree.js +1 -1
- package/dist/src/update-check.js +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/web2.js +1 -1
- package/package.json +3 -2
- package/server.json +2 -2
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.12.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.12.apk.sha256 +0 -1
- package/dist/src/app-inventory.d.ts +0 -4
- package/dist/src/apps-simctl.js +0 -1
- package/dist/src/cloud-artifacts.d.ts +0 -61
- package/dist/src/runner-contract.js +0 -3
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift
CHANGED
|
@@ -4,27 +4,66 @@ extension RunnerTests {
|
|
|
4
4
|
static let navigationBackKeywords = ["back", "close", "cancel"]
|
|
5
5
|
static let navigationFallbackVerificationDelay: TimeInterval = 0.25
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
enum InAppBackOutcome {
|
|
11
|
+
case performed
|
|
12
|
+
case unavailable
|
|
13
|
+
case unverified(ErrorPayload)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
enum NavigationVisualObservation: Equatable {
|
|
19
|
+
case changed
|
|
20
|
+
case unchanged
|
|
21
|
+
case unobserved
|
|
22
|
+
|
|
23
|
+
var logToken: String {
|
|
24
|
+
switch self {
|
|
25
|
+
case .changed: return "yes"
|
|
26
|
+
case .unchanged: return "no"
|
|
27
|
+
case .unobserved: return "unknown"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
struct NavigationVisualSample {
|
|
35
|
+
let data: Data?
|
|
36
|
+
let refusalCode: String?
|
|
37
|
+
let refusalHint: String?
|
|
38
|
+
|
|
39
|
+
init(data: Data?, refusalCode: String? = nil, refusalHint: String? = nil) {
|
|
40
|
+
self.data = data
|
|
41
|
+
self.refusalCode = refusalCode
|
|
42
|
+
self.refusalHint = refusalHint
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func tapInAppBackControl(app: XCUIApplication) -> InAppBackOutcome {
|
|
8
47
|
#if os(macOS)
|
|
9
48
|
if let back = macOSNavigationBackElement(app: app) {
|
|
10
49
|
tapElementCenter(app: app, element: back)
|
|
11
|
-
return
|
|
50
|
+
return .performed
|
|
12
51
|
}
|
|
13
|
-
return
|
|
52
|
+
return .unavailable
|
|
14
53
|
#elseif os(tvOS)
|
|
15
54
|
_ = pressTvRemote(.menu)
|
|
16
|
-
return
|
|
55
|
+
return .performed
|
|
17
56
|
#else
|
|
18
57
|
let buttons = app.navigationBars.buttons.allElementsBoundByIndex
|
|
19
58
|
if let back = buttons.first(where: { $0.isHittable }) {
|
|
20
59
|
back.tap()
|
|
21
|
-
return
|
|
60
|
+
return .performed
|
|
22
61
|
}
|
|
23
62
|
if isSnapshotXCTestChannelPenalized(bundleId: currentBundleId) {
|
|
24
63
|
NSLog("AGENT_DEVICE_RUNNER_IN_APP_BACK_SKIPPED_XCTEST_ENUMERATION bundle=%@", currentBundleId ?? "")
|
|
25
64
|
} else if let back = topNavigationBackElement(app: app) {
|
|
26
65
|
tapElementCenter(app: app, element: back)
|
|
27
|
-
return
|
|
66
|
+
return .performed
|
|
28
67
|
}
|
|
29
68
|
return tapTopLeadingNavigationFallback(app: app)
|
|
30
69
|
#endif
|
|
@@ -109,11 +148,11 @@ extension RunnerTests {
|
|
|
109
148
|
return CGPoint(x: frame.minX + xOffset, y: frame.minY + yOffset)
|
|
110
149
|
}
|
|
111
150
|
|
|
112
|
-
private func tapTopLeadingNavigationFallback(app: XCUIApplication) ->
|
|
151
|
+
private func tapTopLeadingNavigationFallback(app: XCUIApplication) -> InAppBackOutcome {
|
|
113
152
|
#if os(iOS)
|
|
114
153
|
let frame = onScreenWindowFrame(app: app)
|
|
115
154
|
guard let point = Self.topLeadingNavigationFallbackPoint(in: frame) else {
|
|
116
|
-
return
|
|
155
|
+
return .unavailable
|
|
117
156
|
}
|
|
118
157
|
let before = captureNavigationFallbackVisualState(app: app)
|
|
119
158
|
let context = synthesizedCoordinateContext(
|
|
@@ -124,107 +163,30 @@ extension RunnerTests {
|
|
|
124
163
|
synthesizedTapAt(app: app, x: point.x, y: point.y, context: context)
|
|
125
164
|
}
|
|
126
165
|
if case .performed = synthesized.outcome {
|
|
127
|
-
return
|
|
166
|
+
return verifyNavigationFallbackOutcome(app: app, before: before)
|
|
128
167
|
}
|
|
129
168
|
let fallback = performGesture(app) {
|
|
130
169
|
tapAt(app: app, x: point.x, y: point.y)
|
|
131
170
|
}
|
|
132
171
|
if case .performed = fallback.outcome {
|
|
133
|
-
return
|
|
172
|
+
return verifyNavigationFallbackOutcome(app: app, before: before)
|
|
134
173
|
}
|
|
135
174
|
#endif
|
|
136
|
-
return
|
|
175
|
+
return .unavailable
|
|
137
176
|
}
|
|
138
177
|
|
|
139
|
-
private func captureNavigationFallbackVisualState(app: XCUIApplication) ->
|
|
178
|
+
private func captureNavigationFallbackVisualState(app: XCUIApplication) -> NavigationVisualSample {
|
|
140
179
|
#if os(iOS)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return nil
|
|
147
|
-
}
|
|
148
|
-
return runnerPngData(for: captured.image)
|
|
180
|
+
return Self.navigationFallbackSample(
|
|
181
|
+
resolvingApp: { self.captureResolvedAppScreen(app: app) },
|
|
182
|
+
systemSurface: { self.captureResolvedAppScreen(app: self.springboard) },
|
|
183
|
+
encoding: { runnerPngData(for: $0.image) }
|
|
184
|
+
)
|
|
149
185
|
#else
|
|
150
|
-
return nil
|
|
186
|
+
return NavigationVisualSample(data: nil)
|
|
151
187
|
#endif
|
|
152
188
|
}
|
|
153
189
|
|
|
154
|
-
private func didNavigationFallbackChangeVisualState(
|
|
155
|
-
app: XCUIApplication,
|
|
156
|
-
before: Data?
|
|
157
|
-
) -> Bool {
|
|
158
|
-
sleepFor(Self.navigationFallbackVerificationDelay)
|
|
159
|
-
let after = captureNavigationFallbackVisualState(app: app)
|
|
160
|
-
let changed = Self.didNavigationFallbackChangeVisualState(before: before, after: after)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
NSLog(
|
|
164
|
-
"AGENT_DEVICE_RUNNER_IN_APP_BACK_VISUAL_VERIFICATION beforeBytes=%ld afterBytes=%ld changed=%@",
|
|
165
|
-
before?.count ?? -1,
|
|
166
|
-
after?.count ?? -1,
|
|
167
|
-
changed ? "yes" : "no"
|
|
168
|
-
)
|
|
169
|
-
return changed
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
static func didNavigationFallbackChangeVisualState(before: Data?, after: Data?) -> Bool {
|
|
173
|
-
guard let before, let after else { return false }
|
|
174
|
-
return before != after
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
private func macOSNavigationBackElement(app: XCUIApplication) -> XCUIElement? {
|
|
178
|
-
let predicate = NSPredicate(
|
|
179
|
-
format: "identifier == %@ OR label == %@",
|
|
180
|
-
"go back",
|
|
181
|
-
"Back"
|
|
182
|
-
)
|
|
183
|
-
let element = app.descendants(matching: .any).matching(predicate).firstMatch
|
|
184
|
-
return element.exists ? element : nil
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
190
|
|
|
229
191
|
|
|
230
192
|
|
|
@@ -232,23 +194,113 @@ extension RunnerTests {
|
|
|
232
194
|
|
|
233
195
|
|
|
234
196
|
|
|
197
|
+
static func navigationFallbackSample(
|
|
198
|
+
resolvingApp: () -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure>,
|
|
199
|
+
systemSurface: () -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure>,
|
|
200
|
+
encoding: (CapturedAppScreen) -> Data?
|
|
201
|
+
) -> NavigationVisualSample {
|
|
202
|
+
_ = systemSurface
|
|
203
|
+
return navigationVisualSample(from: resolvingApp(), encoding: encoding)
|
|
204
|
+
}
|
|
235
205
|
|
|
236
206
|
|
|
237
207
|
|
|
238
208
|
|
|
239
209
|
|
|
210
|
+
static func navigationVisualSample(
|
|
211
|
+
from outcome: Result<CapturedAppScreen, RunnerAppScreenCaptureFailure>,
|
|
212
|
+
encoding: (CapturedAppScreen) -> Data?
|
|
213
|
+
) -> NavigationVisualSample {
|
|
214
|
+
switch outcome {
|
|
215
|
+
case .success(let captured):
|
|
216
|
+
guard let png = encoding(captured) else {
|
|
217
|
+
let refusal = RunnerAppScreenCaptureFailure.unrenderableImage
|
|
218
|
+
return NavigationVisualSample(
|
|
219
|
+
data: nil,
|
|
220
|
+
refusalCode: refusal.rawValue,
|
|
221
|
+
refusalHint: refusal.hint
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
return NavigationVisualSample(data: png)
|
|
225
|
+
case .failure(let failure):
|
|
226
|
+
return NavigationVisualSample(
|
|
227
|
+
data: nil,
|
|
228
|
+
refusalCode: failure.rawValue,
|
|
229
|
+
refusalHint: failure.hint
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
240
233
|
|
|
234
|
+
private func verifyNavigationFallbackOutcome(
|
|
235
|
+
app: XCUIApplication,
|
|
236
|
+
before: NavigationVisualSample
|
|
237
|
+
) -> InAppBackOutcome {
|
|
238
|
+
sleepFor(Self.navigationFallbackVerificationDelay)
|
|
239
|
+
let after = captureNavigationFallbackVisualState(app: app)
|
|
240
|
+
let observation = Self.navigationVisualObservation(before: before.data, after: after.data)
|
|
241
241
|
|
|
242
242
|
|
|
243
|
+
NSLog(
|
|
244
|
+
"AGENT_DEVICE_RUNNER_IN_APP_BACK_VISUAL_VERIFICATION beforeBytes=%ld afterBytes=%ld changed=%@",
|
|
245
|
+
before.data?.count ?? -1,
|
|
246
|
+
after.data?.count ?? -1,
|
|
247
|
+
observation.logToken
|
|
248
|
+
)
|
|
249
|
+
return Self.inAppBackOutcome(observation: observation, before: before, after: after)
|
|
250
|
+
}
|
|
243
251
|
|
|
244
252
|
|
|
245
253
|
|
|
254
|
+
static func inAppBackOutcome(
|
|
255
|
+
observation: NavigationVisualObservation,
|
|
256
|
+
before: NavigationVisualSample,
|
|
257
|
+
after: NavigationVisualSample
|
|
258
|
+
) -> InAppBackOutcome {
|
|
259
|
+
switch observation {
|
|
260
|
+
case .changed:
|
|
261
|
+
return .performed
|
|
262
|
+
case .unchanged:
|
|
263
|
+
return .unavailable
|
|
264
|
+
case .unobserved:
|
|
246
265
|
|
|
247
266
|
|
|
267
|
+
return .unverified(Self.navigationFallbackErrorPayload(after: after, before: before))
|
|
268
|
+
}
|
|
269
|
+
}
|
|
248
270
|
|
|
271
|
+
static func navigationVisualObservation(
|
|
272
|
+
before: Data?,
|
|
273
|
+
after: Data?
|
|
274
|
+
) -> NavigationVisualObservation {
|
|
275
|
+
guard let before, let after else { return .unobserved }
|
|
276
|
+
return before != after ? .changed : .unchanged
|
|
277
|
+
}
|
|
249
278
|
|
|
250
279
|
|
|
251
280
|
|
|
252
281
|
|
|
282
|
+
static func navigationFallbackErrorPayload(
|
|
283
|
+
after: NavigationVisualSample,
|
|
284
|
+
before: NavigationVisualSample
|
|
285
|
+
) -> ErrorPayload {
|
|
286
|
+
ErrorPayload(
|
|
287
|
+
code:
|
|
288
|
+
after.refusalCode
|
|
289
|
+
?? before.refusalCode
|
|
290
|
+
?? RunnerAppScreenCaptureFailure.unresolvedScreen.rawValue,
|
|
291
|
+
message:
|
|
292
|
+
"The in-app back fallback was dispatched, but no display could be sampled to confirm the result. This is an unknown outcome, not evidence that a back control is absent.",
|
|
293
|
+
hint: after.refusalHint ?? before.refusalHint
|
|
294
|
+
)
|
|
295
|
+
}
|
|
253
296
|
|
|
297
|
+
private func macOSNavigationBackElement(app: XCUIApplication) -> XCUIElement? {
|
|
298
|
+
let predicate = NSPredicate(
|
|
299
|
+
format: "identifier == %@ OR label == %@",
|
|
300
|
+
"go back",
|
|
301
|
+
"Back"
|
|
302
|
+
)
|
|
303
|
+
let element = app.descendants(matching: .any).matching(predicate).firstMatch
|
|
304
|
+
return element.exists ? element : nil
|
|
305
|
+
}
|
|
254
306
|
}
|
|
@@ -89,212 +89,3 @@ extension RunnerTests {
|
|
|
89
89
|
(value as? Bool) ?? (value as? NSNumber)?.boolValue
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
@@ -25,12 +25,20 @@ extension RunnerTests {
|
|
|
25
25
|
private var startedSession = false
|
|
26
26
|
private var startError: Error?
|
|
27
27
|
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
28
31
|
init(outputPath: String, fps: Int32?) {
|
|
29
32
|
self.outputPath = outputPath
|
|
30
33
|
self.fps = fps
|
|
31
34
|
}
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
func start(
|
|
39
|
+
bootstrap: @escaping () -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure>,
|
|
40
|
+
frame: @escaping () -> RunnerImage?
|
|
41
|
+
) throws {
|
|
34
42
|
let url = URL(fileURLWithPath: outputPath)
|
|
35
43
|
let directory = url.deletingLastPathComponent()
|
|
36
44
|
try FileManager.default.createDirectory(
|
|
@@ -44,21 +52,34 @@ extension RunnerTests {
|
|
|
44
52
|
|
|
45
53
|
var dimensions: CGSize = .zero
|
|
46
54
|
var bootstrapImage: RunnerImage?
|
|
55
|
+
var lastFailure: RunnerAppScreenCaptureFailure?
|
|
47
56
|
let bootstrapDeadline = Date().addingTimeInterval(2.0)
|
|
48
57
|
while Date() < bootstrapDeadline {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
58
|
+
switch bootstrap() {
|
|
59
|
+
case .success(let captured):
|
|
60
|
+
bootstrapImage = captured.image
|
|
61
|
+
dimensions = CGSize(width: captured.pixelWidth, height: captured.pixelHeight)
|
|
62
|
+
case .failure(let failure):
|
|
63
|
+
lastFailure = failure
|
|
64
|
+
}
|
|
65
|
+
if dimensions.width > 0, dimensions.height > 0 {
|
|
52
66
|
break
|
|
53
67
|
}
|
|
54
68
|
Thread.sleep(forTimeInterval: 0.05)
|
|
55
69
|
}
|
|
56
70
|
guard dimensions.width > 0, dimensions.height > 0 else {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
#if os(iOS)
|
|
76
|
+
throw RunnerTests.recordingBootstrapError(from: lastFailure)
|
|
77
|
+
#else
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
_ = lastFailure
|
|
81
|
+
throw RunnerTests.recordingBootstrapError(from: nil)
|
|
82
|
+
#endif
|
|
62
83
|
}
|
|
63
84
|
|
|
64
85
|
let writer = try AVAssetWriter(outputURL: url, fileType: .mp4)
|
|
@@ -114,7 +135,7 @@ extension RunnerTests {
|
|
|
114
135
|
timer.setEventHandler { [weak self] in
|
|
115
136
|
guard let self else { return }
|
|
116
137
|
if self.shouldStop() { return }
|
|
117
|
-
guard let image =
|
|
138
|
+
guard let image = frame() else { return }
|
|
118
139
|
self.append(image: image)
|
|
119
140
|
}
|
|
120
141
|
self.timer = timer
|
|
@@ -212,6 +233,9 @@ extension RunnerTests {
|
|
|
212
233
|
return
|
|
213
234
|
}
|
|
214
235
|
lastTimestampValue = timestampValue
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
215
239
|
}
|
|
216
240
|
|
|
217
241
|
private func timestampCandidateValue(for nowUptime: TimeInterval) -> Int64 {
|
|
@@ -269,6 +293,58 @@ extension RunnerTests {
|
|
|
269
293
|
}
|
|
270
294
|
}
|
|
271
295
|
|
|
296
|
+
extension RunnerTests {
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
func startRecording(
|
|
303
|
+
_ recorder: ScreenRecorder,
|
|
304
|
+
capture: @escaping () -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure>
|
|
305
|
+
) throws {
|
|
306
|
+
try recorder.start(bootstrap: capture) { [weak self] in
|
|
307
|
+
guard let self else { return nil }
|
|
308
|
+
return try? self.runMainThreadWorkIfIdle(
|
|
309
|
+
"recording_frame",
|
|
310
|
+
timeout: self.recordingFrameCaptureTimeout,
|
|
311
|
+
timeoutError: self.mainThreadExecutionTimeoutError
|
|
312
|
+
) {
|
|
313
|
+
try capture().get().image
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
static func recordingBootstrapError(from lastFailure: RunnerAppScreenCaptureFailure?) -> Error {
|
|
323
|
+
lastFailure
|
|
324
|
+
?? NSError(
|
|
325
|
+
domain: "AgentDeviceRunner.Record",
|
|
326
|
+
code: 1,
|
|
327
|
+
userInfo: [NSLocalizedDescriptionKey: "failed to capture initial frame"]
|
|
328
|
+
)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
static func recordingStartErrorPayload(for error: Error) -> ErrorPayload {
|
|
335
|
+
if let failure = error as? RunnerAppScreenCaptureFailure {
|
|
336
|
+
return ErrorPayload(code: failure.rawValue, message: failure.message, hint: failure.hint)
|
|
337
|
+
}
|
|
338
|
+
return ErrorPayload(message: "failed to start recording: \(error.localizedDescription)")
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
|
|
272
348
|
|
|
273
349
|
|
|
274
350
|
|