agent-device 0.21.19 → 0.21.21
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.19.apk → agent-device-android-ime-helper-0.21.21.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.21.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.19.manifest.json → agent-device-android-ime-helper-0.21.21.manifest.json} +4 -4
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.21.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.21.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.19.manifest.json → agent-device-android-snapshot-helper-0.21.21.manifest.json} +6 -6
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/AppWindowScreenshot.swift +73 -0
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/BackgroundInteraction.swift +557 -0
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/GhostCursor.swift +141 -0
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/SnapshotTraversal.swift +107 -3
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/main.swift +136 -22
- package/apple/macos-helper/Tests/AgentDeviceMacOSHelperTests/BackgroundInteractionTests.swift +88 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +133 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +10 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +36 -9
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +28 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -14
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +14 -16
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +67 -14
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedCommitDeadline.swift +6 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +7 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedInteraction.swift +21 -7
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +121 -17
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +179 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryConfirmation.swift +119 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +8 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryReadiness.swift +23 -11
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputProbe.swift +59 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +112 -23
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TypeExecution.swift +25 -12
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/RecordingExportSupport.swift +6 -1
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +43 -13
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotModels.swift +20 -5
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationProjection.swift +2 -15
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFold.swift +10 -25
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFoldProjection.swift +1 -18
- package/dist/src/adapter.js +1 -1
- package/dist/src/adb-executor.js +2 -2
- package/dist/src/adb-failure.js +1 -1
- package/dist/src/adb-transport.js +1 -1
- package/dist/src/agent-browser-lifecycle.js +1 -1
- package/dist/src/agent-browser-process-record.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/alert.js +1 -0
- package/dist/src/android-adb.d.ts +12 -0
- package/dist/src/android-input-ownership.js +1 -1
- package/dist/src/app-backend.js +1 -0
- 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 +2 -2
- package/dist/src/app-lifecycle.js +2 -2
- package/dist/src/app-lifecycle2.js +1 -1
- package/dist/src/app-log-files.js +1 -1
- package/dist/src/app-log-reconnect.js +1 -1
- package/dist/src/app-log-runtime2.js +3 -3
- package/dist/src/app-log-session-resource.js +1 -0
- 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 +2 -2
- 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/back-mode.js +1 -1
- package/dist/src/backend-snapshot-options.js +1 -1
- package/dist/src/boot-diagnostics.js +1 -1
- package/dist/src/browser-launch.js +1 -1
- package/dist/src/cache.js +1 -1
- package/dist/src/capabilities.js +1 -1
- package/dist/src/capture.js +1 -1
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +317 -323
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +4 -4
- package/dist/src/click-button.js +1 -1
- package/dist/src/client-metro-companion.js +1 -1
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-options.js +3 -0
- package/dist/src/client-types.d.ts +101 -6
- package/dist/src/clipboard-shell-response.js +1 -1
- package/dist/src/{scroll-command.d.ts → cloud-artifacts.d.ts} +249 -240
- package/dist/src/code-signature-cache.js +1 -1
- package/dist/src/code-signature.js +1 -1
- package/dist/src/command-schema.js +3 -3
- package/dist/src/command-tools.js +2 -2
- package/dist/src/command.js +1 -1
- package/dist/src/config.js +1 -1
- package/dist/src/connection-runtime.js +1 -1
- package/dist/src/connection.js +5 -5
- package/dist/src/contracts.d.ts +1 -1
- package/dist/src/contracts.js +1 -1
- package/dist/src/daemon-artifacts.js +1 -0
- package/dist/src/daemon-client-lease-beat.js +1 -1
- package/dist/src/daemon-client-lifecycle.js +1 -1
- package/dist/src/daemon-client-liveness-probe.js +1 -0
- package/dist/src/daemon-client-transport.js +1 -1
- package/dist/src/daemon-http.js +1 -0
- package/dist/src/daemon-policy-file.js +1 -1
- package/dist/src/daemon-registration-owner.js +1 -0
- package/dist/src/daemon-registration.js +1 -1
- package/dist/src/daemon-resolution.js +1 -1
- package/dist/src/daemon-shutdown-report.js +1 -1
- package/dist/src/daemon.js +2 -2
- package/dist/src/debug-symbols-facade.js +3 -3
- package/dist/src/device-claim-inspection.js +1 -1
- package/dist/src/device-claim-rule.js +1 -1
- package/dist/src/device-inventory-context.js +1 -1
- package/dist/src/device-readiness-runtime.js +1 -1
- package/dist/src/device-release.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/device.js +1 -1
- package/dist/src/device2.js +1 -3
- package/dist/src/device3.js +3 -0
- package/dist/src/devicectl.js +1 -1
- package/dist/src/diagnostics.js +3 -3
- package/dist/src/dispatch-resolve.js +4 -1
- package/dist/src/display-inventory.js +1 -1
- package/dist/src/doctor-facade.js +1 -1
- package/dist/src/doctor2.js +1 -1
- package/dist/src/durable-capture-resource.js +1 -0
- 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/generic-settle.js +1 -1
- package/dist/src/generic.js +1 -1
- package/dist/src/gesture-admission.js +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/hdc.js +1 -1
- package/dist/src/helper.js +2 -2
- package/dist/src/host-file.js +1 -1
- package/dist/src/host.js +1 -1
- package/dist/src/human-control-contract.js +1 -1
- package/dist/src/human-control.js +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +1 -1
- package/dist/src/input-actions2.js +2 -2
- package/dist/src/install-artifact-facade.js +1 -1
- package/dist/src/install-source-network-transport.js +1 -1
- package/dist/src/install-source.d.ts +5 -0
- package/dist/src/install-source2.js +1 -1
- package/dist/src/instance-client.js +1 -0
- package/dist/src/interaction-positionals.js +1 -1
- package/dist/src/interaction-ref-policy.js +1 -1
- package/dist/src/interaction.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor-operation-binding.js +1 -1
- package/dist/src/interactor.js +5 -5
- 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 +1 -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 +4 -4
- 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-client.js +4 -30
- package/dist/src/ios-settings.js +1 -0
- package/dist/src/ios-snapshot-engine.js +1 -1
- package/dist/src/ios-snapshot-runtime.js +1 -1
- package/dist/src/launch-confirmation.js +1 -0
- package/dist/src/lease-context.js +1 -1
- package/dist/src/lease-registry-scope.js +1 -0
- package/dist/src/lease-scope.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/legacy-xctest-device-set.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 +78 -44
- package/dist/src/limrun.js +1 -1
- package/dist/src/linux.js +1 -1
- package/dist/src/load.js +1 -0
- package/dist/src/location-coordinates.js +1 -1
- package/dist/src/macos-facade.js +1 -1
- package/dist/src/managed-device-scope.js +1 -1
- package/dist/src/mechanics.js +16 -16
- package/dist/src/observation.js +1 -1
- package/dist/src/observe-until.js +1 -1
- package/dist/src/overlay.js +2 -2
- package/dist/src/owner-identity.js +3 -3
- package/dist/src/path-resolution.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 +1 -1
- package/dist/src/perf.js +1 -1
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/platform-request-scope.js +1 -1
- package/dist/src/platform-runtime-android-adb-host.js +1 -1
- package/dist/src/platform-runtime-app-log-process.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 +2 -2
- package/dist/src/platform-runtime-runtime-hints.js +2 -2
- package/dist/src/platform-runtime-screen-recording-android-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-apple-runner-transport.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-output-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-process-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/plugins.d.ts +9 -0
- package/dist/src/plugins.js +1 -0
- package/dist/src/plugins2.js +2 -0
- 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/process.js +1 -1
- package/dist/src/project-runtime.js +1 -1
- package/dist/src/provider-credential-fingerprint.js +1 -0
- package/dist/src/provider-device-admission.js +1 -1
- package/dist/src/provider-device-runtimes.js +1 -0
- package/dist/src/provider-limrun-credentials.js +1 -0
- package/dist/src/provider-profile-fields.js +1 -0
- package/dist/src/provider-session-ownership.js +2 -2
- package/dist/src/provider-webdriver.js +2 -1
- package/dist/src/providers.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/record-trace.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 +52 -36
- package/dist/src/remote-config2.js +1 -1
- package/dist/src/replay-divergence.js +1 -1
- package/dist/src/replay.js +2 -2
- package/dist/src/reporting.js +5 -5
- package/dist/src/request-admission.js +1 -1
- package/dist/src/request-cancel.js +1 -1
- package/dist/src/request-cancellation.js +1 -1
- package/dist/src/request-runtime-binding.js +1 -1
- package/dist/src/result-serialization.js +1 -1
- package/dist/src/retry.js +1 -1
- package/dist/src/runner-artifact-manifest.js +1 -1
- package/dist/src/runner-cache-metadata.js +3 -3
- 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 +2 -2
- package/dist/src/runner-exchange.js +1 -1
- package/dist/src/runner-operations-facade.js +1 -1
- package/dist/src/runner-session-types.js +1 -1
- package/dist/src/runner-start-budget.js +1 -1
- package/dist/src/runner.js +1 -1
- package/dist/src/runtime-admission.js +1 -1
- package/dist/src/runtime-transport-hints.js +1 -1
- package/dist/src/runtime.js +1 -1
- package/dist/src/runtime10.js +2 -2
- package/dist/src/runtime2.js +3 -3
- 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/screen-recording-transport.js +1 -1
- package/dist/src/screenshot-density.js +1 -1
- package/dist/src/screenshot-image.js +1 -1
- package/dist/src/screenshot-result.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.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 +47 -2
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-device.js +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 +37 -8
- package/dist/src/selection.js +0 -0
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.d.ts +2 -2
- package/dist/src/selectors.js +1 -1
- package/dist/src/server.js +1 -1
- package/dist/src/session-allocation.js +1 -1
- package/dist/src/session-artifact-paths.js +1 -1
- package/dist/src/session-repair-tombstone.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-stream.js +27 -0
- package/dist/src/session.js +1 -1
- package/dist/src/session2.js +5 -5
- package/dist/src/settings.js +1 -1
- package/dist/src/settings2.js +1 -1
- package/dist/src/simctl-settings-facade.js +1 -0
- package/dist/src/simctl-settings.js +1 -0
- package/dist/src/simctl.js +1 -1
- package/dist/src/simulator-boot.js +1 -1
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-diagnostics.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/src7.js +1 -1
- package/dist/src/src8.js +2 -2
- package/dist/src/store.js +1 -0
- 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/target-evidence.js +1 -1
- package/dist/src/telemetry.js +1 -1
- package/dist/src/text-entry-focus.js +1 -1
- package/dist/src/tool-provider.js +3 -3
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/tool-provider3.js +1 -1
- package/dist/src/toolchain-probe.js +2 -2
- package/dist/src/touch-runtime.js +1 -1
- package/dist/src/touch-runtime2.js +1 -1
- package/dist/src/transport.js +2 -2
- package/dist/src/tv-remote.js +1 -1
- package/dist/src/type-text-runtime.js +1 -1
- package/dist/src/update-check.js +1 -1
- package/dist/src/vars.js +1 -1
- package/dist/src/verified-file.js +1 -1
- package/dist/src/version.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 +5 -1
- package/server.json +2 -2
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.19.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.19.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.19.apk.sha256 +0 -1
- package/dist/src/api.js +0 -3
- package/dist/src/daemon-process.js +0 -1
- package/dist/src/multitouch-support.js +0 -1
- package/dist/src/parameterized-recorded-fill.js +0 -1
- package/dist/src/runner-startup-transport.js +0 -1
- package/dist/src/runner-xctestrun.js +0 -1
- package/dist/src/session-store.js +0 -4
|
@@ -66,6 +66,10 @@ int main(int argc, const char *argv[]) {
|
|
|
66
66
|
@property(nonatomic, assign) NSUInteger firstAlertActions;
|
|
67
67
|
@property(nonatomic, assign) NSUInteger replacementAlertActions;
|
|
68
68
|
@property(nonatomic, strong) UILabel *textEntryWriteBackStatus;
|
|
69
|
+
@property(nonatomic, strong) UILabel *textEntryDigitSlots;
|
|
70
|
+
// Filled from the fixture field's own delegate callbacks so a test can tell that a gesture really
|
|
71
|
+
// took focus from an input that has stopped answering the accessibility query that found it.
|
|
72
|
+
@property(nonatomic, strong) UILabel *textEntryFocusWitness;
|
|
69
73
|
@property(nonatomic, assign) NSUInteger textEntryWriteBacks;
|
|
70
74
|
@property(nonatomic, copy, nullable) NSString *textEntryRenderedValue;
|
|
71
75
|
@property(nonatomic, assign) NSTimeInterval textEntryLastEditTime;
|
|
@@ -73,6 +77,7 @@ int main(int argc, const char *argv[]) {
|
|
|
73
77
|
@property(nonatomic, assign) NSUInteger textEntryBurstEdits;
|
|
74
78
|
@property(nonatomic, assign) NSTimeInterval textEntryBurstMinGap;
|
|
75
79
|
@property(nonatomic, assign) NSTimeInterval textEntryAcknowledgeWindowSeconds;
|
|
80
|
+
@property(nonatomic, strong) NSLayoutConstraint *textEntryFieldTop;
|
|
76
81
|
@property(nonatomic, assign) BOOL alertFixtureStarted;
|
|
77
82
|
@property(nonatomic, strong) NSTimer *alertActivationBusyBackstop;
|
|
78
83
|
@property(nonatomic, strong) NSTimer *alertBannerRepost;
|
|
@@ -81,6 +86,17 @@ int main(int argc, const char *argv[]) {
|
|
|
81
86
|
#if TARGET_OS_IOS
|
|
82
87
|
@interface AgentDeviceRunnerViewController () <UNUserNotificationCenterDelegate>
|
|
83
88
|
@end
|
|
89
|
+
|
|
90
|
+
// A one-time-code field that announces how many digits it holds instead of the digits, the way
|
|
91
|
+
// React Native OTP inputs set `accessibilityValue` on their hidden text input.
|
|
92
|
+
@interface AgentDeviceDigitCountTextField : UITextField
|
|
93
|
+
@end
|
|
94
|
+
|
|
95
|
+
@implementation AgentDeviceDigitCountTextField
|
|
96
|
+
- (NSString *)accessibilityValue {
|
|
97
|
+
return [NSString stringWithFormat:@"%lu of 6 digits", (unsigned long)self.text.length];
|
|
98
|
+
}
|
|
99
|
+
@end
|
|
84
100
|
#endif
|
|
85
101
|
|
|
86
102
|
@implementation AgentDeviceRunnerViewController
|
|
@@ -265,6 +281,11 @@ static NSTimeInterval AgentDeviceTextEntryAcknowledgeWindow(void) {
|
|
|
265
281
|
// Edits further apart than this belong to different bursts: one runner command's characters arrive
|
|
266
282
|
// well inside it, and two commands are separated by at least a commit-wait poll and a status read.
|
|
267
283
|
static const NSTimeInterval AgentDeviceTextEntryBurstBreakSeconds = 1.0;
|
|
284
|
+
static const NSUInteger AgentDeviceTextEntryAutoSubmitLength = 6;
|
|
285
|
+
|
|
286
|
+
static const CGFloat AgentDeviceTextEntryFieldTopInset = 24;
|
|
287
|
+
static const CGFloat AgentDeviceTextEntryFieldHeight = 44;
|
|
288
|
+
static const CGFloat AgentDeviceTextEntryNeighbourGap = 16;
|
|
268
289
|
|
|
269
290
|
- (void)agentDeviceTextEntryDidChange:(UITextField *)textField {
|
|
270
291
|
// A field whose app owns its value, the way a controlled React Native `TextInput` does. A burst
|
|
@@ -293,10 +314,56 @@ static const NSTimeInterval AgentDeviceTextEntryBurstBreakSeconds = 1.0;
|
|
|
293
314
|
}
|
|
294
315
|
[self updateTextEntryWriteBackStatus];
|
|
295
316
|
}
|
|
317
|
+
self.textEntryDigitSlots.text = textField.text;
|
|
296
318
|
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-text-entry-disappear-after-input"] &&
|
|
297
319
|
textField.text.length > 0) {
|
|
298
320
|
[textField removeFromSuperview];
|
|
299
321
|
}
|
|
322
|
+
// An auto-submitting one-time-code field: the last digit navigates away, to a screen whose own
|
|
323
|
+
// input takes the code field's place or to one without an input. `replace-after-input` is the
|
|
324
|
+
// same navigation landing before the code is complete.
|
|
325
|
+
NSArray<NSString *> *arguments = NSProcessInfo.processInfo.arguments;
|
|
326
|
+
BOOL codeComplete = textField.text.length >= AgentDeviceTextEntryAutoSubmitLength;
|
|
327
|
+
if (textField.superview == nil) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if ((codeComplete && [arguments containsObject:@"--agent-device-text-entry-auto-submit"]) ||
|
|
331
|
+
(textField.text.length > 0 && [arguments containsObject:@"--agent-device-text-entry-replace-after-input"])) {
|
|
332
|
+
UITextField *nextScreenField = [[UITextField alloc] initWithFrame:textField.frame];
|
|
333
|
+
if (![arguments containsObject:@"--agent-device-text-entry-unnamed-input"]) {
|
|
334
|
+
nextScreenField.accessibilityIdentifier = @"agent-device-auto-submit-next-screen-input";
|
|
335
|
+
}
|
|
336
|
+
nextScreenField.borderStyle = UITextBorderStyleRoundedRect;
|
|
337
|
+
[textField.superview addSubview:nextScreenField];
|
|
338
|
+
[textField removeFromSuperview];
|
|
339
|
+
[nextScreenField becomeFirstResponder];
|
|
340
|
+
} else if (codeComplete &&
|
|
341
|
+
[arguments containsObject:@"--agent-device-text-entry-auto-submit-without-successor"]) {
|
|
342
|
+
[textField removeFromSuperview];
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Stops answering the element-type query that found it, the moment it takes focus, under
|
|
347
|
+
// `--agent-device-text-entry-unqueryable-on-focus`. #3060's Flutter password field reaches this shape
|
|
348
|
+
// because its two accessibility channels disagree once focused — `TextField` through the legacy
|
|
349
|
+
// attributes, `Other` through the modern ones — and what either channel leaves behind is the same:
|
|
350
|
+
// the tap's element answers the query that resolved it up to the gesture and refuses it after, so a
|
|
351
|
+
// read of it after dispatching records an XCTest failure instead of describing the tap that already
|
|
352
|
+
// landed. The field keeps first-responder, so a test still needs a witness that is not the
|
|
353
|
+
// accessibility tree to tell the gesture landed: `agent-device-text-entry-focus` is a label this
|
|
354
|
+
// method fills in from the field's own delegate callback.
|
|
355
|
+
- (void)agentDeviceTextEntryBecomesUnqueryable:(UITextField *)textField {
|
|
356
|
+
self.textEntryFocusWitness.text = @"focus";
|
|
357
|
+
textField.hidden = YES;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Moves the field up by its own height plus the gap below it when it gains focus, the way keyboard
|
|
361
|
+
// avoidance or a bottom sheet extending above the keyboard does, so the neighbouring field slides
|
|
362
|
+
// into the point the focus tap hit.
|
|
363
|
+
- (void)agentDeviceTextEntryDidBeginEditing:(UITextField *)textField {
|
|
364
|
+
self.textEntryFieldTop.constant =
|
|
365
|
+
AgentDeviceTextEntryFieldTopInset - AgentDeviceTextEntryFieldHeight - AgentDeviceTextEntryNeighbourGap;
|
|
366
|
+
[self.view layoutIfNeeded];
|
|
300
367
|
}
|
|
301
368
|
#endif
|
|
302
369
|
|
|
@@ -339,8 +406,13 @@ static const NSTimeInterval AgentDeviceTextEntryBurstBreakSeconds = 1.0;
|
|
|
339
406
|
}
|
|
340
407
|
|
|
341
408
|
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-text-entry-regression"]) {
|
|
342
|
-
|
|
343
|
-
|
|
409
|
+
BOOL digitCountValue =
|
|
410
|
+
[NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-text-entry-digit-count-value"];
|
|
411
|
+
UITextField *textField =
|
|
412
|
+
digitCountValue ? [[AgentDeviceDigitCountTextField alloc] init] : [[UITextField alloc] init];
|
|
413
|
+
if (![NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-text-entry-unnamed-input"]) {
|
|
414
|
+
textField.accessibilityIdentifier = @"agent-device-hardware-keyboard-input";
|
|
415
|
+
}
|
|
344
416
|
textField.borderStyle = UITextBorderStyleRoundedRect;
|
|
345
417
|
// An empty input view keeps the software keyboard down, which is the hardware-keyboard responder
|
|
346
418
|
// these routes are addressed to. `--agent-device-text-entry-soft-keyboard` leaves the real input
|
|
@@ -354,12 +426,46 @@ static const NSTimeInterval AgentDeviceTextEntryBurstBreakSeconds = 1.0;
|
|
|
354
426
|
forControlEvents:UIControlEventEditingChanged];
|
|
355
427
|
textField.translatesAutoresizingMaskIntoConstraints = NO;
|
|
356
428
|
[self.view addSubview:textField];
|
|
429
|
+
self.textEntryFieldTop = [textField.topAnchor constraintEqualToAnchor:label.bottomAnchor
|
|
430
|
+
constant:AgentDeviceTextEntryFieldTopInset];
|
|
357
431
|
[NSLayoutConstraint activateConstraints:@[
|
|
358
432
|
[textField.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
|
|
359
|
-
|
|
433
|
+
self.textEntryFieldTop,
|
|
360
434
|
[textField.widthAnchor constraintEqualToConstant:240],
|
|
361
|
-
[textField.heightAnchor constraintEqualToConstant:
|
|
435
|
+
[textField.heightAnchor constraintEqualToConstant:AgentDeviceTextEntryFieldHeight],
|
|
362
436
|
]];
|
|
437
|
+
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-text-entry-unqueryable-on-focus"]) {
|
|
438
|
+
self.textEntryFocusWitness = [[UILabel alloc] init];
|
|
439
|
+
self.textEntryFocusWitness.accessibilityIdentifier = @"agent-device-text-entry-focus";
|
|
440
|
+
self.textEntryFocusWitness.translatesAutoresizingMaskIntoConstraints = NO;
|
|
441
|
+
[self.view addSubview:self.textEntryFocusWitness];
|
|
442
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
443
|
+
[self.textEntryFocusWitness.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
|
|
444
|
+
[self.textEntryFocusWitness.topAnchor constraintEqualToAnchor:textField.bottomAnchor constant:24],
|
|
445
|
+
]];
|
|
446
|
+
[textField addTarget:self
|
|
447
|
+
action:@selector(agentDeviceTextEntryBecomesUnqueryable:)
|
|
448
|
+
forControlEvents:UIControlEventEditingDidBegin];
|
|
449
|
+
}
|
|
450
|
+
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-text-entry-moves-on-focus"]) {
|
|
451
|
+
textField.text = @"stale";
|
|
452
|
+
[textField addTarget:self
|
|
453
|
+
action:@selector(agentDeviceTextEntryDidBeginEditing:)
|
|
454
|
+
forControlEvents:UIControlEventEditingDidBegin];
|
|
455
|
+
UITextField *neighbour = [[UITextField alloc] init];
|
|
456
|
+
neighbour.accessibilityIdentifier = @"agent-device-text-entry-neighbour";
|
|
457
|
+
neighbour.borderStyle = UITextBorderStyleRoundedRect;
|
|
458
|
+
neighbour.text = @"neighbour";
|
|
459
|
+
neighbour.translatesAutoresizingMaskIntoConstraints = NO;
|
|
460
|
+
[self.view addSubview:neighbour];
|
|
461
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
462
|
+
[neighbour.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
|
|
463
|
+
[neighbour.topAnchor constraintEqualToAnchor:textField.bottomAnchor
|
|
464
|
+
constant:AgentDeviceTextEntryNeighbourGap],
|
|
465
|
+
[neighbour.widthAnchor constraintEqualToConstant:240],
|
|
466
|
+
[neighbour.heightAnchor constraintEqualToConstant:AgentDeviceTextEntryFieldHeight],
|
|
467
|
+
]];
|
|
468
|
+
}
|
|
363
469
|
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-text-entry-app-owned-value"]) {
|
|
364
470
|
self.textEntryAcknowledgeWindowSeconds = AgentDeviceTextEntryAcknowledgeWindow();
|
|
365
471
|
// Reports how many edits this app rendered and how many writes it had to make because a
|
|
@@ -375,6 +481,17 @@ static const NSTimeInterval AgentDeviceTextEntryBurstBreakSeconds = 1.0;
|
|
|
375
481
|
]];
|
|
376
482
|
[self updateTextEntryWriteBackStatus];
|
|
377
483
|
}
|
|
484
|
+
if (digitCountValue) {
|
|
485
|
+
// The slots an OTP screen renders next to its input: the digits the field really holds.
|
|
486
|
+
self.textEntryDigitSlots = [[UILabel alloc] init];
|
|
487
|
+
self.textEntryDigitSlots.accessibilityIdentifier = @"agent-device-text-entry-digit-slots";
|
|
488
|
+
self.textEntryDigitSlots.translatesAutoresizingMaskIntoConstraints = NO;
|
|
489
|
+
[self.view addSubview:self.textEntryDigitSlots];
|
|
490
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
491
|
+
[self.textEntryDigitSlots.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
|
|
492
|
+
[self.textEntryDigitSlots.topAnchor constraintEqualToAnchor:textField.bottomAnchor constant:12],
|
|
493
|
+
]];
|
|
494
|
+
}
|
|
378
495
|
}
|
|
379
496
|
|
|
380
497
|
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-crowded-screen"]) {
|
|
@@ -422,6 +539,8 @@ static const NSTimeInterval AgentDeviceTextEntryBurstBreakSeconds = 1.0;
|
|
|
422
539
|
// UIApplicationSceneManifest in Info.plist names this class; a rename must update the manifest.
|
|
423
540
|
@interface AgentDeviceRunnerSceneDelegate : UIResponder <UIWindowSceneDelegate>
|
|
424
541
|
@property(nonatomic, strong) UIWindow *window;
|
|
542
|
+
// Held for the app's lifetime: a window nobody retained would be gone before the test queried it.
|
|
543
|
+
@property(nonatomic, strong) UIWindow *secondWindow;
|
|
425
544
|
@end
|
|
426
545
|
|
|
427
546
|
@implementation AgentDeviceRunnerSceneDelegate
|
|
@@ -442,6 +561,16 @@ static const NSTimeInterval AgentDeviceTextEntryBurstBreakSeconds = 1.0;
|
|
|
442
561
|
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-dismiss-popup-window"]) {
|
|
443
562
|
self.window.accessibilityIdentifier = @"Dismiss popup";
|
|
444
563
|
}
|
|
564
|
+
// A second window the app keeps visible, so `app.windows` reports the main window and this one.
|
|
565
|
+
// Window order is what the resolver walks, and a candidate behind the answer must never be read.
|
|
566
|
+
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-second-window"]) {
|
|
567
|
+
UIWindow *second = [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)scene];
|
|
568
|
+
second.frame = ((UIWindowScene *)scene).coordinateSpace.bounds;
|
|
569
|
+
second.accessibilityIdentifier = @"agent-device-second-window";
|
|
570
|
+
second.rootViewController = [UIViewController new];
|
|
571
|
+
self.secondWindow = second;
|
|
572
|
+
[second makeKeyAndVisible];
|
|
573
|
+
}
|
|
445
574
|
#endif
|
|
446
575
|
[self.window makeKeyAndVisible];
|
|
447
576
|
}
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h
CHANGED
|
@@ -5,6 +5,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
5
5
|
FOUNDATION_EXPORT NSInteger RunnerControlledScrollFrameCount(double durationMs);
|
|
6
6
|
FOUNDATION_EXPORT double RunnerControlledScrollProgress(double t);
|
|
7
7
|
|
|
8
|
+
typedef NS_ENUM(NSInteger, RunnerTapSynthesisStatus) {
|
|
9
|
+
RunnerTapSynthesisStatusSucceeded,
|
|
10
|
+
RunnerTapSynthesisStatusDeadlineExceeded,
|
|
11
|
+
RunnerTapSynthesisStatusFailed,
|
|
12
|
+
};
|
|
13
|
+
|
|
8
14
|
@interface RunnerSynthesizedGesture : NSObject
|
|
9
15
|
|
|
10
16
|
// `resolvedWindow` is the app window the caller already resolved for the gesture's reference
|
|
@@ -26,10 +32,12 @@ FOUNDATION_EXPORT double RunnerControlledScrollProgress(double t);
|
|
|
26
32
|
y2:(double)y2
|
|
27
33
|
durationMs:(double)durationMs;
|
|
28
34
|
|
|
29
|
-
+ (
|
|
35
|
+
+ (RunnerTapSynthesisStatus)synthesizeTapWithApplication:(id)application
|
|
30
36
|
resolvedWindow:(id _Nullable)resolvedWindow
|
|
31
37
|
x:(double)x
|
|
32
|
-
y:(double)y
|
|
38
|
+
y:(double)y
|
|
39
|
+
deadline:(NSDate * _Nullable)deadline
|
|
40
|
+
errorMessage:(NSString * _Nullable * _Nullable)errorMessage;
|
|
33
41
|
|
|
34
42
|
// Each pointer is an ordered array of { x, y, offsetMs } samples. The first sample
|
|
35
43
|
// starts contact; subsequent samples move it; all pointers lift at their final offset.
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m
CHANGED
|
@@ -75,7 +75,13 @@ static NSString * _Nullable RunnerTrySynthesizeDrag(
|
|
|
75
75
|
NSString *recordName,
|
|
76
76
|
RunnerDragPointerPathFactory pathFactory
|
|
77
77
|
);
|
|
78
|
-
static
|
|
78
|
+
static RunnerTapSynthesisStatus RunnerTrySynthesizeTap(
|
|
79
|
+
id application,
|
|
80
|
+
id _Nullable resolvedWindow,
|
|
81
|
+
CGPoint point,
|
|
82
|
+
NSDate * _Nullable deadline,
|
|
83
|
+
NSString * _Nullable * _Nullable errorMessage
|
|
84
|
+
);
|
|
79
85
|
// XCTest's proven swipe profile reaches the endpoint in 100 ms, then holds for the planned
|
|
80
86
|
// fling duration. Fast movement is what lets UIKit distinguish a fling from a timed pan.
|
|
81
87
|
static const NSTimeInterval RunnerSwipeMovementDurationSeconds = 0.1;
|
|
@@ -132,14 +138,20 @@ static id RunnerTapPointerPath(
|
|
|
132
138
|
}
|
|
133
139
|
}
|
|
134
140
|
|
|
135
|
-
+ (
|
|
141
|
+
+ (RunnerTapSynthesisStatus)synthesizeTapWithApplication:(id)application
|
|
136
142
|
resolvedWindow:(id _Nullable)resolvedWindow
|
|
137
143
|
x:(double)x
|
|
138
|
-
y:(double)y
|
|
144
|
+
y:(double)y
|
|
145
|
+
deadline:(NSDate * _Nullable)deadline
|
|
146
|
+
errorMessage:(NSString * _Nullable * _Nullable)errorMessage {
|
|
147
|
+
if (errorMessage != NULL) *errorMessage = nil;
|
|
139
148
|
@try {
|
|
140
|
-
return RunnerTrySynthesizeTap(application, resolvedWindow, CGPointMake(x, y));
|
|
149
|
+
return RunnerTrySynthesizeTap(application, resolvedWindow, CGPointMake(x, y), deadline, errorMessage);
|
|
141
150
|
} @catch (NSException *exception) {
|
|
142
|
-
|
|
151
|
+
if (errorMessage != NULL) {
|
|
152
|
+
*errorMessage = RunnerFormatXCTestException(exception, @"private XCTest event synthesis failed");
|
|
153
|
+
}
|
|
154
|
+
return RunnerTapSynthesisStatusFailed;
|
|
143
155
|
}
|
|
144
156
|
}
|
|
145
157
|
|
|
@@ -227,7 +239,13 @@ static NSString * _Nullable RunnerTrySynthesizeDrag(
|
|
|
227
239
|
return RunnerSynthesizeEventRecord(&bridge, record);
|
|
228
240
|
}
|
|
229
241
|
|
|
230
|
-
static
|
|
242
|
+
static RunnerTapSynthesisStatus RunnerTrySynthesizeTap(
|
|
243
|
+
id application,
|
|
244
|
+
id _Nullable resolvedWindow,
|
|
245
|
+
CGPoint point,
|
|
246
|
+
NSDate * _Nullable deadline,
|
|
247
|
+
NSString * _Nullable * _Nullable errorMessage
|
|
248
|
+
) {
|
|
231
249
|
RunnerGestureEventBridge bridge;
|
|
232
250
|
id record = nil;
|
|
233
251
|
NSString *error = RunnerCreateEventRecord(
|
|
@@ -237,14 +255,23 @@ static NSString * _Nullable RunnerTrySynthesizeTap(id application, id _Nullable
|
|
|
237
255
|
&bridge,
|
|
238
256
|
&record
|
|
239
257
|
);
|
|
240
|
-
if (error != nil)
|
|
258
|
+
if (error != nil) {
|
|
259
|
+
if (errorMessage != NULL) *errorMessage = error;
|
|
260
|
+
return RunnerTapSynthesisStatusFailed;
|
|
261
|
+
}
|
|
241
262
|
|
|
242
263
|
id path = RunnerTapPointerPath(&bridge, point);
|
|
243
264
|
if (path == nil) {
|
|
244
|
-
|
|
265
|
+
if (errorMessage != NULL) *errorMessage = @"private XCTest event synthesis failed: could not create pointer path";
|
|
266
|
+
return RunnerTapSynthesisStatusFailed;
|
|
245
267
|
}
|
|
246
268
|
((RunnerMsgSendAddPath)objc_msgSend)(record, bridge.core.addPathSelector, path);
|
|
247
|
-
|
|
269
|
+
if (deadline != nil && deadline.timeIntervalSinceNow <= 0) {
|
|
270
|
+
return RunnerTapSynthesisStatusDeadlineExceeded;
|
|
271
|
+
}
|
|
272
|
+
error = RunnerSynthesizeEventRecord(&bridge, record);
|
|
273
|
+
if (errorMessage != NULL) *errorMessage = error;
|
|
274
|
+
return error == nil ? RunnerTapSynthesisStatusSucceeded : RunnerTapSynthesisStatusFailed;
|
|
248
275
|
}
|
|
249
276
|
|
|
250
277
|
static NSString * _Nullable RunnerResolveGestureEventBridge(
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift
CHANGED
|
@@ -138,12 +138,40 @@ extension RunnerTests {
|
|
|
138
138
|
#if !os(tvOS)
|
|
139
139
|
guard !frame.isEmpty else { return }
|
|
140
140
|
#endif
|
|
141
|
+
#if os(iOS)
|
|
142
|
+
let postEventWaitSelector = NSSelectorFromString("_waitForQuiescenceAsPreEvent:")
|
|
143
|
+
guard alert.ownerApp.responds(to: postEventWaitSelector) else {
|
|
144
|
+
outcome = .unsupported(
|
|
145
|
+
message: "alert activation could not wait for post-event quiescence",
|
|
146
|
+
hint: "Inspect the current alert before deciding whether to act again."
|
|
147
|
+
)
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
switch synthesizedTapAt(app: alert.ownerApp, x: frame.midX, y: frame.midY, deadline: deadline) {
|
|
151
|
+
case .performed?:
|
|
152
|
+
typealias WaitForQuiescence = @convention(c) (NSObject, Selector, Bool) -> Void
|
|
153
|
+
let waitForQuiescence = unsafeBitCast(
|
|
154
|
+
alert.ownerApp.method(for: postEventWaitSelector),
|
|
155
|
+
to: WaitForQuiescence.self
|
|
156
|
+
)
|
|
157
|
+
waitForQuiescence(alert.ownerApp, postEventWaitSelector, false)
|
|
158
|
+
outcome = .performed
|
|
159
|
+
case .unsupported(let message, _)?:
|
|
160
|
+
outcome = .unsupported(
|
|
161
|
+
message: message,
|
|
162
|
+
hint: "Inspect the current alert before deciding whether to act again."
|
|
163
|
+
)
|
|
164
|
+
case nil:
|
|
165
|
+
break
|
|
166
|
+
}
|
|
167
|
+
#else
|
|
141
168
|
outcome = activateElement(
|
|
142
169
|
app: alert.ownerApp,
|
|
143
170
|
element: button,
|
|
144
171
|
action: "alert \(action)",
|
|
145
172
|
resolvedFrame: frame
|
|
146
173
|
)
|
|
174
|
+
#endif
|
|
147
175
|
}
|
|
148
176
|
}
|
|
149
177
|
return outcome
|
|
@@ -125,22 +125,9 @@ final class RunnerCommandJournal {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
private func encodeResponseJson(command: Command, response: Response) -> String? {
|
|
128
|
-
guard
|
|
128
|
+
guard command.traits.retainsJournalResponseJson else { return nil }
|
|
129
129
|
guard let data = try? JSONEncoder().encode(response) else { return nil }
|
|
130
130
|
guard data.count <= maxResponseJsonBytes else { return nil }
|
|
131
131
|
return String(data: data, encoding: .utf8)
|
|
132
132
|
}
|
|
133
|
-
|
|
134
|
-
private func shouldRetainResponseJson(command: Command) -> Bool {
|
|
135
|
-
switch command.command {
|
|
136
|
-
case .snapshot, .screenshot:
|
|
137
|
-
return false
|
|
138
|
-
case .tap, .mouseClick, .longPress, .drag,
|
|
139
|
-
.remotePress, .type, .swipe, .scroll, .desktopScroll, .findText, .querySelector, .readText,
|
|
140
|
-
.backInApp, .backSystem, .home, .rotate, .appSwitcher, .actionButton, .keyboardDismiss, .keyboardReturn,
|
|
141
|
-
.alert, .sequence, .gesture, .gestureViewport, .recordStart, .recordStop,
|
|
142
|
-
.status, .uptime, .appState, .pasteboardWrite, .activate, .terminate, .targetReset, .shutdown:
|
|
143
|
-
return true
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
133
|
}
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift
CHANGED
|
@@ -224,25 +224,23 @@ extension RunnerTests {
|
|
|
224
224
|
|
|
225
225
|
|
|
226
226
|
|
|
227
|
-
func resolveRunnerWindow(app: XCUIApplication) -> (window: XCUIElement?, frame: CGRect) {
|
|
228
|
-
let windows = app.windows.allElementsBoundByIndex
|
|
229
|
-
var frames: [CGRect?] = []
|
|
230
|
-
for window in windows {
|
|
231
|
-
frames.append(window.exists ? window.frame : nil)
|
|
232
|
-
}
|
|
233
|
-
if let index = Self.firstUsableWindowIndex(frames: frames) {
|
|
234
|
-
return (windows[index], frames[index] ?? .zero)
|
|
235
|
-
}
|
|
236
|
-
return (nil, app.frame)
|
|
237
|
-
}
|
|
238
227
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
func resolveRunnerWindow(app: XCUIApplication) -> (window: XCUIElement?, frame: CGRect) {
|
|
237
|
+
for window in app.windows.allElementsBoundByIndex where window.exists {
|
|
238
|
+
let frame = window.frame
|
|
239
|
+
if !frame.isEmpty {
|
|
240
|
+
return (window, frame)
|
|
243
241
|
}
|
|
244
242
|
}
|
|
245
|
-
return nil
|
|
243
|
+
return (nil, app.frame)
|
|
246
244
|
}
|
|
247
245
|
|
|
248
246
|
func onScreenWindowFrame(app: XCUIApplication) -> CGRect {
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift
CHANGED
|
@@ -102,16 +102,20 @@ struct CommandTraits {
|
|
|
102
102
|
|
|
103
103
|
let convertsRecordedFailure: Bool
|
|
104
104
|
|
|
105
|
+
let retainsJournalResponseJson: Bool
|
|
106
|
+
|
|
105
107
|
init(
|
|
106
108
|
isInteraction: Bool = false,
|
|
107
109
|
retryOnSessionLoss: Bool = false,
|
|
108
110
|
launchPolicy: CommandLaunchPolicy,
|
|
109
|
-
convertsRecordedFailure: Bool = false
|
|
111
|
+
convertsRecordedFailure: Bool = false,
|
|
112
|
+
retainsJournalResponseJson: Bool
|
|
110
113
|
) {
|
|
111
114
|
self.isInteraction = isInteraction
|
|
112
115
|
self.retryOnSessionLoss = retryOnSessionLoss
|
|
113
116
|
self.launchPolicy = launchPolicy
|
|
114
117
|
self.convertsRecordedFailure = convertsRecordedFailure
|
|
118
|
+
self.retainsJournalResponseJson = retainsJournalResponseJson
|
|
115
119
|
}
|
|
116
120
|
}
|
|
117
121
|
|
|
@@ -121,18 +125,26 @@ fileprivate extension CommandTraits {
|
|
|
121
125
|
static let interaction = CommandTraits(
|
|
122
126
|
isInteraction: true,
|
|
123
127
|
launchPolicy: .mayLaunch,
|
|
124
|
-
convertsRecordedFailure: true
|
|
128
|
+
convertsRecordedFailure: true,
|
|
129
|
+
retainsJournalResponseJson: true
|
|
125
130
|
)
|
|
126
131
|
|
|
127
132
|
|
|
128
133
|
|
|
129
134
|
|
|
130
135
|
|
|
131
|
-
static let appMutation = CommandTraits(
|
|
136
|
+
static let appMutation = CommandTraits(
|
|
137
|
+
launchPolicy: .mayLaunch, convertsRecordedFailure: true, retainsJournalResponseJson: true
|
|
138
|
+
)
|
|
132
139
|
|
|
133
140
|
|
|
134
141
|
|
|
135
|
-
static
|
|
142
|
+
static func appRead(retainsJournalResponseJson: Bool) -> CommandTraits {
|
|
143
|
+
CommandTraits(
|
|
144
|
+
retryOnSessionLoss: true, launchPolicy: .existingApp,
|
|
145
|
+
retainsJournalResponseJson: retainsJournalResponseJson
|
|
146
|
+
)
|
|
147
|
+
}
|
|
136
148
|
|
|
137
149
|
|
|
138
150
|
|
|
@@ -140,33 +152,41 @@ fileprivate extension CommandTraits {
|
|
|
140
152
|
|
|
141
153
|
static let selectorResolution = CommandTraits(
|
|
142
154
|
launchPolicy: .existingApp,
|
|
143
|
-
convertsRecordedFailure: true
|
|
155
|
+
convertsRecordedFailure: true,
|
|
156
|
+
retainsJournalResponseJson: true
|
|
144
157
|
)
|
|
145
158
|
|
|
146
159
|
|
|
147
160
|
|
|
148
|
-
static
|
|
161
|
+
static func runnerCaptureRead(retainsJournalResponseJson: Bool) -> CommandTraits {
|
|
162
|
+
CommandTraits(
|
|
163
|
+
retryOnSessionLoss: true, launchPolicy: .noApp,
|
|
164
|
+
retainsJournalResponseJson: retainsJournalResponseJson
|
|
165
|
+
)
|
|
166
|
+
}
|
|
149
167
|
|
|
150
168
|
|
|
151
|
-
static let runnerLifecycle = CommandTraits(launchPolicy: .noApp)
|
|
169
|
+
static let runnerLifecycle = CommandTraits(launchPolicy: .noApp, retainsJournalResponseJson: true)
|
|
152
170
|
|
|
153
171
|
|
|
154
172
|
|
|
155
173
|
|
|
156
|
-
static let deviceState = CommandTraits(launchPolicy: .noApp)
|
|
174
|
+
static let deviceState = CommandTraits(launchPolicy: .noApp, retainsJournalResponseJson: true)
|
|
157
175
|
|
|
158
176
|
|
|
159
177
|
|
|
160
178
|
|
|
161
179
|
static let presentedSurfaceMutation = CommandTraits(
|
|
162
180
|
launchPolicy: .presentedSurface,
|
|
163
|
-
convertsRecordedFailure: true
|
|
181
|
+
convertsRecordedFailure: true,
|
|
182
|
+
retainsJournalResponseJson: true
|
|
164
183
|
)
|
|
165
184
|
|
|
166
185
|
|
|
167
186
|
static let presentedSurfaceQuery = CommandTraits(
|
|
168
187
|
retryOnSessionLoss: true,
|
|
169
|
-
launchPolicy: .presentedSurface
|
|
188
|
+
launchPolicy: .presentedSurface,
|
|
189
|
+
retainsJournalResponseJson: true
|
|
170
190
|
)
|
|
171
191
|
}
|
|
172
192
|
|
|
@@ -243,13 +263,19 @@ extension Command {
|
|
|
243
263
|
.keyboardDismiss, .keyboardReturn, .sequence, .gesture:
|
|
244
264
|
return .interaction
|
|
245
265
|
|
|
246
|
-
case .findText, .readText, .
|
|
247
|
-
return .appRead
|
|
266
|
+
case .findText, .readText, .gestureViewport:
|
|
267
|
+
return .appRead(retainsJournalResponseJson: true)
|
|
268
|
+
|
|
269
|
+
case .snapshot:
|
|
270
|
+
return .appRead(retainsJournalResponseJson: false)
|
|
248
271
|
|
|
249
272
|
|
|
250
273
|
|
|
251
|
-
case .
|
|
252
|
-
return .runnerCaptureRead
|
|
274
|
+
case .status, .appState:
|
|
275
|
+
return .runnerCaptureRead(retainsJournalResponseJson: true)
|
|
276
|
+
|
|
277
|
+
case .screenshot:
|
|
278
|
+
return .runnerCaptureRead(retainsJournalResponseJson: false)
|
|
253
279
|
|
|
254
280
|
case .alert:
|
|
255
281
|
return (action ?? "get").lowercased() == "get"
|
|
@@ -444,6 +470,13 @@ struct DataPayload: Codable {
|
|
|
444
470
|
var keyboardMinY: Double?
|
|
445
471
|
var maestroNonHittableCoordinateFallbackUsed: Bool?
|
|
446
472
|
var textEntryRoute: String?
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
var verification: String?
|
|
476
|
+
var requested: String?
|
|
477
|
+
var before: String?
|
|
478
|
+
var after: String?
|
|
479
|
+
var target: TextEntryVerificationTargetPayload?
|
|
447
480
|
var runnerFatal: Bool?
|
|
448
481
|
var runnerFatalReason: String?
|
|
449
482
|
|
|
@@ -461,6 +494,26 @@ struct DataPayload: Codable {
|
|
|
461
494
|
}
|
|
462
495
|
|
|
463
496
|
|
|
497
|
+
struct TextEntryVerificationTargetPayload: Codable, Equatable {
|
|
498
|
+
let resourceId: String?
|
|
499
|
+
let className: String?
|
|
500
|
+
let packageName: String?
|
|
501
|
+
let rect: SnapshotRect
|
|
502
|
+
|
|
503
|
+
enum CodingKeys: String, CodingKey {
|
|
504
|
+
case resourceId, className, packageName, rect
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
func encode(to encoder: Encoder) throws {
|
|
508
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
509
|
+
try container.encode(resourceId, forKey: .resourceId)
|
|
510
|
+
try container.encode(className, forKey: .className)
|
|
511
|
+
try container.encode(packageName, forKey: .packageName)
|
|
512
|
+
try container.encode(rect, forKey: .rect)
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
|
|
464
517
|
|
|
465
518
|
|
|
466
519
|
|
|
@@ -68,6 +68,7 @@ extension RunnerTests {
|
|
|
68
68
|
|
|
69
69
|
|
|
70
70
|
|
|
71
|
+
|
|
71
72
|
func awaitSynthesizedReplacementCommit(
|
|
72
73
|
app: XCUIApplication,
|
|
73
74
|
target: TextEntryTarget,
|
|
@@ -82,6 +83,7 @@ extension RunnerTests {
|
|
|
82
83
|
let outcome = Self.awaitSynthesizedReplacementCommitOutcome(
|
|
83
84
|
expectedText: expectedText,
|
|
84
85
|
placeholder: ingredients.placeholder,
|
|
86
|
+
fieldIsSecure: ingredients.fieldIsSecure,
|
|
85
87
|
now: { Date() },
|
|
86
88
|
observe: ingredients.observe,
|
|
87
89
|
waitForNextObservation: ingredients.waitForNextObservation
|
|
@@ -132,13 +134,16 @@ extension RunnerTests {
|
|
|
132
134
|
expectedText: String
|
|
133
135
|
) -> (
|
|
134
136
|
placeholder: String?,
|
|
137
|
+
fieldIsSecure: Bool,
|
|
135
138
|
observe: () -> String?,
|
|
136
139
|
waitForNextObservation: () -> Void
|
|
137
140
|
) {
|
|
138
|
-
let
|
|
141
|
+
let field = resolveTextEntryElement(app: app, target: target)
|
|
142
|
+
let placeholder = field?.placeholderValue
|
|
139
143
|
let waitStartedAt = Date()
|
|
140
144
|
return (
|
|
141
145
|
placeholder: placeholder,
|
|
146
|
+
fieldIsSecure: field?.elementType == .secureTextField,
|
|
142
147
|
observe: {
|
|
143
148
|
let observedText = self.editableTextValue(
|
|
144
149
|
for: self.resolveTextEntryElement(app: app, target: target),
|
|
@@ -143,9 +143,14 @@ extension RunnerTests {
|
|
|
143
143
|
_ app: XCUIApplication,
|
|
144
144
|
kind: SynthesizedGesturePolicyKind,
|
|
145
145
|
context: SynthesizedCoordinateContext?,
|
|
146
|
-
synthesize: () -> RunnerInteractionOutcome
|
|
146
|
+
synthesize: () -> RunnerInteractionOutcome?
|
|
147
147
|
) -> SynthesizedGestureAttempt {
|
|
148
|
-
|
|
148
|
+
var outcome: RunnerInteractionOutcome?
|
|
149
|
+
let timing = measureGesture { outcome = synthesize() }
|
|
150
|
+
guard let outcome else {
|
|
151
|
+
logSynthesizedGesturePolicyDecision(kind: kind, context: context, fallbackAttempted: false)
|
|
152
|
+
return .refused(timing: timing, message: "synthesized gesture deadline expired before dispatch", hint: nil)
|
|
153
|
+
}
|
|
149
154
|
guard case .unsupported(let message, let hint) = outcome else {
|
|
150
155
|
logSynthesizedGesturePolicyDecision(kind: kind, context: context, fallbackAttempted: false)
|
|
151
156
|
return .performed(timing: timing)
|