agent-device 0.21.13 → 0.21.15
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.13.apk → agent-device-android-ime-helper-0.21.15.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.15.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.13.manifest.json → agent-device-android-ime-helper-0.21.15.manifest.json} +4 -4
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.15.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.15.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.13.manifest.json → agent-device-android-snapshot-helper-0.21.15.manifest.json} +6 -6
- package/apple/snapshot-bridge/SnapshotBridgeRuntime.m +11 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +110 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +4 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerMainOwnedState.swift +27 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedTextEntry.h +8 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedTextEntry.m +26 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +12 -19
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +59 -20
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AlertObservation.swift +2 -3
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandDispatch.swift +179 -91
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +21 -24
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+GestureExecution.swift +9 -13
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +36 -49
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+MainThreadWork.swift +11 -15
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +136 -29
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +20 -21
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +3 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +6 -5
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollDragExecution.swift +12 -24
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +22 -42
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +15 -18
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotAcquisition.swift +73 -31
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +20 -11
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCaptureTarget.swift +9 -7
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotExecution.swift +5 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTiming.swift +2 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +51 -19
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedInteraction.swift +5 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +78 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +32 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +7 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +23 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +17 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +8 -9
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TypeExecution.swift +9 -15
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +12 -11
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotCoordinateSpace.swift +16 -19
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotGeometry.swift +24 -9
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotModels.swift +66 -10
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationInvariant.swift +12 -10
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationProjection.swift +1 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFold.swift +27 -5
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFoldProjection.swift +1 -0
- package/dist/src/adapter.js +1 -1
- package/dist/src/adb-executor.js +1 -1
- package/dist/src/adb-failure.js +1 -1
- package/dist/src/adb-transport.js +1 -1
- package/dist/src/agent-browser-provider.js +1 -1
- package/dist/src/agent-browser-tool.js +1 -1
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/ai-sdk.js +1 -1
- package/dist/src/alert-runtime.js +1 -1
- package/dist/src/android-adb.d.ts +1 -8
- package/dist/src/android-input-ownership.js +1 -1
- package/dist/src/android-snapshot-quality.js +1 -0
- package/dist/src/android-system-chrome.js +1 -1
- package/dist/src/android.js +1 -1
- package/dist/src/app-catalog.js +1 -1
- package/dist/src/app-deployment-resolution.js +1 -1
- package/dist/src/app-inventory.js +1 -1
- package/dist/src/app-launch.js +1 -1
- package/dist/src/app-lifecycle.js +1 -1
- package/dist/src/app-lifecycle2.js +1 -1
- package/dist/src/app-log-files.js +1 -1
- package/dist/src/app-log-runtime2.js +1 -1
- package/dist/src/app-resolution.js +2 -2
- package/dist/src/apple-runner-platform.js +1 -1
- package/dist/src/application-lifecycle-interaction.js +1 -1
- package/dist/src/archive.js +1 -1
- package/dist/src/artifact-download.js +1 -1
- package/dist/src/auth-session.js +1 -1
- package/dist/src/auth.js +1 -1
- package/dist/src/backend-snapshot-options.js +1 -1
- package/dist/src/boot-diagnostics.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 +2 -2
- package/dist/src/cli.js +4 -4
- package/dist/src/click-button.js +1 -1
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-types.d.ts +102 -95
- package/dist/src/clipboard-shell-response.js +1 -1
- package/dist/src/command-schema.js +1 -1
- package/dist/src/command-tools.js +3 -3
- package/dist/src/connection-runtime.js +1 -1
- package/dist/src/connection.js +1 -1
- package/dist/src/contracts.d.ts +1 -1
- package/dist/src/contracts.js +1 -1
- package/dist/src/daemon-client-lifecycle.js +1 -1
- package/dist/src/daemon.js +1 -1
- package/dist/src/debug-symbols-facade.js +1 -1
- package/dist/src/device-claim-rule.js +2 -2
- package/dist/src/device-input-state.d.ts +15 -2
- package/dist/src/device-inventory-context.js +1 -1
- package/dist/src/device-rotation.js +1 -1
- package/dist/src/device-selection-resolver.js +1 -1
- package/dist/src/device-session.js +1 -1
- package/dist/src/device-shell.js +1 -1
- package/dist/src/device2.js +1 -1
- package/dist/src/devicectl.js +1 -1
- package/dist/src/diagnostics.js +1 -1
- package/dist/src/dispatch-resolve.js +1 -1
- package/dist/src/doctor2.js +1 -1
- package/dist/src/engine-eval-script.js +1 -1
- package/dist/src/error.js +1 -1
- package/dist/src/exec.js +1 -1
- package/dist/src/file.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/format.js +1 -1
- package/dist/src/gesture-plan-types.d.ts +1 -1
- package/dist/src/gesture-plan.js +1 -1
- package/dist/src/gesture-runtime.js +1 -1
- package/dist/src/harmonyos.js +1 -1
- package/dist/src/helper.js +2 -2
- package/dist/src/human-control-contract.js +1 -1
- package/dist/src/human-control.js +1 -1
- package/dist/src/index.d.ts +7 -3
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +1 -1
- package/dist/src/input-actions2.js +1 -1
- package/dist/src/install-artifact-facade.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-positionals.js +1 -1
- package/dist/src/interaction-ref-policy.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor-operation-binding.js +1 -1
- package/dist/src/interactor.js +4 -4
- package/dist/src/interactor2.js +1 -1
- package/dist/src/interactors.js +1 -1
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +2 -2
- package/dist/src/internal/png-worker.js +1 -1
- package/dist/src/internal/run-script-http-child.js +1 -1
- package/dist/src/inventory.js +1 -1
- package/dist/src/inventory2.js +1 -1
- package/dist/src/inventory3.js +1 -1
- package/dist/src/inventory5.js +1 -1
- package/dist/src/ios-snapshot-acquisition.js +1 -1
- package/dist/src/ios-snapshot-engine.js +1 -0
- package/dist/src/ios-snapshot-runtime.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/limrun-download-file.js +1 -1
- package/dist/src/limrun-runtime-dependencies.js +1 -1
- package/dist/src/limrun.d.ts +16 -3
- package/dist/src/linux.js +1 -1
- package/dist/src/location-coordinates.js +1 -1
- package/dist/src/managed-device-scope.js +1 -1
- package/dist/src/mechanics.js +17 -17
- package/dist/src/mobile-snapshot-semantics.js +1 -1
- package/dist/src/multitouch-support.js +1 -1
- package/dist/src/native-build-cache.js +1 -0
- package/dist/src/observation.js +1 -1
- package/dist/src/overlay.js +3 -0
- package/dist/src/parameterized-recorded-fill.js +1 -1
- package/dist/src/perf-facade.js +1 -1
- package/dist/src/perf-runtime-operation-builder.js +1 -1
- package/dist/src/perf-runtime-plan.js +1 -1
- package/dist/src/perf-target.js +2 -2
- package/dist/src/perf.js +1 -1
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/platform-runtime-host.js +1 -1
- package/dist/src/platform-runtime-managed-owner.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-runtime-hints.js +1 -1
- package/dist/src/platform-runtime-screen-recording-apple-simulator-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-process-host.js +1 -1
- package/dist/src/platform-runtime.js +1 -1
- package/dist/src/platform-runtime2.js +1 -1
- package/dist/src/png-crop-bytes.js +1 -1
- package/dist/src/png-size.js +1 -1
- package/dist/src/png-worker-client.js +1 -1
- package/dist/src/png.js +1 -1
- package/dist/src/prepare-kind.js +1 -1
- package/dist/src/provider-session-ownership.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/recording.js +1 -1
- package/dist/src/rect-center.js +1 -1
- package/dist/src/register-builtins.js +1 -1
- package/dist/src/registry.js +36 -36
- package/dist/src/remote-config2.js +1 -1
- package/dist/src/replay-divergence.js +1 -1
- package/dist/src/replay.js +1 -1
- package/dist/src/reporting.js +1 -1
- package/dist/src/request-admission.js +1 -1
- package/dist/src/request-cancel.js +1 -1
- package/dist/src/request-runtime-binding.js +1 -1
- package/dist/src/retry.js +1 -1
- package/dist/src/runner-cache-metadata.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 +1 -1
- package/dist/src/runner.js +1 -1
- package/dist/src/runtime-transport-hints.js +1 -1
- package/dist/src/runtime.js +1 -3
- package/dist/src/runtime10.js +2 -2
- package/dist/src/runtime2.js +4 -4
- package/dist/src/runtime3.js +1 -1
- 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-completion.js +1 -1
- package/dist/src/screen-recording-options.js +1 -1
- package/dist/src/screen-recording-resource-recovery.js +1 -1
- package/dist/src/screenshot-density.js +1 -1
- package/dist/src/screenshot-image.js +1 -1
- package/dist/src/screenshot-overlay-draw.js +1 -1
- package/dist/src/screenshot-runtime.js +1 -1
- package/dist/src/screenshot.js +1 -1
- package/dist/src/screenshot3.js +1 -1
- package/dist/src/script.js +1 -1
- package/dist/src/scroll-command.d.ts +13 -6
- package/dist/src/scroll-command.js +1 -1
- package/dist/src/scroll-gesture.js +1 -1
- package/dist/src/sdk-batch-runner.js +2 -2
- package/dist/src/sdk-batch.js +2 -2
- package/dist/src/sdk-contracts.d.ts +59 -12
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-device.js +1 -1
- package/dist/src/sdk-finders.d.ts +1 -1
- package/dist/src/sdk-io.js +1 -1
- package/dist/src/sdk-remote-config.js +1 -1
- package/dist/src/sdk-selectors.d.ts +1 -1
- package/dist/src/selection.js +0 -0
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/server.js +1 -1
- package/dist/src/session-allocation.js +1 -1
- package/dist/src/session-routing.js +1 -1
- package/dist/src/session-runtime-admission.js +1 -1
- package/dist/src/session-snapshot.js +1 -1
- package/dist/src/session-store.js +1 -1
- package/dist/src/session.js +1 -1
- package/dist/src/session2.js +4 -4
- package/dist/src/settings.js +1 -1
- package/dist/src/settings2.js +1 -0
- 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-capture-annotations.js +1 -1
- package/dist/src/snapshot-desktop-projection.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/snapshot2.js +1 -1
- package/dist/src/snapshot3.js +1 -1
- package/dist/src/snapshot4.js +1 -1
- package/dist/src/src.js +1 -1
- package/dist/src/src4.js +1 -1
- package/dist/src/src7.js +1 -1
- package/dist/src/src8.js +1 -1
- package/dist/src/string-enum.js +1 -1
- package/dist/src/surface-snapshot.js +1 -1
- package/dist/src/takeover.js +1 -1
- package/dist/src/text-entry-focus.js +1 -1
- package/dist/src/tool-provider-facade.js +1 -1
- package/dist/src/tool-provider.js +2 -2
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/touch-runtime.js +1 -1
- package/dist/src/transport.js +1 -1
- package/dist/src/tree.js +1 -1
- package/dist/src/tv-remote.js +1 -1
- package/dist/src/type-text-runtime.js +1 -1
- package/dist/src/verified-file.js +1 -1
- package/dist/src/video.js +1 -1
- package/dist/src/viewport.js +1 -1
- package/dist/src/web.js +1 -1
- package/dist/src/web2.js +1 -1
- package/dist/src/webdriver-source.js +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.13.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/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 +0 -1
- package/dist/src/absence-observation-errors.js +0 -1
- package/dist/src/runner-presentation.js +0 -1
- package/dist/src/semantic-index.js +0 -1
- package/dist/src/snapshot-process.js +0 -1
- package/dist/src/snapshot-scope.js +0 -1
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift
CHANGED
|
@@ -180,6 +180,7 @@ extension RunnerTests {
|
|
|
180
180
|
|
|
181
181
|
|
|
182
182
|
|
|
183
|
+
@MainActor
|
|
183
184
|
func ensureRunnerHostAppActive(reason: String) {
|
|
184
185
|
NSLog(
|
|
185
186
|
"AGENT_DEVICE_RUNNER_HOST_ACTIVATE state=%d reason=%@",
|
|
@@ -191,9 +192,9 @@ extension RunnerTests {
|
|
|
191
192
|
} else if app.state != .runningForeground {
|
|
192
193
|
app.activate()
|
|
193
194
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
195
|
+
mainOwned.app = app
|
|
196
|
+
mainOwned.bundleId = nil
|
|
197
|
+
mainOwned.processIdentifier = nil
|
|
197
198
|
resetTargetBoundState()
|
|
198
199
|
}
|
|
199
200
|
|
|
@@ -207,16 +208,18 @@ extension RunnerTests {
|
|
|
207
208
|
lastLoggedGesturePolicyLines.removeAll()
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
@MainActor
|
|
210
212
|
func invalidateCachedTarget(reason: String) {
|
|
211
|
-
if
|
|
213
|
+
if mainOwned.app != nil || mainOwned.bundleId != nil {
|
|
212
214
|
NSLog("AGENT_DEVICE_RUNNER_TARGET_CACHE_INVALIDATE reason=%@", reason)
|
|
213
215
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
216
|
+
mainOwned.app = nil
|
|
217
|
+
mainOwned.bundleId = nil
|
|
218
|
+
mainOwned.processIdentifier = nil
|
|
217
219
|
resetTargetBoundState()
|
|
218
220
|
}
|
|
219
221
|
|
|
222
|
+
@MainActor
|
|
220
223
|
func resetTargetAfterExternalRelaunch() -> Response {
|
|
221
224
|
invalidateCachedTarget(reason: "external_app_relaunch")
|
|
222
225
|
|
|
@@ -228,22 +231,23 @@ extension RunnerTests {
|
|
|
228
231
|
return Response(ok: true, data: DataPayload(message: "target reset"))
|
|
229
232
|
}
|
|
230
233
|
|
|
234
|
+
@MainActor
|
|
231
235
|
func refreshCachedTargetIfProcessChanged(bundleId: String) {
|
|
232
|
-
guard
|
|
236
|
+
guard mainOwned.bundleId == bundleId, mainOwned.app != nil else { return }
|
|
233
237
|
let candidate = XCUIApplication(bundleIdentifier: bundleId)
|
|
234
238
|
let observedProcessIdentifier = Self.processIdentifier(of: candidate)
|
|
235
239
|
guard Self.shouldRefreshCachedTarget(
|
|
236
|
-
cachedProcessIdentifier:
|
|
240
|
+
cachedProcessIdentifier: mainOwned.processIdentifier,
|
|
237
241
|
observedProcessIdentifier: observedProcessIdentifier
|
|
238
242
|
) else { return }
|
|
239
243
|
NSLog(
|
|
240
244
|
"AGENT_DEVICE_RUNNER_TARGET_CACHE_REFRESH bundle=%@ previousPid=%d currentPid=%d",
|
|
241
245
|
bundleId,
|
|
242
|
-
|
|
246
|
+
mainOwned.processIdentifier ?? 0,
|
|
243
247
|
observedProcessIdentifier ?? 0
|
|
244
248
|
)
|
|
245
|
-
|
|
246
|
-
|
|
249
|
+
mainOwned.app = candidate
|
|
250
|
+
mainOwned.processIdentifier = observedProcessIdentifier
|
|
247
251
|
resetTargetBoundState()
|
|
248
252
|
clearSnapshotXCTestChannelPenalty(reason: "target_process_changed")
|
|
249
253
|
clearPrivateAXAcceptedDepth(reason: "target_process_changed")
|
|
@@ -280,11 +284,12 @@ extension RunnerTests {
|
|
|
280
284
|
return false
|
|
281
285
|
}
|
|
282
286
|
|
|
287
|
+
@MainActor
|
|
283
288
|
func canUseFastForegroundAppGuard(
|
|
284
289
|
activeApp: XCUIApplication,
|
|
285
290
|
requestedBundleId: String?
|
|
286
291
|
) -> Bool {
|
|
287
|
-
guard let requestedBundleId,
|
|
292
|
+
guard let requestedBundleId, mainOwned.bundleId == requestedBundleId, mainOwned.app != nil else {
|
|
288
293
|
return false
|
|
289
294
|
}
|
|
290
295
|
guard activeApp.state == .runningForeground else { return false }
|
|
@@ -292,6 +297,7 @@ extension RunnerTests {
|
|
|
292
297
|
return true
|
|
293
298
|
}
|
|
294
299
|
|
|
300
|
+
@MainActor
|
|
295
301
|
func writeFastAppGuardMarker(bundleId: String, state: XCUIApplication.State) {
|
|
296
302
|
|
|
297
303
|
|
|
@@ -318,9 +324,10 @@ extension RunnerTests {
|
|
|
318
324
|
|
|
319
325
|
|
|
320
326
|
|
|
321
|
-
|
|
327
|
+
|
|
328
|
+
func notRunningRefusal(command: Command, bundleId: String) -> Response? {
|
|
322
329
|
#if os(iOS)
|
|
323
|
-
guard
|
|
330
|
+
guard command.traits.launchPolicy == .existingApp,
|
|
324
331
|
XCUIApplication(bundleIdentifier: bundleId).state == .notRunning
|
|
325
332
|
else { return nil }
|
|
326
333
|
NSLog(
|
|
@@ -341,6 +348,7 @@ extension RunnerTests {
|
|
|
341
348
|
#endif
|
|
342
349
|
}
|
|
343
350
|
|
|
351
|
+
@MainActor
|
|
344
352
|
func activateTarget(bundleId: String, reason: String) -> XCUIApplication {
|
|
345
353
|
let target = XCUIApplication(bundleIdentifier: bundleId)
|
|
346
354
|
let initialState = target.state
|
|
@@ -374,9 +382,9 @@ extension RunnerTests {
|
|
|
374
382
|
otherActiveApplicationPid.map(String.init) ?? "-"
|
|
375
383
|
)
|
|
376
384
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
385
|
+
mainOwned.app = target
|
|
386
|
+
mainOwned.bundleId = bundleId
|
|
387
|
+
mainOwned.processIdentifier = Self.processIdentifier(of: target)
|
|
380
388
|
resetTargetBoundState()
|
|
381
389
|
beginFirstInteractionStabilization()
|
|
382
390
|
return target
|
|
@@ -387,10 +395,11 @@ extension RunnerTests {
|
|
|
387
395
|
|
|
388
396
|
|
|
389
397
|
|
|
398
|
+
@MainActor
|
|
390
399
|
func withBoundedInteractionIdleTimeoutIfSupported(
|
|
391
400
|
_ target: XCUIApplication,
|
|
392
401
|
waits: RunnerInteractionIdleWaits,
|
|
393
|
-
operation: () -> Void
|
|
402
|
+
operation: @MainActor () -> Void
|
|
394
403
|
) {
|
|
395
404
|
let setter = NSSelectorFromString("setWaitForIdleTimeout:")
|
|
396
405
|
let supportsWaitForIdleTimeout = target.responds(to: setter)
|
|
@@ -409,10 +418,11 @@ extension RunnerTests {
|
|
|
409
418
|
}
|
|
410
419
|
|
|
411
420
|
|
|
421
|
+
@MainActor
|
|
412
422
|
private func performWithQuiescenceSkippedIfSupported(
|
|
413
423
|
_ target: XCUIApplication,
|
|
414
424
|
waits: RunnerInteractionIdleWaits,
|
|
415
|
-
operation: () -> Void
|
|
425
|
+
operation: @MainActor () -> Void
|
|
416
426
|
) {
|
|
417
427
|
let selector = NSSelectorFromString("_performWithInteractionOptions:block:")
|
|
418
428
|
guard target.responds(to: selector) else {
|
|
@@ -440,7 +450,7 @@ extension RunnerTests {
|
|
|
440
450
|
options = skipPreEventQuiescence
|
|
441
451
|
}
|
|
442
452
|
withoutActuallyEscaping(operation) { escapableOperation in
|
|
443
|
-
let block: @convention(block) () -> Void = escapableOperation
|
|
453
|
+
let block: @convention(block) () -> Void = { _ = runOnMainActor(escapableOperation) }
|
|
444
454
|
performWithOptions(
|
|
445
455
|
target,
|
|
446
456
|
selector,
|
|
@@ -450,49 +460,26 @@ extension RunnerTests {
|
|
|
450
460
|
}
|
|
451
461
|
}
|
|
452
462
|
|
|
453
|
-
|
|
454
|
-
isReadOnlyCommand(command)
|
|
455
|
-
}
|
|
463
|
+
|
|
456
464
|
|
|
457
465
|
func shouldRetryException(_ command: Command, message: String) -> Bool {
|
|
458
|
-
guard
|
|
466
|
+
guard command.traits.retryOnSessionLoss else { return false }
|
|
459
467
|
|
|
460
468
|
return message.lowercased().contains("kaxerrorservernotfound")
|
|
461
469
|
}
|
|
462
470
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
func isReadOnlyCommand(_ command: Command) -> Bool {
|
|
466
|
-
switch command.command.traits.readOnly {
|
|
467
|
-
case .always:
|
|
468
|
-
return true
|
|
469
|
-
case .never:
|
|
470
|
-
return false
|
|
471
|
-
case .conditional:
|
|
472
|
-
|
|
473
|
-
return (command.action ?? "get").lowercased() == "get"
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
471
|
func shouldRetryResponse(_ response: Response) -> Bool {
|
|
478
472
|
guard response.ok == false else { return false }
|
|
479
473
|
return response.error?.retryableFailure != nil
|
|
480
474
|
}
|
|
481
475
|
|
|
482
|
-
func isInteractionCommand(_ command: CommandType) -> Bool {
|
|
483
|
-
return command.traits.isInteraction
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
func isRunnerLifecycleCommand(_ command: CommandType) -> Bool {
|
|
487
|
-
return command.traits.isLifecycle
|
|
488
|
-
}
|
|
489
|
-
|
|
490
476
|
|
|
491
477
|
|
|
478
|
+
@MainActor
|
|
492
479
|
func applyInteractionStabilizationIfNeeded() {
|
|
493
|
-
if needsPostSnapshotInteractionDelay {
|
|
480
|
+
if mainOwned.needsPostSnapshotInteractionDelay {
|
|
494
481
|
sleepFor(postSnapshotInteractionDelay)
|
|
495
|
-
needsPostSnapshotInteractionDelay = false
|
|
482
|
+
mainOwned.needsPostSnapshotInteractionDelay = false
|
|
496
483
|
}
|
|
497
484
|
if let readyUptime = firstInteractionReadyUptime {
|
|
498
485
|
sleepFor(readyUptime - ProcessInfo.processInfo.systemUptime)
|
|
@@ -57,12 +57,12 @@ extension RunnerTests {
|
|
|
57
57
|
func runMainThreadWork<T>(
|
|
58
58
|
_ operation: String,
|
|
59
59
|
timeout: TimeInterval,
|
|
60
|
-
timeoutError: @escaping () -> Error,
|
|
61
|
-
onAbandoned: (() -> Void)? = nil,
|
|
62
|
-
_ work: @escaping () throws -> T
|
|
60
|
+
timeoutError: @escaping @Sendable () -> Error,
|
|
61
|
+
onAbandoned: (@Sendable () -> Void)? = nil,
|
|
62
|
+
_ work: @escaping @MainActor () throws -> T
|
|
63
63
|
) throws -> T {
|
|
64
64
|
if Thread.isMainThread {
|
|
65
|
-
return try work()
|
|
65
|
+
return try runOnMainActor(work).get()
|
|
66
66
|
}
|
|
67
67
|
mainThreadWorkLock.lock()
|
|
68
68
|
let state = enqueueMainThreadWorkLocked(operation, work)
|
|
@@ -85,8 +85,8 @@ extension RunnerTests {
|
|
|
85
85
|
func runMainThreadWorkIfIdle<T>(
|
|
86
86
|
_ operation: String,
|
|
87
87
|
timeout: TimeInterval,
|
|
88
|
-
timeoutError: @escaping () -> Error,
|
|
89
|
-
_ work: @escaping () throws -> T
|
|
88
|
+
timeoutError: @escaping @Sendable () -> Error,
|
|
89
|
+
_ work: @escaping @MainActor () throws -> T
|
|
90
90
|
) throws -> T? {
|
|
91
91
|
if Thread.isMainThread {
|
|
92
92
|
return nil
|
|
@@ -109,16 +109,12 @@ extension RunnerTests {
|
|
|
109
109
|
|
|
110
110
|
private func enqueueMainThreadWorkLocked<T>(
|
|
111
111
|
_ operation: String,
|
|
112
|
-
_ work: @escaping () throws -> T
|
|
112
|
+
_ work: @escaping @MainActor () throws -> T
|
|
113
113
|
) -> MainThreadWorkState<T> {
|
|
114
114
|
let state = MainThreadWorkState<T>()
|
|
115
115
|
mainThreadWorkInFlightCount += 1
|
|
116
116
|
DispatchQueue.main.async {
|
|
117
|
-
|
|
118
|
-
state.result = .success(try work())
|
|
119
|
-
} catch {
|
|
120
|
-
state.result = .failure(error)
|
|
121
|
-
}
|
|
117
|
+
state.result = runOnMainActor(work)
|
|
122
118
|
self.mainThreadWorkLock.lock()
|
|
123
119
|
self.mainThreadWorkInFlightCount -= 1
|
|
124
120
|
let abandoned = state.abandoned
|
|
@@ -147,8 +143,8 @@ extension RunnerTests {
|
|
|
147
143
|
_ state: MainThreadWorkState<T>,
|
|
148
144
|
operation: String,
|
|
149
145
|
timeout: TimeInterval,
|
|
150
|
-
timeoutError: @escaping () -> Error,
|
|
151
|
-
onAbandoned: (() -> Void)?
|
|
146
|
+
timeoutError: @escaping @Sendable () -> Error,
|
|
147
|
+
onAbandoned: (@Sendable () -> Void)?
|
|
152
148
|
) throws -> T {
|
|
153
149
|
let waitResult = state.completed.wait(timeout: .now() + timeout)
|
|
154
150
|
if waitResult == .timedOut {
|
|
@@ -191,7 +187,7 @@ extension RunnerTests {
|
|
|
191
187
|
}
|
|
192
188
|
}
|
|
193
189
|
|
|
194
|
-
func mainThreadExecutionTimeoutError() -> Error {
|
|
190
|
+
static func mainThreadExecutionTimeoutError() -> Error {
|
|
195
191
|
NSError(
|
|
196
192
|
domain: RunnerErrorDomain.general,
|
|
197
193
|
code: RunnerErrorCode.mainThreadExecutionTimedOut,
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift
CHANGED
|
@@ -2,7 +2,7 @@ import AgentDeviceSnapshotPresentation
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
enum CommandType: String, Codable {
|
|
5
|
+
enum CommandType: String, Codable, CaseIterable {
|
|
6
6
|
case tap
|
|
7
7
|
case mouseClick
|
|
8
8
|
case longPress
|
|
@@ -33,6 +33,7 @@ enum CommandType: String, Codable {
|
|
|
33
33
|
case recordStop
|
|
34
34
|
case status
|
|
35
35
|
case uptime
|
|
36
|
+
case appState
|
|
36
37
|
case activate
|
|
37
38
|
case terminate
|
|
38
39
|
case targetReset
|
|
@@ -42,6 +43,46 @@ enum CommandType: String, Codable {
|
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
|
|
46
|
+
enum CommandLaunchPolicy: Equatable {
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
case noApp
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
case presentedSurface
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
case existingApp
|
|
69
|
+
|
|
70
|
+
case mayLaunch
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
45
86
|
|
|
46
87
|
|
|
47
88
|
|
|
@@ -50,72 +91,94 @@ struct CommandTraits {
|
|
|
50
91
|
|
|
51
92
|
let isInteraction: Bool
|
|
52
93
|
|
|
94
|
+
let retryOnSessionLoss: Bool
|
|
53
95
|
|
|
54
|
-
let readOnly: ReadOnly
|
|
55
96
|
|
|
56
|
-
let
|
|
97
|
+
let launchPolicy: CommandLaunchPolicy
|
|
57
98
|
|
|
58
|
-
enum ReadOnly {
|
|
59
|
-
case always
|
|
60
|
-
case never
|
|
61
99
|
|
|
62
100
|
|
|
63
101
|
|
|
64
|
-
|
|
102
|
+
let convertsRecordedFailure: Bool
|
|
103
|
+
|
|
104
|
+
init(
|
|
105
|
+
isInteraction: Bool = false,
|
|
106
|
+
retryOnSessionLoss: Bool = false,
|
|
107
|
+
launchPolicy: CommandLaunchPolicy,
|
|
108
|
+
convertsRecordedFailure: Bool = false
|
|
109
|
+
) {
|
|
110
|
+
self.isInteraction = isInteraction
|
|
111
|
+
self.retryOnSessionLoss = retryOnSessionLoss
|
|
112
|
+
self.launchPolicy = launchPolicy
|
|
113
|
+
self.convertsRecordedFailure = convertsRecordedFailure
|
|
65
114
|
}
|
|
66
115
|
}
|
|
67
116
|
|
|
68
|
-
extension
|
|
117
|
+
fileprivate extension CommandTraits {
|
|
69
118
|
|
|
70
119
|
|
|
120
|
+
static let interaction = CommandTraits(
|
|
121
|
+
isInteraction: true,
|
|
122
|
+
launchPolicy: .mayLaunch,
|
|
123
|
+
convertsRecordedFailure: true
|
|
124
|
+
)
|
|
71
125
|
|
|
72
|
-
var traits: CommandTraits {
|
|
73
|
-
switch self {
|
|
74
126
|
|
|
75
127
|
|
|
76
128
|
|
|
77
129
|
|
|
130
|
+
static let appMutation = CommandTraits(launchPolicy: .mayLaunch, convertsRecordedFailure: true)
|
|
78
131
|
|
|
79
|
-
case .tap, .longPress, .drag, .remotePress, .type, .swipe, .scroll, .desktopScroll,
|
|
80
|
-
.backInApp, .backSystem, .rotate, .appSwitcher,
|
|
81
|
-
.keyboardDismiss, .keyboardReturn, .sequence, .gesture:
|
|
82
|
-
return CommandTraits(isInteraction: true, readOnly: .never, isLifecycle: false)
|
|
83
132
|
|
|
84
133
|
|
|
85
|
-
|
|
86
|
-
return CommandTraits(isInteraction: false, readOnly: .always, isLifecycle: false)
|
|
134
|
+
static let appRead = CommandTraits(retryOnSessionLoss: true, launchPolicy: .existingApp)
|
|
87
135
|
|
|
88
136
|
|
|
89
|
-
case .screenshot:
|
|
90
|
-
return CommandTraits(isInteraction: false, readOnly: .always, isLifecycle: true)
|
|
91
137
|
|
|
92
138
|
|
|
93
|
-
case .alert:
|
|
94
|
-
return CommandTraits(isInteraction: false, readOnly: .conditional, isLifecycle: false)
|
|
95
139
|
|
|
140
|
+
static let selectorResolution = CommandTraits(
|
|
141
|
+
launchPolicy: .existingApp,
|
|
142
|
+
convertsRecordedFailure: true
|
|
143
|
+
)
|
|
96
144
|
|
|
97
|
-
case .recordStop, .uptime, .terminate, .targetReset, .shutdown:
|
|
98
|
-
return CommandTraits(isInteraction: false, readOnly: .never, isLifecycle: true)
|
|
99
145
|
|
|
100
146
|
|
|
147
|
+
static let runnerCaptureRead = CommandTraits(retryOnSessionLoss: true, launchPolicy: .noApp)
|
|
101
148
|
|
|
102
149
|
|
|
150
|
+
static let runnerLifecycle = CommandTraits(launchPolicy: .noApp)
|
|
103
151
|
|
|
104
152
|
|
|
105
|
-
case .actionButton:
|
|
106
|
-
return CommandTraits(isInteraction: false, readOnly: .never, isLifecycle: false)
|
|
107
153
|
|
|
108
|
-
case .status:
|
|
109
|
-
return CommandTraits(isInteraction: false, readOnly: .always, isLifecycle: true)
|
|
110
154
|
|
|
155
|
+
static let presentedSurfaceMutation = CommandTraits(
|
|
156
|
+
launchPolicy: .presentedSurface,
|
|
157
|
+
convertsRecordedFailure: true
|
|
158
|
+
)
|
|
111
159
|
|
|
112
160
|
|
|
161
|
+
static let presentedSurfaceQuery = CommandTraits(
|
|
162
|
+
retryOnSessionLoss: true,
|
|
163
|
+
launchPolicy: .presentedSurface
|
|
164
|
+
)
|
|
165
|
+
}
|
|
113
166
|
|
|
167
|
+
extension CommandTraits {
|
|
114
168
|
|
|
115
169
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
170
|
+
|
|
171
|
+
static let textEntryWitnessOwners: Set<CommandType> = [.tap, .type]
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
extension Command {
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
var invalidatesRememberedTextEntryTap: Bool {
|
|
181
|
+
traits.convertsRecordedFailure && !CommandTraits.textEntryWitnessOwners.contains(command)
|
|
119
182
|
}
|
|
120
183
|
}
|
|
121
184
|
|
|
@@ -159,6 +222,49 @@ struct Command: Codable {
|
|
|
159
222
|
let steps: [SequenceStep]?
|
|
160
223
|
}
|
|
161
224
|
|
|
225
|
+
extension Command {
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
var traits: CommandTraits {
|
|
230
|
+
switch command {
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
case .tap, .type, .longPress, .drag, .remotePress, .swipe, .scroll, .desktopScroll,
|
|
236
|
+
.backInApp, .backSystem, .rotate, .appSwitcher,
|
|
237
|
+
.keyboardDismiss, .keyboardReturn, .sequence, .gesture:
|
|
238
|
+
return .interaction
|
|
239
|
+
|
|
240
|
+
case .findText, .readText, .snapshot, .gestureViewport:
|
|
241
|
+
return .appRead
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
case .screenshot, .status, .appState:
|
|
246
|
+
return .runnerCaptureRead
|
|
247
|
+
|
|
248
|
+
case .alert:
|
|
249
|
+
return (action ?? "get").lowercased() == "get"
|
|
250
|
+
? .presentedSurfaceQuery
|
|
251
|
+
: .presentedSurfaceMutation
|
|
252
|
+
|
|
253
|
+
case .recordStop, .uptime, .terminate, .targetReset, .shutdown:
|
|
254
|
+
return .runnerLifecycle
|
|
255
|
+
|
|
256
|
+
case .actionButton:
|
|
257
|
+
return .presentedSurfaceMutation
|
|
258
|
+
|
|
259
|
+
case .querySelector:
|
|
260
|
+
return .selectorResolution
|
|
261
|
+
|
|
262
|
+
case .mouseClick, .home, .recordStart, .activate:
|
|
263
|
+
return .appMutation
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
162
268
|
enum ScrollReleaseBehavior: String, Codable {
|
|
163
269
|
case controlled
|
|
164
270
|
case inertial
|
|
@@ -306,6 +412,7 @@ struct DataPayload: Codable {
|
|
|
306
412
|
var referenceWidth: Double?
|
|
307
413
|
var referenceHeight: Double?
|
|
308
414
|
var currentUptimeMs: Double?
|
|
415
|
+
var applicationState: String?
|
|
309
416
|
var commandId: String?
|
|
310
417
|
var lifecycleState: String?
|
|
311
418
|
var lifecycleCommand: String?
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import AgentDeviceSnapshotPresentation
|
|
1
2
|
import XCTest
|
|
2
3
|
|
|
3
4
|
extension RunnerTests {
|
|
@@ -43,6 +44,7 @@ extension RunnerTests {
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
@MainActor
|
|
46
48
|
func tapInAppBackControl(app: XCUIApplication) -> InAppBackOutcome {
|
|
47
49
|
#if os(macOS)
|
|
48
50
|
if let back = macOSNavigationBackElement(app: app) {
|
|
@@ -59,8 +61,8 @@ extension RunnerTests {
|
|
|
59
61
|
back.tap()
|
|
60
62
|
return .performed
|
|
61
63
|
}
|
|
62
|
-
if isSnapshotXCTestChannelPenalized(bundleId:
|
|
63
|
-
NSLog("AGENT_DEVICE_RUNNER_IN_APP_BACK_SKIPPED_XCTEST_ENUMERATION bundle=%@",
|
|
64
|
+
if isSnapshotXCTestChannelPenalized(bundleId: mainOwned.bundleId) {
|
|
65
|
+
NSLog("AGENT_DEVICE_RUNNER_IN_APP_BACK_SKIPPED_XCTEST_ENUMERATION bundle=%@", mainOwned.bundleId ?? "")
|
|
64
66
|
} else if let back = topNavigationBackElement(app: app) {
|
|
65
67
|
tapElementCenter(app: app, element: back)
|
|
66
68
|
return .performed
|
|
@@ -120,16 +122,9 @@ extension RunnerTests {
|
|
|
120
122
|
return navigationBackKeywords.firstIndex { text.contains($0) }
|
|
121
123
|
}
|
|
122
124
|
|
|
123
|
-
|
|
124
|
-
static func isUsableNavigationFrame(_ frame: CGRect) -> Bool {
|
|
125
|
-
guard frame.width.isFinite, frame.height.isFinite, frame.width > 0, frame.height > 0 else {
|
|
126
|
-
return false
|
|
127
|
-
}
|
|
128
|
-
return !frame.isInfinite
|
|
129
|
-
}
|
|
130
|
-
|
|
131
125
|
static func isTopNavigationControlFrame(_ candidate: CGRect, in window: CGRect) -> Bool {
|
|
132
|
-
guard
|
|
126
|
+
guard SnapshotGeometry.isPositiveFinite(candidate), SnapshotGeometry.isPositiveFinite(window)
|
|
127
|
+
else {
|
|
133
128
|
return false
|
|
134
129
|
}
|
|
135
130
|
|
|
@@ -138,7 +133,7 @@ extension RunnerTests {
|
|
|
138
133
|
}
|
|
139
134
|
|
|
140
135
|
static func topLeadingNavigationFallbackPoint(in frame: CGRect) -> CGPoint? {
|
|
141
|
-
guard
|
|
136
|
+
guard SnapshotGeometry.isPositiveFinite(frame) else {
|
|
142
137
|
return nil
|
|
143
138
|
}
|
|
144
139
|
|
|
@@ -148,6 +143,7 @@ extension RunnerTests {
|
|
|
148
143
|
return CGPoint(x: frame.minX + xOffset, y: frame.minY + yOffset)
|
|
149
144
|
}
|
|
150
145
|
|
|
146
|
+
@MainActor
|
|
151
147
|
private func tapTopLeadingNavigationFallback(app: XCUIApplication) -> InAppBackOutcome {
|
|
152
148
|
#if os(iOS)
|
|
153
149
|
let frame = onScreenWindowFrame(app: app)
|
|
@@ -159,17 +155,20 @@ extension RunnerTests {
|
|
|
159
155
|
app: app,
|
|
160
156
|
policy: synthesizedGesturePolicy(.coordinateTap)
|
|
161
157
|
)?.withReferenceFrame(frame)
|
|
162
|
-
|
|
158
|
+
switch performSynthesizedGesture(app, kind: .coordinateTap, context: context, synthesize: {
|
|
163
159
|
synthesizedTapAt(app: app, x: point.x, y: point.y, context: context)
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return verifyNavigationFallbackOutcome(app: app, before: before)
|
|
167
|
-
}
|
|
168
|
-
let fallback = performGesture(app) {
|
|
169
|
-
tapAt(app: app, x: point.x, y: point.y)
|
|
170
|
-
}
|
|
171
|
-
if case .performed = fallback.outcome {
|
|
160
|
+
}) {
|
|
161
|
+
case .performed:
|
|
172
162
|
return verifyNavigationFallbackOutcome(app: app, before: before)
|
|
163
|
+
case .refused:
|
|
164
|
+
return .unavailable
|
|
165
|
+
case .xctestFallback:
|
|
166
|
+
let fallback = performGesture(app) {
|
|
167
|
+
tapAt(app: app, x: point.x, y: point.y)
|
|
168
|
+
}
|
|
169
|
+
if case .performed = fallback.outcome {
|
|
170
|
+
return verifyNavigationFallbackOutcome(app: app, before: before)
|
|
171
|
+
}
|
|
173
172
|
}
|
|
174
173
|
#endif
|
|
175
174
|
return .unavailable
|
|
@@ -8,6 +8,7 @@ struct PrivateAXFields {
|
|
|
8
8
|
let label: String
|
|
9
9
|
let identifier: String
|
|
10
10
|
let value: String
|
|
11
|
+
let placeholder: String
|
|
11
12
|
let rawType: Int
|
|
12
13
|
let elementType: XCUIElement.ElementType?
|
|
13
14
|
let enabled: Bool
|
|
@@ -52,6 +53,7 @@ extension RunnerTests {
|
|
|
52
53
|
label: privateAXPresentationString(raw["label"]),
|
|
53
54
|
identifier: privateAXPresentationString(raw["identifier"]),
|
|
54
55
|
value: privateAXPresentationString(raw["value"]),
|
|
56
|
+
placeholder: privateAXPresentationString(raw["placeholder"]),
|
|
55
57
|
rawType: rawType,
|
|
56
58
|
elementType: privateAXElementType(rawElementType: rawType),
|
|
57
59
|
enabled: privateAXPresentationBool(raw["enabled"]) ?? true,
|
|
@@ -70,6 +72,7 @@ extension RunnerTests {
|
|
|
70
72
|
label: fields.label.isEmpty ? nil : fields.label,
|
|
71
73
|
identifier: fields.identifier.isEmpty ? nil : fields.identifier,
|
|
72
74
|
value: fields.value.isEmpty ? nil : fields.value,
|
|
75
|
+
placeholder: fields.placeholder.isEmpty ? nil : fields.placeholder,
|
|
73
76
|
rect: SnapshotRect(fields.rect), enabled: fields.enabled,
|
|
74
77
|
focused: fields.focused, selected: fields.selected,
|
|
75
78
|
hittable: false,
|
|
@@ -36,8 +36,8 @@ extension RunnerTests {
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
func start(
|
|
39
|
-
bootstrap:
|
|
40
|
-
frame: @escaping () -> RunnerImage?
|
|
39
|
+
bootstrap: () -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure>,
|
|
40
|
+
frame: @escaping @Sendable () -> RunnerImage?
|
|
41
41
|
) throws {
|
|
42
42
|
let url = URL(fileURLWithPath: outputPath)
|
|
43
43
|
let directory = url.deletingLastPathComponent()
|
|
@@ -132,7 +132,7 @@ extension RunnerTests {
|
|
|
132
132
|
|
|
133
133
|
let timer = DispatchSource.makeTimerSource(queue: queue)
|
|
134
134
|
timer.schedule(deadline: .now() + frameInterval, repeating: frameInterval)
|
|
135
|
-
timer.setEventHandler { [weak self] in
|
|
135
|
+
timer.setEventHandler { @Sendable [weak self] in
|
|
136
136
|
guard let self else { return }
|
|
137
137
|
if self.shouldStop() { return }
|
|
138
138
|
guard let image = frame() else { return }
|
|
@@ -299,16 +299,17 @@ extension RunnerTests {
|
|
|
299
299
|
|
|
300
300
|
|
|
301
301
|
|
|
302
|
+
@MainActor
|
|
302
303
|
func startRecording(
|
|
303
304
|
_ recorder: ScreenRecorder,
|
|
304
|
-
capture: @escaping () -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure>
|
|
305
|
+
capture: @escaping @MainActor () -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure>
|
|
305
306
|
) throws {
|
|
306
307
|
try recorder.start(bootstrap: capture) { [weak self] in
|
|
307
308
|
guard let self else { return nil }
|
|
308
309
|
return try? self.runMainThreadWorkIfIdle(
|
|
309
310
|
"recording_frame",
|
|
310
311
|
timeout: self.recordingFrameCaptureTimeout,
|
|
311
|
-
timeoutError:
|
|
312
|
+
timeoutError: Self.mainThreadExecutionTimeoutError
|
|
312
313
|
) {
|
|
313
314
|
try capture().get().image
|
|
314
315
|
}
|