agent-device 0.20.9 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.9.apk → agent-device-android-ime-helper-0.21.0.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.0.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.9.manifest.json → agent-device-android-ime-helper-0.21.0.manifest.json} +4 -4
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.0.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.0.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.9.manifest.json → agent-device-android-snapshot-helper-0.21.0.manifest.json} +6 -6
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/AudioProbe.swift +35 -33
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/main.swift +6 -1
- package/apple/snapshot-bridge/LICENSE.idb +23 -0
- package/apple/snapshot-bridge/README.md +49 -0
- package/apple/snapshot-bridge/SnapshotBridge.m +280 -0
- package/apple/snapshot-bridge/SnapshotBridgeRuntime.h +33 -0
- package/apple/snapshot-bridge/SnapshotBridgeRuntime.m +382 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +58 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +19 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAlertVerification.swift +36 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerStringNormalization.swift +8 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +12 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +100 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift +2 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +21 -12
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +21 -88
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AlertObservation.swift +124 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +110 -107
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +6 -14
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +85 -114
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +13 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +72 -175
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +10 -11
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXElementTypes.swift +12 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +78 -64
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +17 -9
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +47 -13
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +232 -438
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotBackendCapabilities.swift +98 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +229 -168
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentationInvariant.swift +19 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTiming.swift +110 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedCommitDeadline.swift +206 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +147 -25
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +21 -18
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +24 -307
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +206 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryReadiness.swift +158 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputCandidatePolicy.swift +19 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +49 -16
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +2 -11
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +4 -19
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +16 -20
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/RecordingExportSupport.swift +111 -0
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +42 -81
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-trim.swift +35 -82
- package/dist/apple/snapshot-presentation/Package.swift +21 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotGeometry.swift +56 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotModels.swift +259 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentation.swift +153 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationFailure.swift +27 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationInvariant.swift +91 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationProjection.swift +161 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotScopePolicy.swift +53 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFold.swift +242 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFoldProjection.swift +97 -0
- package/dist/src/adapter.js +1 -0
- package/dist/src/adb-executor.js +2 -0
- package/dist/src/adb-failure.js +1 -0
- package/dist/src/adb-host.js +1 -0
- package/dist/src/adb.js +1 -0
- package/dist/src/agent-browser-lifecycle.js +1 -0
- package/dist/src/agent-browser-process-record.js +1 -0
- package/dist/src/agent-browser-provider.js +1 -0
- package/dist/src/agent-browser-tool.js +1 -1
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/ai-sdk.d.ts +61 -0
- package/dist/src/ai-sdk.js +1 -0
- package/dist/src/alert-contract.js +1 -0
- package/dist/src/alert-runtime.js +1 -0
- package/dist/src/android-adb.d.ts +27 -19
- package/dist/src/android-adb.js +1 -1
- package/dist/src/android-input-ownership.js +1 -0
- package/dist/src/android-system-chrome.js +1 -0
- package/dist/src/android.js +1 -1
- package/dist/src/api.js +11 -0
- package/dist/src/app-catalog.js +1 -0
- package/dist/src/app-deployment-resolution.js +2 -0
- package/dist/src/app-helpers.js +1 -1
- package/dist/src/app-inventory-contract.js +1 -0
- package/dist/src/app-inventory.js +1 -0
- package/dist/src/app-launch.js +2 -0
- package/dist/src/app-lifecycle-facade.js +1 -0
- package/dist/src/app-lifecycle.js +3 -6
- package/dist/src/app-lifecycle2.js +2 -2
- package/dist/src/app-lifecycle3.js +1 -0
- package/dist/src/app-log-files.js +1 -1
- package/dist/src/app-log-reconnect.js +1 -1
- package/dist/src/app-log-runtime.js +1 -4
- package/dist/src/app-log-runtime2.js +4 -0
- package/dist/src/app-parsers.js +4 -0
- package/dist/src/app-resolution-cache.js +1 -0
- package/dist/src/app-resolution-facade.js +1 -0
- package/dist/src/app-resolution.js +2 -2
- package/dist/src/app-state.js +1 -2
- package/dist/src/application-lifecycle-interaction.js +1 -0
- package/dist/src/application-lifecycle-runtime.js +1 -0
- package/dist/src/apps-simctl.js +1 -0
- package/dist/src/archive.js +4 -0
- package/dist/src/artifact-download.js +1 -0
- package/dist/src/artifacts.d.ts +6 -2
- package/dist/src/artifacts.js +1 -1
- package/dist/src/async-lifecycle.js +1 -0
- package/dist/src/audio-probe-result.js +1 -0
- package/dist/src/audio-probe-runtime.js +1 -0
- package/dist/src/audio-probe-support.js +1 -0
- package/dist/src/auth-session.js +1 -1
- package/dist/src/auth.js +1 -1
- package/dist/src/back-mode.js +1 -0
- package/dist/src/{url.js → base-url.js} +1 -1
- package/dist/src/boot-diagnostics.js +2 -2
- package/dist/src/byte-limit-stream.js +1 -1
- package/dist/src/capabilities.js +1 -0
- package/dist/src/capture.js +1 -0
- package/dist/src/catalog.js +1 -0
- package/dist/src/cli-command-aliases.js +1 -0
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +77 -51
- package/dist/src/cli-output.js +1 -1
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +5 -7
- package/dist/src/click-button.js +1 -0
- package/dist/src/client-metro-companion.js +1 -0
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-types.d.ts +1606 -0
- package/dist/src/clipboard.js +1 -0
- package/dist/src/code-signature-cache.js +1 -0
- package/dist/src/code-signature.js +1 -0
- package/dist/src/color.js +1 -0
- package/dist/src/command-metadata.js +1 -1
- package/dist/src/command-schema.js +3 -3
- package/dist/src/command-surface.js +1 -1
- package/dist/src/command-tools.js +2 -0
- package/dist/src/command.js +1 -0
- package/dist/src/{selector-vocabulary.js → compatibility-policy.js} +1 -1
- package/dist/src/config.js +1 -1
- package/dist/src/config2.js +1 -0
- 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-client-lifecycle.js +1 -0
- package/dist/src/daemon-process.js +1 -0
- package/dist/src/daemon-registration.js +1 -0
- package/dist/src/daemon-shutdown-report.js +1 -1
- package/dist/src/daemon.js +2 -2
- package/dist/src/debug-symbols-facade.js +5 -0
- package/dist/src/deploy-result-target.js +1 -0
- package/dist/src/device-claim-inspection.js +1 -1
- package/dist/src/device-claim-rule.js +1 -0
- package/dist/src/device-input-state.d.ts +190 -3
- package/dist/src/device-inventory-context.js +1 -0
- package/dist/src/device-isolation.js +1 -0
- package/dist/src/device-release.js +1 -0
- package/dist/src/device-rotation.js +1 -0
- package/dist/src/device-selection-resolver.js +1 -0
- package/dist/src/device-session.js +1 -0
- package/dist/src/device.js +1 -1
- package/dist/src/device2.js +3 -2
- package/dist/src/diagnostics.js +3 -0
- package/dist/src/diagnostics2.js +1 -0
- package/dist/src/dispatch-resolve.js +1 -0
- package/dist/src/doctor-facade.js +1 -0
- package/dist/src/doctor-output.js +1 -0
- package/dist/src/doctor.js +1 -0
- package/dist/src/doctor2.js +1 -0
- package/dist/src/doctor3.js +1 -0
- package/dist/src/durable-resource.js +1 -0
- package/dist/src/entities.js +1 -1
- package/dist/src/error.js +2 -0
- package/dist/src/exec.js +1 -0
- package/dist/src/file.js +1 -0
- package/dist/src/find.js +1 -1
- package/dist/src/finders.js +1 -1
- package/dist/src/format.js +2 -0
- package/dist/src/generic-settle.js +1 -1
- package/dist/src/generic.js +1 -1
- package/dist/src/gesture-admission.js +1 -0
- package/dist/src/gesture-plan-types.js +1 -0
- package/dist/src/gesture-plan.js +1 -0
- package/dist/src/gesture-runtime.js +1 -0
- 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 -0
- package/dist/src/human-control-contract.js +1 -0
- package/dist/src/human-control.js +1 -0
- package/dist/src/index.d.ts +2 -1578
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +1 -4
- package/dist/src/input-actions2.js +2 -1
- package/dist/src/install-artifact-facade.js +1 -0
- package/dist/src/install-source-network-transport.js +1 -0
- package/dist/src/install-source.d.ts +3 -10
- package/dist/src/install-source2.js +1 -1
- package/dist/src/interaction-positionals.js +1 -0
- package/dist/src/interaction-ref-policy.js +1 -0
- package/dist/src/interaction.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor-operation-catalog.js +1 -0
- package/dist/src/interactor-types.js +1 -0
- package/dist/src/interactor.js +6 -2
- package/dist/src/interactor2.js +1 -1
- package/dist/src/interactors.js +1 -1
- package/dist/src/internal/bin.d.ts +1 -1
- package/dist/src/internal/bin.js +1 -2
- package/dist/src/internal/companion-tunnel.d.ts +1 -1
- package/dist/src/internal/companion-tunnel.js +1 -1
- package/dist/src/internal/daemon.d.ts +1 -1
- package/dist/src/internal/daemon.js +2 -4
- package/dist/src/internal/png-worker.d.ts +4 -4
- package/dist/src/internal/png-worker.js +1 -1
- package/dist/src/internal/run-script-http-child.d.ts +4 -0
- package/dist/src/internal/run-script-http-child.js +1 -0
- package/dist/src/internal/update-check-entry.d.ts +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/inventory6.js +1 -1
- package/dist/src/ios-client.js +16 -0
- package/dist/src/ios-snapshot-acquisition.js +1 -0
- package/dist/src/ios-snapshot-adapter.js +1 -0
- package/dist/src/ios-snapshot-planning.js +1 -0
- package/dist/src/ios-snapshot-runtime.js +1 -0
- package/dist/src/json.js +1 -0
- package/dist/src/keyboard-actions.js +1 -0
- package/dist/src/launch-console.js +1 -0
- package/dist/src/lease-context.js +1 -1
- package/dist/src/lease-scope.js +1 -0
- package/dist/src/lease.js +1 -1
- package/dist/src/limrun-runtime-dependencies.js +1 -1
- package/dist/src/limrun.d.ts +1618 -7
- package/dist/src/limrun.js +1 -1
- package/dist/src/linux.js +1 -1
- package/dist/src/local-interactor-operation-set.js +1 -0
- package/dist/src/location-coordinates.js +1 -1
- package/dist/src/logcat.js +1 -1
- package/dist/src/macos-facade.js +1 -0
- package/dist/src/managed-device-scope.js +1 -0
- package/dist/src/mechanics.js +19 -0
- package/dist/src/metro.d.ts +4 -2
- package/dist/src/metro.js +1 -1
- package/dist/src/metro2.js +1 -1
- package/dist/src/mobile-snapshot-semantics.js +1 -0
- package/dist/src/multitouch-support.js +1 -0
- package/dist/src/numeric.js +1 -0
- package/dist/src/observability.js +1 -1
- package/dist/src/observation.js +2 -0
- package/dist/src/output-path.js +1 -1
- package/dist/src/owner-identity.js +3 -1
- package/dist/src/parameterized-recorded-fill.js +1 -0
- package/dist/src/parser.js +1 -1
- package/dist/src/perf-facade.js +2 -0
- package/dist/src/perf-runtime-operation-builder.js +1 -0
- package/dist/src/perf-runtime-plan.js +1 -0
- package/dist/src/perf-runtime.js +1 -0
- package/dist/src/perf.js +1 -4
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/physical-device-facade.js +1 -0
- package/dist/src/platform-request-scope.js +1 -0
- package/dist/src/platform-runtime-android-adb-host.js +1 -0
- package/dist/src/platform-runtime-android-mechanics.js +1 -0
- package/dist/src/platform-runtime-app-log-android-transport.js +1 -1
- package/dist/src/platform-runtime-app-log-process.js +1 -1
- package/dist/src/platform-runtime-apple-resources.js +1 -0
- package/dist/src/platform-runtime-host.js +1 -1
- package/dist/src/platform-runtime-managed-owner.js +1 -0
- package/dist/src/platform-runtime-network-web-transport.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 +2 -2
- package/dist/src/platform-runtime-screen-recording-android-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-apple-runner-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-apple-transport.js +1 -1
- package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-harmony-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-process-host.js +1 -0
- package/dist/src/platform-runtime-screen-recording-web-host.js +1 -1
- package/dist/src/platform-runtime-unavailable.js +1 -0
- package/dist/src/platform-runtime.js +1 -1
- package/dist/src/platform-runtime2.js +1 -1
- package/dist/src/plist.js +1 -1
- package/dist/src/png-worker-contract.js +1 -1
- package/dist/src/prepare-kind.js +1 -15
- package/dist/src/process-exit.js +1 -1
- package/dist/src/process.js +1 -0
- package/dist/src/provider-device-runtime.js +1 -0
- package/dist/src/provider-session-ownership.js +2 -0
- package/dist/src/provider-webdriver.js +1 -1
- package/dist/src/provider.js +1 -1
- package/dist/src/providers.js +1 -0
- package/dist/src/proxy.js +2 -2
- package/dist/src/react-native-overlay.js +1 -0
- 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/rect-center.js +1 -0
- package/dist/src/register-builtins.js +1 -0
- package/dist/src/registry.js +39 -28
- package/dist/src/remote-config2.js +1 -1
- package/dist/src/replay-divergence.js +2 -0
- package/dist/src/replay.js +2 -2
- package/dist/src/reporting.js +8 -8
- package/dist/src/request-admission.js +1 -0
- package/dist/src/request-cancel.js +1 -0
- package/dist/src/request-cancellation.js +1 -0
- package/dist/src/request-progress-protocol.js +1 -0
- package/dist/src/request-providers.js +1 -0
- package/dist/src/request-runtime-binding.js +1 -0
- package/dist/src/request.js +1 -0
- package/dist/src/result-serialization.js +1 -0
- package/dist/src/retry.js +1 -0
- package/dist/src/rolldown-runtime.js +1 -1
- package/dist/src/runner-cache-metadata.js +2 -0
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-disposal.js +1 -1
- package/dist/src/runner-operations-facade.js +1 -0
- package/dist/src/runner-owner-facade.js +1 -0
- package/dist/src/runner-owner-state.js +1 -0
- package/dist/src/runner-presentation.js +1 -0
- package/dist/src/runner-selector-query.js +1 -0
- package/dist/src/runner.js +1 -0
- package/dist/src/{runtime-transport.js → runtime-transport-hints.js} +1 -1
- package/dist/src/runtime.js +3 -3
- package/dist/src/runtime2.js +4 -4
- package/dist/src/runtime3.js +1 -1
- package/dist/src/runtime4.js +4 -3
- package/dist/src/runtime5.js +1 -1
- package/dist/src/runtime6.js +1 -1
- package/dist/src/runtime7.js +1 -1
- package/dist/src/runtime8.js +1 -1
- package/dist/src/runtime9.js +1 -1
- package/dist/src/scoped-provider.js +1 -1
- package/dist/src/screen-recording-completion.js +1 -0
- package/dist/src/screen-recording-live-handle.js +1 -0
- package/dist/src/screen-recording-options.js +1 -0
- package/dist/src/screen-recording-resource-recovery.js +1 -0
- package/dist/src/screen-recording-runtime.js +1 -0
- package/dist/src/screenshot-density.js +1 -1
- package/dist/src/screenshot-result.js +1 -6
- package/dist/src/screenshot-runtime.js +1 -0
- package/dist/src/screenshot.js +1 -1
- package/dist/src/screenshot2.js +1 -0
- package/dist/src/screenshot3.js +5 -0
- package/dist/src/script.js +1 -0
- package/dist/src/scroll-command.js +1 -0
- package/dist/src/scroll-gesture.js +1 -0
- package/dist/src/scroll-indicator.js +1 -0
- package/dist/src/sdk-batch-runner.d.ts +23 -6
- package/dist/src/sdk-batch-runner.js +2 -3
- package/dist/src/sdk-batch.js +2 -0
- package/dist/src/sdk-contracts.d.ts +222 -99
- 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-finders.js +1 -1
- package/dist/src/sdk-io.js +1 -1
- package/dist/src/sdk-remote-config.d.ts +1 -1
- package/dist/src/sdk-remote-config.js +1 -1
- package/dist/src/sdk-selectors.d.ts +539 -199
- package/dist/src/sdk-selectors.js +1 -1
- package/dist/src/selection.js +1 -0
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.js +1 -1
- package/dist/src/semantic-index.js +1 -0
- package/dist/src/server.js +10 -3
- package/dist/src/session-allocation.js +1 -0
- package/dist/src/session-artifact-paths.js +1 -0
- package/dist/src/session-paths.js +1 -0
- package/dist/src/session-repair-tombstone.js +1 -0
- package/dist/src/session-routing.js +1 -0
- package/dist/src/session-runtime-admission.js +1 -0
- package/dist/src/session-snapshot.js +1 -0
- package/dist/src/session-store.js +4 -0
- package/dist/src/session-target-evidence.js +1 -1
- package/dist/src/session2.js +5 -28
- package/dist/src/settings.js +1 -0
- package/dist/src/shared.js +2 -2
- package/dist/src/simctl-facade.js +1 -0
- package/dist/src/simctl.js +1 -1
- package/dist/src/simulator-facade.js +1 -0
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-capture-annotations.js +1 -0
- package/dist/src/snapshot-desktop-projection.js +1 -0
- package/dist/src/snapshot-diagnostics.js +1 -0
- package/dist/src/snapshot-process.js +1 -0
- package/dist/src/snapshot-quality-backend-capabilities.js +1 -0
- package/dist/src/snapshot-quality-verdict.js +1 -0
- package/dist/src/snapshot-runtime-binding.js +1 -0
- package/dist/src/snapshot-runtime.js +1 -1
- package/dist/src/snapshot-scope.js +1 -0
- package/dist/src/snapshot-state.js +1 -0
- package/dist/src/snapshot.js +1 -8
- package/dist/src/snapshot2.js +1 -1
- package/dist/src/snapshot3.js +1 -1
- package/dist/src/snapshot4.js +1 -0
- package/dist/src/src.js +1 -1
- package/dist/src/src2.js +1 -1
- package/dist/src/src3.js +1 -2
- package/dist/src/src4.js +1 -0
- package/dist/src/src5.js +1 -0
- package/dist/src/src6.js +1 -0
- package/dist/src/src7.js +2 -0
- package/dist/src/src8.js +115 -0
- package/dist/src/startup-recovery-fence.js +1 -0
- package/dist/src/status-markers.js +1 -0
- package/dist/src/string-enum.js +1 -1
- package/dist/src/success-text.js +1 -0
- package/dist/src/surface-snapshot.js +1 -0
- package/dist/src/surface-snapshot2.js +1 -0
- package/dist/src/takeover.js +5 -0
- package/dist/src/tool-provider-facade.js +1 -0
- package/dist/src/tool-provider.js +4 -3
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/tool-provider3.js +1 -0
- package/dist/src/toolchain-probe.js +2 -0
- package/dist/src/touch-runtime.js +1 -0
- package/dist/src/transport.js +3 -0
- package/dist/src/tree.js +1 -0
- package/dist/src/ttl-memo.js +1 -0
- package/dist/src/tv-remote.js +1 -0
- package/dist/src/type-text-runtime.js +1 -0
- package/dist/src/undici.js +99 -0
- package/dist/src/update-check.js +1 -1
- package/dist/src/verified-file.js +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/video.js +2 -2
- package/dist/src/web.js +2 -1
- package/dist/src/web2.js +1 -0
- package/dist/src/webdriver-ios-snapshot.js +1 -0
- package/dist/src/webdriver-source.js +1 -0
- package/linux/atspi-dump.py +54 -9
- package/package.json +73 -38
- package/server.json +9 -3
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.9.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.9.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.9.apk.sha256 +0 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CoordinateTextEntryTests.swift +0 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +0 -75
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+LifecycleCacheTests.swift +0 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+RecordingTests.swift +0 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SelectorMatchPolicyTests.swift +0 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTraversalIdentityTests.swift +0 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryPolicyTests.swift +0 -4
- package/dist/src/appearance.js +0 -1
- package/dist/src/apps.js +0 -5
- package/dist/src/audio-probe.js +0 -1
- package/dist/src/cancel.js +0 -1
- package/dist/src/cli-grammar.js +0 -1
- package/dist/src/command-catalog.js +0 -1
- package/dist/src/debug-symbols.js +0 -5
- package/dist/src/device-input-state.js +0 -2
- package/dist/src/device-ready.js +0 -1
- package/dist/src/dispatch.js +0 -1
- package/dist/src/handler-utils.js +0 -1
- package/dist/src/helper-package-install.js +0 -1
- package/dist/src/host-process.js +0 -3
- package/dist/src/ime-lifecycle.js +0 -2
- package/dist/src/ime-recovery-marker.js +0 -1
- package/dist/src/input-actions3.js +0 -1
- package/dist/src/install-artifact.js +0 -1
- package/dist/src/install-artifact2.js +0 -1
- package/dist/src/interaction-common.js +0 -1
- package/dist/src/interaction-runtime.js +0 -1
- package/dist/src/interaction-snapshot.js +0 -1
- package/dist/src/manifest.js +0 -1
- package/dist/src/method-scope.js +0 -1
- package/dist/src/png-resize.js +0 -1
- package/dist/src/process-lock.js +0 -1
- package/dist/src/runner-lease.js +0 -1
- package/dist/src/runner-sequence.js +0 -1
- package/dist/src/screenshot-geometry.js +0 -1
- package/dist/src/sdk-android-adb.d.ts +0 -245
- package/dist/src/sdk-android-adb.js +0 -4
- package/dist/src/sdk.js +0 -1
- package/dist/src/setting-state.js +0 -1
- package/dist/src/shell-quote.js +0 -1
- package/dist/src/snapshot-session.js +0 -1
- package/dist/src/timing-safe-equal.js +0 -1
- package/dist/src/unsupported-interactor.js +0 -1
- package/dist/src/verdict.js +0 -1
- /package/dist/src/{recording-telemetry.js → telemetry.js} +0 -0
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import XCTest
|
|
2
|
+
import AgentDeviceSnapshotPresentation
|
|
2
3
|
|
|
3
4
|
extension RunnerTests {
|
|
4
5
|
private static let axSnapshotErrorCode = "IOS_AX_SNAPSHOT_FAILED"
|
|
@@ -15,69 +16,76 @@ extension RunnerTests {
|
|
|
15
16
|
let queryRoot: XCUIElement
|
|
16
17
|
let rootSnapshot: XCUIElementSnapshot
|
|
17
18
|
let viewport: CGRect
|
|
18
|
-
let flatSnapshots: [XCUIElementSnapshot]
|
|
19
|
-
let snapshotRanges: [ObjectIdentifier: (Int, Int)]
|
|
20
|
-
let maxDepth: Int
|
|
21
19
|
}
|
|
22
20
|
|
|
23
21
|
private struct SnapshotEvaluation {
|
|
24
22
|
let label: String
|
|
25
23
|
let identifier: String
|
|
26
24
|
let valueText: String?
|
|
27
|
-
let hittable: Bool
|
|
28
25
|
let focused: Bool
|
|
29
26
|
let selected: Bool
|
|
30
|
-
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private struct SnapshotTraversalEntry {
|
|
30
|
+
let snapshot: XCUIElementSnapshot
|
|
31
|
+
let depth: Int
|
|
32
|
+
let parentIndex: Int?
|
|
33
|
+
let parentPresentedDepth: Int
|
|
34
|
+
let parentTraversal: SnapshotVisibilityFold.TraversalState
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
struct SnapshotCaptureFailure: Error {
|
|
34
38
|
let code: String
|
|
35
39
|
let message: String
|
|
36
40
|
let hint: String
|
|
41
|
+
let qualityReasonCode: String?
|
|
42
|
+
|
|
43
|
+
init(code: String, message: String, hint: String, qualityReasonCode: String? = nil) {
|
|
44
|
+
self.code = code
|
|
45
|
+
self.message = message
|
|
46
|
+
self.hint = hint
|
|
47
|
+
self.qualityReasonCode = qualityReasonCode
|
|
48
|
+
}
|
|
37
49
|
}
|
|
38
50
|
|
|
39
51
|
// MARK: - Snapshot Entry
|
|
40
52
|
|
|
53
|
+
/// One raw-value table covers public XCTest cases and the SDK-hidden Keyboard/Key values.
|
|
54
|
+
static let elementTypeNamesByRawValue = [
|
|
55
|
+
XCUIElement.ElementType.application.rawValue: "Application",
|
|
56
|
+
XCUIElement.ElementType.window.rawValue: "Window",
|
|
57
|
+
XCUIElement.ElementType.button.rawValue: "Button",
|
|
58
|
+
XCUIElement.ElementType.cell.rawValue: "Cell",
|
|
59
|
+
XCUIElement.ElementType.staticText.rawValue: "StaticText",
|
|
60
|
+
XCUIElement.ElementType.textField.rawValue: "TextField",
|
|
61
|
+
XCUIElement.ElementType.textView.rawValue: "TextView",
|
|
62
|
+
XCUIElement.ElementType.secureTextField.rawValue: "SecureTextField",
|
|
63
|
+
XCUIElement.ElementType.switch.rawValue: "Switch",
|
|
64
|
+
XCUIElement.ElementType.slider.rawValue: "Slider",
|
|
65
|
+
XCUIElement.ElementType.link.rawValue: "Link",
|
|
66
|
+
XCUIElement.ElementType.image.rawValue: "Image",
|
|
67
|
+
XCUIElement.ElementType.navigationBar.rawValue: "NavigationBar",
|
|
68
|
+
XCUIElement.ElementType.tabBar.rawValue: "TabBar",
|
|
69
|
+
XCUIElement.ElementType.collectionView.rawValue: "CollectionView",
|
|
70
|
+
XCUIElement.ElementType.table.rawValue: "Table",
|
|
71
|
+
XCUIElement.ElementType.scrollView.rawValue: "ScrollView",
|
|
72
|
+
XCUIElement.ElementType.toolbar.rawValue: "Toolbar",
|
|
73
|
+
XCUIElement.ElementType.searchField.rawValue: "SearchField",
|
|
74
|
+
XCUIElement.ElementType.segmentedControl.rawValue: "SegmentedControl",
|
|
75
|
+
XCUIElement.ElementType.stepper.rawValue: "Stepper",
|
|
76
|
+
XCUIElement.ElementType.picker.rawValue: "Picker",
|
|
77
|
+
XCUIElement.ElementType.activityIndicator.rawValue: "ActivityIndicator",
|
|
78
|
+
XCUIElement.ElementType.progressIndicator.rawValue: "ProgressIndicator",
|
|
79
|
+
XCUIElement.ElementType.checkBox.rawValue: "CheckBox",
|
|
80
|
+
XCUIElement.ElementType.menuItem.rawValue: "MenuItem",
|
|
81
|
+
XCUIElement.ElementType.webView.rawValue: "WebView",
|
|
82
|
+
XCUIElement.ElementType.other.rawValue: "Other",
|
|
83
|
+
19: "Keyboard",
|
|
84
|
+
20: "Key"
|
|
85
|
+
]
|
|
86
|
+
|
|
41
87
|
func elementTypeName(_ type: XCUIElement.ElementType) -> String {
|
|
42
|
-
|
|
43
|
-
case .application: return "Application"
|
|
44
|
-
case .window: return "Window"
|
|
45
|
-
case .button: return "Button"
|
|
46
|
-
case .cell: return "Cell"
|
|
47
|
-
case .staticText: return "StaticText"
|
|
48
|
-
case .textField: return "TextField"
|
|
49
|
-
case .textView: return "TextView"
|
|
50
|
-
case .secureTextField: return "SecureTextField"
|
|
51
|
-
case .switch: return "Switch"
|
|
52
|
-
case .slider: return "Slider"
|
|
53
|
-
case .link: return "Link"
|
|
54
|
-
case .image: return "Image"
|
|
55
|
-
case .navigationBar: return "NavigationBar"
|
|
56
|
-
case .tabBar: return "TabBar"
|
|
57
|
-
case .collectionView: return "CollectionView"
|
|
58
|
-
case .table: return "Table"
|
|
59
|
-
case .scrollView: return "ScrollView"
|
|
60
|
-
case .toolbar: return "Toolbar"
|
|
61
|
-
case .searchField: return "SearchField"
|
|
62
|
-
case .segmentedControl: return "SegmentedControl"
|
|
63
|
-
case .stepper: return "Stepper"
|
|
64
|
-
case .picker: return "Picker"
|
|
65
|
-
case .activityIndicator: return "ActivityIndicator"
|
|
66
|
-
case .progressIndicator: return "ProgressIndicator"
|
|
67
|
-
case .checkBox: return "CheckBox"
|
|
68
|
-
case .menuItem: return "MenuItem"
|
|
69
|
-
case .webView: return "WebView"
|
|
70
|
-
case .other: return "Other"
|
|
71
|
-
default:
|
|
72
|
-
switch type.rawValue {
|
|
73
|
-
case 19:
|
|
74
|
-
return "Keyboard"
|
|
75
|
-
case 20:
|
|
76
|
-
return "Key"
|
|
77
|
-
default:
|
|
78
|
-
return "Element(\(type.rawValue))"
|
|
79
|
-
}
|
|
80
|
-
}
|
|
88
|
+
Self.elementTypeNamesByRawValue[type.rawValue] ?? "Element(\(type.rawValue))"
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
static let structuralOnlyNodeTypes: Set<String> = [
|
|
@@ -108,7 +116,7 @@ extension RunnerTests {
|
|
|
108
116
|
// `boundedBlockingSystemAlertSnapshot`'s probe closure (see `systemModalProbeOverrideForTesting`
|
|
109
117
|
// in RunnerTests.swift), so reverting this entry point to bypass the bounded probe fails the
|
|
110
118
|
// regression test.
|
|
111
|
-
func snapshotFast(app: XCUIApplication, options:
|
|
119
|
+
func snapshotFast(app: XCUIApplication, options: PresentationOptions) throws -> DataPayload {
|
|
112
120
|
let deadline = Date().addingTimeInterval(Self.snapshotPlanBudget)
|
|
113
121
|
if let blocking = boundedBlockingSystemAlertSnapshot(deadline: deadline) {
|
|
114
122
|
return blocking
|
|
@@ -122,10 +130,10 @@ extension RunnerTests {
|
|
|
122
130
|
)
|
|
123
131
|
}
|
|
124
132
|
|
|
125
|
-
func
|
|
133
|
+
func recursiveTreeSnapshotAcquisition(
|
|
126
134
|
context: SnapshotTraversalContext,
|
|
127
|
-
|
|
128
|
-
) ->
|
|
135
|
+
hint: CaptureHint
|
|
136
|
+
) -> SnapshotAcquisition {
|
|
129
137
|
var cachedDescendantElements: [XCUIElement]?
|
|
130
138
|
func collapsedTabDescendants() -> [XCUIElement] {
|
|
131
139
|
if let cachedDescendantElements {
|
|
@@ -138,66 +146,68 @@ extension RunnerTests {
|
|
|
138
146
|
return result.elements
|
|
139
147
|
}
|
|
140
148
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
149
|
+
// Acquisition serializes facts: every traversed node is emitted at raw traversal depth, and
|
|
150
|
+
// the regular projection's clip fold runs once inside `SnapshotPresentation` (#1797). The two
|
|
151
|
+
// walks this backend keeps are the raw budget or regular presented-depth frontier, plus
|
|
152
|
+
// collapsed-tab augmentation which needs live element handles; neither walk publishes a
|
|
153
|
+
// presentation node.
|
|
154
|
+
var nodes: [RawAXNode] = []
|
|
155
|
+
let rootEvaluation = evaluateSnapshot(context.rootSnapshot)
|
|
144
156
|
nodes.append(
|
|
145
157
|
makeSnapshotNode(
|
|
146
158
|
snapshot: context.rootSnapshot,
|
|
147
159
|
evaluation: rootEvaluation,
|
|
148
160
|
depth: 0,
|
|
149
161
|
index: 0,
|
|
150
|
-
parentIndex: nil
|
|
162
|
+
parentIndex: nil,
|
|
163
|
+
viewport: context.viewport
|
|
151
164
|
)
|
|
152
165
|
)
|
|
153
|
-
|
|
166
|
+
let shouldVisitRootChildren = SnapshotPresentation.shouldAcquireChildren(
|
|
167
|
+
for: hint,
|
|
168
|
+
rawDepth: 0,
|
|
169
|
+
regularPresentedDepth: 0
|
|
170
|
+
)
|
|
171
|
+
if shouldVisitRootChildren {
|
|
154
172
|
appendCollapsedTabFallbackNodes(
|
|
155
173
|
to: &nodes,
|
|
156
174
|
containerSnapshot: context.rootSnapshot,
|
|
157
175
|
resolveElements: collapsedTabDescendants,
|
|
158
176
|
depth: 1,
|
|
159
|
-
parentIndex: 0
|
|
177
|
+
parentIndex: 0,
|
|
178
|
+
viewport: context.viewport
|
|
160
179
|
)
|
|
161
180
|
}
|
|
162
181
|
|
|
163
182
|
var seen = Set<String>()
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
183
|
+
var stack: [SnapshotTraversalEntry] = []
|
|
184
|
+
if shouldVisitRootChildren {
|
|
185
|
+
stack = context.rootSnapshot.children.map {
|
|
186
|
+
SnapshotTraversalEntry(
|
|
187
|
+
snapshot: $0,
|
|
188
|
+
depth: 1,
|
|
189
|
+
parentIndex: 0,
|
|
190
|
+
parentPresentedDepth: 0,
|
|
191
|
+
parentTraversal: .root
|
|
192
|
+
)
|
|
172
193
|
}
|
|
194
|
+
}
|
|
173
195
|
|
|
174
|
-
while let
|
|
175
|
-
|
|
196
|
+
while let entry = stack.popLast() {
|
|
197
|
+
let snapshot = entry.snapshot
|
|
198
|
+
let depth = entry.depth
|
|
199
|
+
let parentIndex = entry.parentIndex
|
|
200
|
+
if let limit = hint.rawTraversalDepth, depth > limit { continue }
|
|
176
201
|
|
|
177
|
-
let evaluation = evaluateSnapshot(snapshot
|
|
178
|
-
let
|
|
179
|
-
snapshot.frame,
|
|
180
|
-
viewport: context.viewport,
|
|
181
|
-
scrollContainerAnchor: nearestScrollAnchor
|
|
182
|
-
)
|
|
183
|
-
if !regularVisible, let nearestScrollAnchor {
|
|
184
|
-
rememberHiddenContentHint(
|
|
185
|
-
for: snapshot.frame,
|
|
186
|
-
relativeTo: nearestScrollAnchor,
|
|
187
|
-
hints: &hiddenContentHintsByNodeIndex
|
|
188
|
-
)
|
|
189
|
-
}
|
|
190
|
-
let include = shouldInclude(
|
|
202
|
+
let evaluation = evaluateSnapshot(snapshot)
|
|
203
|
+
let node = makeSnapshotNode(
|
|
191
204
|
snapshot: snapshot,
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
visible: regularVisible,
|
|
198
|
-
regularSnapshot: true
|
|
205
|
+
evaluation: evaluation,
|
|
206
|
+
depth: depth,
|
|
207
|
+
index: nodes.count,
|
|
208
|
+
parentIndex: parentIndex,
|
|
209
|
+
viewport: context.viewport
|
|
199
210
|
)
|
|
200
|
-
|
|
201
211
|
let key = Self.snapshotTraversalIdentity(
|
|
202
212
|
elementType: snapshot.elementType,
|
|
203
213
|
label: evaluation.label,
|
|
@@ -209,58 +219,58 @@ extension RunnerTests {
|
|
|
209
219
|
seen.insert(key)
|
|
210
220
|
}
|
|
211
221
|
|
|
212
|
-
let currentIndex =
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
nextScrollContainerAnchor = nearestScrollAnchor
|
|
226
|
-
}
|
|
222
|
+
let currentIndex = !isDuplicate ? nodes.count : parentIndex
|
|
223
|
+
let transition = SnapshotPresentation.regularTraversalTransition(
|
|
224
|
+
for: node,
|
|
225
|
+
parentPresentedDepth: entry.parentPresentedDepth,
|
|
226
|
+
parentTraversal: entry.parentTraversal,
|
|
227
|
+
hint: hint,
|
|
228
|
+
rawDepth: depth,
|
|
229
|
+
viewport: context.viewport,
|
|
230
|
+
hasChildren: !snapshot.children.isEmpty,
|
|
231
|
+
isDuplicate: isDuplicate,
|
|
232
|
+
policy: .platformDefault
|
|
233
|
+
)
|
|
234
|
+
if transition.shouldVisitChildren {
|
|
227
235
|
for child in snapshot.children.reversed() {
|
|
228
|
-
stack.append(
|
|
236
|
+
stack.append(
|
|
237
|
+
SnapshotTraversalEntry(
|
|
238
|
+
snapshot: child,
|
|
239
|
+
depth: depth + 1,
|
|
240
|
+
parentIndex: currentIndex,
|
|
241
|
+
parentPresentedDepth: transition.presentedDepth,
|
|
242
|
+
parentTraversal: transition.traversal
|
|
243
|
+
)
|
|
244
|
+
)
|
|
229
245
|
}
|
|
230
246
|
}
|
|
231
247
|
|
|
232
|
-
if
|
|
248
|
+
if isDuplicate { continue }
|
|
233
249
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
makeSnapshotNode(
|
|
237
|
-
snapshot: snapshot,
|
|
238
|
-
evaluation: evaluation,
|
|
239
|
-
depth: min(context.maxDepth, visibleDepth),
|
|
240
|
-
index: index,
|
|
241
|
-
parentIndex: parentIndex
|
|
242
|
-
)
|
|
243
|
-
)
|
|
244
|
-
if visibleDepth < context.maxDepth {
|
|
250
|
+
nodes.append(node)
|
|
251
|
+
if transition.shouldVisitChildren {
|
|
245
252
|
appendCollapsedTabFallbackNodes(
|
|
246
253
|
to: &nodes,
|
|
247
254
|
containerSnapshot: snapshot,
|
|
248
255
|
resolveElements: collapsedTabDescendants,
|
|
249
|
-
depth:
|
|
250
|
-
parentIndex: index
|
|
256
|
+
depth: depth + 1,
|
|
257
|
+
parentIndex: node.index,
|
|
258
|
+
viewport: context.viewport
|
|
251
259
|
)
|
|
252
260
|
}
|
|
253
|
-
|
|
254
261
|
}
|
|
255
262
|
|
|
256
|
-
return
|
|
257
|
-
|
|
258
|
-
|
|
263
|
+
return SnapshotAcquisition(
|
|
264
|
+
hint: hint,
|
|
265
|
+
nodes: nodes,
|
|
266
|
+
truncated: false,
|
|
267
|
+
effectiveDepth: nil,
|
|
268
|
+
viewport: context.viewport
|
|
259
269
|
)
|
|
260
270
|
}
|
|
261
271
|
|
|
262
272
|
// See `snapshotFast` above: the single production entry point, no unit-test overload.
|
|
263
|
-
func snapshotRaw(app: XCUIApplication, options:
|
|
273
|
+
func snapshotRaw(app: XCUIApplication, options: PresentationOptions) throws -> DataPayload {
|
|
264
274
|
let deadline = Date().addingTimeInterval(Self.snapshotPlanBudget)
|
|
265
275
|
if let blocking = boundedBlockingSystemAlertSnapshot(deadline: deadline) {
|
|
266
276
|
return blocking
|
|
@@ -306,7 +316,6 @@ extension RunnerTests {
|
|
|
306
316
|
let startedAt = Date()
|
|
307
317
|
do {
|
|
308
318
|
return try runMainThreadWork(
|
|
309
|
-
command: nil,
|
|
310
319
|
timeout: slice,
|
|
311
320
|
timeoutError: {
|
|
312
321
|
SnapshotCaptureFailure(
|
|
@@ -351,40 +360,30 @@ extension RunnerTests {
|
|
|
351
360
|
return min(budget, deadlineRemaining)
|
|
352
361
|
}
|
|
353
362
|
|
|
354
|
-
func
|
|
363
|
+
func rawTreeSnapshotAcquisition(
|
|
355
364
|
context: SnapshotTraversalContext,
|
|
356
|
-
|
|
357
|
-
) throws ->
|
|
358
|
-
var nodes: [
|
|
365
|
+
hint: CaptureHint
|
|
366
|
+
) throws -> SnapshotAcquisition {
|
|
367
|
+
var nodes: [RawAXNode] = []
|
|
359
368
|
|
|
360
369
|
func walk(_ snapshot: XCUIElementSnapshot, depth: Int, parentIndex: Int?) throws {
|
|
361
|
-
if let limit =
|
|
370
|
+
if let limit = hint.rawTraversalDepth, depth > limit { return }
|
|
362
371
|
|
|
363
|
-
let evaluation = evaluateSnapshot(snapshot
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
label: evaluation.label,
|
|
367
|
-
identifier: evaluation.identifier,
|
|
368
|
-
valueText: evaluation.valueText,
|
|
369
|
-
options: options,
|
|
370
|
-
hittable: evaluation.hittable,
|
|
371
|
-
visible: evaluation.visible
|
|
372
|
-
)
|
|
373
|
-
let currentIndex = include ? nodes.count : parentIndex
|
|
374
|
-
if include {
|
|
375
|
-
if nodes.count >= Self.rawSnapshotMaxNodes {
|
|
376
|
-
throw rawSnapshotTooLargeFailure(nodeCount: nodes.count + 1)
|
|
377
|
-
}
|
|
378
|
-
nodes.append(
|
|
379
|
-
makeSnapshotNode(
|
|
380
|
-
snapshot: snapshot,
|
|
381
|
-
evaluation: evaluation,
|
|
382
|
-
depth: depth,
|
|
383
|
-
index: nodes.count,
|
|
384
|
-
parentIndex: parentIndex
|
|
385
|
-
)
|
|
386
|
-
)
|
|
372
|
+
let evaluation = evaluateSnapshot(snapshot)
|
|
373
|
+
if nodes.count >= Self.rawSnapshotMaxNodes {
|
|
374
|
+
throw rawSnapshotTooLargeFailure(nodeCount: nodes.count + 1)
|
|
387
375
|
}
|
|
376
|
+
let currentIndex = nodes.count
|
|
377
|
+
nodes.append(
|
|
378
|
+
makeSnapshotNode(
|
|
379
|
+
snapshot: snapshot,
|
|
380
|
+
evaluation: evaluation,
|
|
381
|
+
depth: depth,
|
|
382
|
+
index: currentIndex,
|
|
383
|
+
parentIndex: parentIndex,
|
|
384
|
+
viewport: context.viewport
|
|
385
|
+
)
|
|
386
|
+
)
|
|
388
387
|
|
|
389
388
|
let children = snapshot.children
|
|
390
389
|
for child in children {
|
|
@@ -393,30 +392,42 @@ extension RunnerTests {
|
|
|
393
392
|
}
|
|
394
393
|
|
|
395
394
|
try walk(context.rootSnapshot, depth: 0, parentIndex: nil)
|
|
396
|
-
return
|
|
395
|
+
return SnapshotAcquisition(
|
|
396
|
+
hint: hint,
|
|
397
|
+
nodes: nodes,
|
|
398
|
+
truncated: false,
|
|
399
|
+
effectiveDepth: nil,
|
|
400
|
+
viewport: context.viewport
|
|
401
|
+
)
|
|
397
402
|
}
|
|
398
403
|
|
|
399
|
-
func
|
|
404
|
+
func querySweepSnapshotAcquisition(
|
|
400
405
|
app: XCUIApplication,
|
|
401
|
-
|
|
406
|
+
hint: CaptureHint,
|
|
402
407
|
planDeadline: Date = .distantFuture
|
|
403
|
-
) ->
|
|
404
|
-
var nodes: [
|
|
408
|
+
) -> SnapshotAcquisition {
|
|
409
|
+
var nodes: [RawAXNode] = [
|
|
405
410
|
interactiveRootNode(rect: .zero)
|
|
406
411
|
]
|
|
407
|
-
if
|
|
408
|
-
return
|
|
412
|
+
if hint.rawTraversalDepth == 0 || hint.regularPresentedDepth == 0 {
|
|
413
|
+
return SnapshotAcquisition(
|
|
414
|
+
hint: hint,
|
|
415
|
+
nodes: nodes,
|
|
416
|
+
truncated: false,
|
|
417
|
+
effectiveDepth: nil,
|
|
418
|
+
viewport: .infinite
|
|
419
|
+
)
|
|
409
420
|
}
|
|
410
421
|
|
|
411
422
|
// Bounded by both its own sweep budget and the umbrella capture-plan deadline, so a
|
|
412
423
|
// chained recovery tier can never push the plan past the main-thread watchdog (#1105).
|
|
413
|
-
let sweepDeadline =
|
|
424
|
+
let sweepDeadline = hint.interactiveOnly
|
|
414
425
|
? Date().addingTimeInterval(Self.flatInteractiveFallbackBudget)
|
|
415
426
|
: Date.distantFuture
|
|
416
427
|
let deadline = min(sweepDeadline, planDeadline)
|
|
417
428
|
let viewport = safeSnapshotViewport(app: app)
|
|
418
429
|
var seen = Set<String>()
|
|
419
|
-
var candidates: [
|
|
430
|
+
var candidates: [RawAXNode] = []
|
|
420
431
|
let flatElements = flatInteractiveElements(app: app, deadline: deadline)
|
|
421
432
|
var truncated = flatElements.truncated
|
|
422
433
|
for element in flatElements.elements {
|
|
@@ -429,8 +440,7 @@ extension RunnerTests {
|
|
|
429
440
|
element: element,
|
|
430
441
|
index: 0,
|
|
431
442
|
parentIndex: 0,
|
|
432
|
-
viewport: viewport
|
|
433
|
-
options: options
|
|
443
|
+
viewport: viewport
|
|
434
444
|
) else {
|
|
435
445
|
continue
|
|
436
446
|
}
|
|
@@ -458,7 +468,7 @@ extension RunnerTests {
|
|
|
458
468
|
nodes[0] = interactiveRootNode(rect: rootRect)
|
|
459
469
|
for candidate in candidates {
|
|
460
470
|
nodes.append(
|
|
461
|
-
|
|
471
|
+
RawAXNode(
|
|
462
472
|
index: nodes.count,
|
|
463
473
|
type: candidate.type,
|
|
464
474
|
label: candidate.label,
|
|
@@ -476,7 +486,13 @@ extension RunnerTests {
|
|
|
476
486
|
)
|
|
477
487
|
)
|
|
478
488
|
}
|
|
479
|
-
return
|
|
489
|
+
return SnapshotAcquisition(
|
|
490
|
+
hint: hint,
|
|
491
|
+
nodes: nodes,
|
|
492
|
+
truncated: truncated,
|
|
493
|
+
effectiveDepth: nil,
|
|
494
|
+
viewport: viewport
|
|
495
|
+
)
|
|
480
496
|
}
|
|
481
497
|
|
|
482
498
|
func snapshotAccessibilityUnavailable(failure: SnapshotCaptureFailure) -> DataPayload {
|
|
@@ -521,7 +537,7 @@ extension RunnerTests {
|
|
|
521
537
|
) -> DataPayload {
|
|
522
538
|
return DataPayload(
|
|
523
539
|
message: message,
|
|
524
|
-
nodes: [interactiveRootNode(rect: .zero)],
|
|
540
|
+
nodes: [SnapshotPresentation.singleElementRead(interactiveRootNode(rect: .zero))],
|
|
525
541
|
truncated: true,
|
|
526
542
|
snapshotQuality: snapshotQuality,
|
|
527
543
|
runnerFatal: runnerFatal,
|
|
@@ -530,8 +546,8 @@ extension RunnerTests {
|
|
|
530
546
|
}
|
|
531
547
|
|
|
532
548
|
|
|
533
|
-
private func interactiveRootNode(rect: CGRect) ->
|
|
534
|
-
|
|
549
|
+
private func interactiveRootNode(rect: CGRect) -> RawAXNode {
|
|
550
|
+
RawAXNode(
|
|
535
551
|
index: 0,
|
|
536
552
|
type: "Application",
|
|
537
553
|
label: nil,
|
|
@@ -549,7 +565,7 @@ extension RunnerTests {
|
|
|
549
565
|
)
|
|
550
566
|
}
|
|
551
567
|
|
|
552
|
-
private func interactiveRootFrame(for candidates: [
|
|
568
|
+
private func interactiveRootFrame(for candidates: [RawAXNode]) -> CGRect {
|
|
553
569
|
guard !candidates.isEmpty else {
|
|
554
570
|
return .zero
|
|
555
571
|
}
|
|
@@ -569,87 +585,29 @@ extension RunnerTests {
|
|
|
569
585
|
|
|
570
586
|
// MARK: - Snapshot Filtering
|
|
571
587
|
|
|
572
|
-
private func shouldInclude(
|
|
573
|
-
snapshot: XCUIElementSnapshot,
|
|
574
|
-
label: String,
|
|
575
|
-
identifier: String,
|
|
576
|
-
valueText: String?,
|
|
577
|
-
options: SnapshotOptions,
|
|
578
|
-
hittable: Bool,
|
|
579
|
-
visible: Bool,
|
|
580
|
-
regularSnapshot: Bool = false
|
|
581
|
-
) -> Bool {
|
|
582
|
-
let type = snapshot.elementType
|
|
583
|
-
let hasContent = !label.isEmpty || !identifier.isEmpty || (valueText != nil)
|
|
584
|
-
if options.interactiveOnly {
|
|
585
|
-
if isScrollableContainer(snapshot, visible: visible) { return true }
|
|
586
|
-
#if os(macOS)
|
|
587
|
-
if !visible && type != .application {
|
|
588
|
-
return false
|
|
589
|
-
}
|
|
590
|
-
#endif
|
|
591
|
-
if interactiveTypes.contains(type) { return true }
|
|
592
|
-
if hittable && type != .other { return true }
|
|
593
|
-
if hasContent { return true }
|
|
594
|
-
return false
|
|
595
|
-
}
|
|
596
|
-
if regularSnapshot {
|
|
597
|
-
if type == .application || type == .window { return true }
|
|
598
|
-
return visible
|
|
599
|
-
}
|
|
600
|
-
return true
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
private func computedSnapshotHittable(
|
|
604
|
-
_ snapshot: XCUIElementSnapshot,
|
|
605
|
-
viewport: CGRect,
|
|
606
|
-
laterNodes: ArraySlice<XCUIElementSnapshot>
|
|
607
|
-
) -> Bool {
|
|
608
|
-
guard snapshot.isEnabled else { return false }
|
|
609
|
-
let frame = snapshot.frame
|
|
610
|
-
if frame.isNull || frame.isEmpty { return false }
|
|
611
|
-
let center = CGPoint(x: frame.midX, y: frame.midY)
|
|
612
|
-
if !viewport.contains(center) { return false }
|
|
613
|
-
for node in laterNodes {
|
|
614
|
-
if !isOccludingType(node.elementType) { continue }
|
|
615
|
-
let nodeFrame = node.frame
|
|
616
|
-
if nodeFrame.isNull || nodeFrame.isEmpty { continue }
|
|
617
|
-
if nodeFrame.contains(center) { return false }
|
|
618
|
-
}
|
|
619
|
-
return true
|
|
620
|
-
}
|
|
621
|
-
|
|
622
588
|
func makeSnapshotTraversalContext(
|
|
623
589
|
app: XCUIApplication,
|
|
624
|
-
|
|
590
|
+
hint: CaptureHint,
|
|
625
591
|
captureDeadline: Date = .distantFuture,
|
|
626
592
|
treeCaptureSliceBudgetOverride: TimeInterval? = nil
|
|
627
593
|
) throws -> SnapshotTraversalContext? {
|
|
628
|
-
let
|
|
629
|
-
command: nil,
|
|
594
|
+
let viewport = try runMainThreadWork(
|
|
630
595
|
timeout: min(1.0, max(0.1, captureDeadline.timeIntervalSinceNow)),
|
|
631
596
|
timeoutError: snapshotMainThreadTimeoutError("preparing tree snapshot")
|
|
632
597
|
) {
|
|
633
|
-
(
|
|
634
|
-
self.safeSnapshotViewport(app: app),
|
|
635
|
-
options.scope.flatMap { self.findScopeElement(app: app, scope: $0) } ?? app
|
|
636
|
-
)
|
|
598
|
+
self.safeSnapshotViewport(app: app)
|
|
637
599
|
}
|
|
638
600
|
|
|
639
601
|
let treeSliceBudget = treeCaptureSliceBudgetOverride ?? treeCaptureSliceBudget
|
|
640
602
|
let slice = min(treeSliceBudget, max(0.5, captureDeadline.timeIntervalSinceNow))
|
|
641
|
-
guard let rootSnapshot = try captureSnapshotRootBounded(
|
|
603
|
+
guard let rootSnapshot = try captureSnapshotRootBounded(app, sliceSeconds: slice) else {
|
|
642
604
|
return nil
|
|
643
605
|
}
|
|
644
606
|
|
|
645
|
-
let (flatSnapshots, snapshotRanges) = flattenedSnapshots(rootSnapshot)
|
|
646
607
|
return SnapshotTraversalContext(
|
|
647
|
-
queryRoot:
|
|
608
|
+
queryRoot: app,
|
|
648
609
|
rootSnapshot: rootSnapshot,
|
|
649
|
-
viewport: viewport
|
|
650
|
-
flatSnapshots: flatSnapshots,
|
|
651
|
-
snapshotRanges: snapshotRanges,
|
|
652
|
-
maxDepth: options.depth ?? Int.max
|
|
610
|
+
viewport: viewport
|
|
653
611
|
)
|
|
654
612
|
}
|
|
655
613
|
|
|
@@ -688,7 +646,6 @@ extension RunnerTests {
|
|
|
688
646
|
return try captureSnapshotRoot(element)
|
|
689
647
|
}
|
|
690
648
|
return try runMainThreadWork(
|
|
691
|
-
command: nil,
|
|
692
649
|
timeout: sliceSeconds,
|
|
693
650
|
timeoutError: treeCaptureTimeoutError(sliceSeconds: sliceSeconds),
|
|
694
651
|
onAbandoned: {
|
|
@@ -786,26 +743,16 @@ extension RunnerTests {
|
|
|
786
743
|
failure.code == Self.axSnapshotErrorCode || isAxIllegalArgument(failure.message)
|
|
787
744
|
}
|
|
788
745
|
|
|
789
|
-
private func evaluateSnapshot(
|
|
790
|
-
_ snapshot: XCUIElementSnapshot,
|
|
791
|
-
in context: SnapshotTraversalContext
|
|
792
|
-
) -> SnapshotEvaluation {
|
|
746
|
+
private func evaluateSnapshot(_ snapshot: XCUIElementSnapshot) -> SnapshotEvaluation {
|
|
793
747
|
let label = aggregatedLabel(for: snapshot) ?? snapshot.label.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
794
748
|
let identifier = snapshot.identifier.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
795
749
|
let valueText = snapshotValueText(snapshot)
|
|
796
|
-
let laterNodes = laterSnapshots(
|
|
797
|
-
for: snapshot,
|
|
798
|
-
in: context.flatSnapshots,
|
|
799
|
-
ranges: context.snapshotRanges
|
|
800
|
-
)
|
|
801
750
|
return SnapshotEvaluation(
|
|
802
751
|
label: label,
|
|
803
752
|
identifier: identifier,
|
|
804
753
|
valueText: valueText,
|
|
805
|
-
hittable: computedSnapshotHittable(snapshot, viewport: context.viewport, laterNodes: laterNodes),
|
|
806
754
|
focused: snapshotHasFocus(snapshot),
|
|
807
|
-
selected: snapshotIsSelected(snapshot)
|
|
808
|
-
visible: isVisibleInViewport(snapshot.frame, context.viewport)
|
|
755
|
+
selected: snapshotIsSelected(snapshot)
|
|
809
756
|
)
|
|
810
757
|
}
|
|
811
758
|
|
|
@@ -814,9 +761,10 @@ extension RunnerTests {
|
|
|
814
761
|
evaluation: SnapshotEvaluation,
|
|
815
762
|
depth: Int,
|
|
816
763
|
index: Int,
|
|
817
|
-
parentIndex: Int
|
|
818
|
-
|
|
819
|
-
|
|
764
|
+
parentIndex: Int?,
|
|
765
|
+
viewport: CGRect
|
|
766
|
+
) -> RawAXNode {
|
|
767
|
+
return RawAXNode(
|
|
820
768
|
index: index,
|
|
821
769
|
type: elementTypeName(snapshot.elementType),
|
|
822
770
|
label: evaluation.label.isEmpty ? nil : evaluation.label,
|
|
@@ -826,7 +774,11 @@ extension RunnerTests {
|
|
|
826
774
|
enabled: snapshot.isEnabled,
|
|
827
775
|
focused: evaluation.focused ? true : nil,
|
|
828
776
|
selected: evaluation.selected ? true : nil,
|
|
829
|
-
hittable:
|
|
777
|
+
hittable: parentIndex != nil && SnapshotGeometry.isGeometricallyActionable(
|
|
778
|
+
enabled: snapshot.isEnabled,
|
|
779
|
+
frame: snapshot.frame,
|
|
780
|
+
viewport: viewport
|
|
781
|
+
),
|
|
830
782
|
depth: depth,
|
|
831
783
|
parentIndex: parentIndex,
|
|
832
784
|
hiddenContentAbove: nil,
|
|
@@ -834,52 +786,6 @@ extension RunnerTests {
|
|
|
834
786
|
)
|
|
835
787
|
}
|
|
836
788
|
|
|
837
|
-
private func isOccludingType(_ type: XCUIElement.ElementType) -> Bool {
|
|
838
|
-
switch type {
|
|
839
|
-
case .application, .window:
|
|
840
|
-
return false
|
|
841
|
-
default:
|
|
842
|
-
return true
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
private func flattenedSnapshots(
|
|
847
|
-
_ root: XCUIElementSnapshot
|
|
848
|
-
) -> ([XCUIElementSnapshot], [ObjectIdentifier: (Int, Int)]) {
|
|
849
|
-
var ordered: [XCUIElementSnapshot] = []
|
|
850
|
-
var ranges: [ObjectIdentifier: (Int, Int)] = [:]
|
|
851
|
-
|
|
852
|
-
@discardableResult
|
|
853
|
-
func visit(_ snapshot: XCUIElementSnapshot) -> Int {
|
|
854
|
-
let start = ordered.count
|
|
855
|
-
ordered.append(snapshot)
|
|
856
|
-
var end = start
|
|
857
|
-
for child in snapshot.children {
|
|
858
|
-
end = max(end, visit(child))
|
|
859
|
-
}
|
|
860
|
-
ranges[ObjectIdentifier(snapshot)] = (start, end)
|
|
861
|
-
return end
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
_ = visit(root)
|
|
865
|
-
return (ordered, ranges)
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
private func laterSnapshots(
|
|
869
|
-
for snapshot: XCUIElementSnapshot,
|
|
870
|
-
in ordered: [XCUIElementSnapshot],
|
|
871
|
-
ranges: [ObjectIdentifier: (Int, Int)]
|
|
872
|
-
) -> ArraySlice<XCUIElementSnapshot> {
|
|
873
|
-
guard let (_, subtreeEnd) = ranges[ObjectIdentifier(snapshot)] else {
|
|
874
|
-
return ordered.suffix(from: ordered.count)
|
|
875
|
-
}
|
|
876
|
-
let nextIndex = subtreeEnd + 1
|
|
877
|
-
if nextIndex >= ordered.count {
|
|
878
|
-
return ordered.suffix(from: ordered.count)
|
|
879
|
-
}
|
|
880
|
-
return ordered.suffix(from: nextIndex)
|
|
881
|
-
}
|
|
882
|
-
|
|
883
789
|
private func snapshotValueText(_ snapshot: XCUIElementSnapshot) -> String? {
|
|
884
790
|
guard let value = snapshot.value else { return nil }
|
|
885
791
|
let text = String(describing: value).trimmingCharacters(in: .whitespacesAndNewlines)
|
|
@@ -920,121 +826,33 @@ extension RunnerTests {
|
|
|
920
826
|
return nil
|
|
921
827
|
}
|
|
922
828
|
|
|
923
|
-
func isVisibleInViewport(_ rect: CGRect, _ viewport: CGRect) -> Bool {
|
|
924
|
-
if rect.isNull || rect.isEmpty { return false }
|
|
925
|
-
return rect.intersects(viewport)
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
func isVisibleInRegularSnapshot(
|
|
929
|
-
_ rect: CGRect,
|
|
930
|
-
viewport: CGRect,
|
|
931
|
-
scrollContainerAnchor: (index: Int, rect: CGRect)?
|
|
932
|
-
) -> Bool {
|
|
933
|
-
if !isVisibleInViewport(rect, viewport) { return false }
|
|
934
|
-
guard let scrollContainerAnchor else { return true }
|
|
935
|
-
return isVisibleInViewport(rect, scrollContainerAnchor.rect)
|
|
936
|
-
}
|
|
937
|
-
|
|
938
829
|
private func appendCollapsedTabFallbackNodes(
|
|
939
|
-
to nodes: inout [
|
|
830
|
+
to nodes: inout [RawAXNode],
|
|
940
831
|
containerSnapshot: XCUIElementSnapshot,
|
|
941
832
|
resolveElements: () -> [XCUIElement],
|
|
942
833
|
depth: Int,
|
|
943
|
-
parentIndex: Int
|
|
834
|
+
parentIndex: Int,
|
|
835
|
+
viewport: CGRect
|
|
944
836
|
) {
|
|
945
837
|
let fallbackNodes = collapsedTabFallbackNodes(
|
|
946
838
|
for: containerSnapshot,
|
|
947
839
|
resolveElements: resolveElements,
|
|
948
840
|
startingIndex: nodes.count,
|
|
949
841
|
depth: depth,
|
|
950
|
-
parentIndex: parentIndex
|
|
842
|
+
parentIndex: parentIndex,
|
|
843
|
+
viewport: viewport
|
|
951
844
|
)
|
|
952
845
|
nodes.append(contentsOf: fallbackNodes)
|
|
953
846
|
}
|
|
954
847
|
|
|
955
|
-
private func scrollContainerAnchor(
|
|
956
|
-
for snapshot: XCUIElementSnapshot,
|
|
957
|
-
visible: Bool,
|
|
958
|
-
nodeIndex: Int?
|
|
959
|
-
) -> (index: Int, rect: CGRect)? {
|
|
960
|
-
return scrollContainerAnchor(
|
|
961
|
-
for: snapshot.elementType,
|
|
962
|
-
hasChildren: !snapshot.children.isEmpty,
|
|
963
|
-
visible: visible,
|
|
964
|
-
frame: snapshot.frame,
|
|
965
|
-
nodeIndex: nodeIndex
|
|
966
|
-
)
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
func scrollContainerAnchor(
|
|
970
|
-
for elementType: XCUIElement.ElementType,
|
|
971
|
-
hasChildren: Bool,
|
|
972
|
-
visible: Bool,
|
|
973
|
-
frame: CGRect,
|
|
974
|
-
nodeIndex: Int?
|
|
975
|
-
) -> (index: Int, rect: CGRect)? {
|
|
976
|
-
guard let nodeIndex else { return nil }
|
|
977
|
-
if !isScrollableContainer(
|
|
978
|
-
elementType: elementType,
|
|
979
|
-
hasChildren: hasChildren,
|
|
980
|
-
visible: visible
|
|
981
|
-
) { return nil }
|
|
982
|
-
return (nodeIndex, frame)
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
func rememberHiddenContentHint(
|
|
986
|
-
for frame: CGRect,
|
|
987
|
-
relativeTo scrollContainerAnchor: (index: Int, rect: CGRect),
|
|
988
|
-
hints: inout [Int: (above: Bool, below: Bool)]
|
|
989
|
-
) {
|
|
990
|
-
if frame.isNull || frame.isEmpty { return }
|
|
991
|
-
var hint = hints[scrollContainerAnchor.index] ?? (above: false, below: false)
|
|
992
|
-
if frame.maxY <= scrollContainerAnchor.rect.minY {
|
|
993
|
-
hint.above = true
|
|
994
|
-
} else if frame.minY >= scrollContainerAnchor.rect.maxY {
|
|
995
|
-
hint.below = true
|
|
996
|
-
} else {
|
|
997
|
-
return
|
|
998
|
-
}
|
|
999
|
-
hints[scrollContainerAnchor.index] = hint
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
func applyHiddenContentHints(
|
|
1003
|
-
_ hints: [Int: (above: Bool, below: Bool)],
|
|
1004
|
-
to nodes: [SnapshotNode]
|
|
1005
|
-
) -> [SnapshotNode] {
|
|
1006
|
-
if hints.isEmpty { return nodes }
|
|
1007
|
-
return nodes.map { node in
|
|
1008
|
-
guard let hint = hints[node.index] else { return node }
|
|
1009
|
-
let hiddenContentAbove: Bool? = (node.hiddenContentAbove == true || hint.above) ? true : nil
|
|
1010
|
-
let hiddenContentBelow: Bool? = (node.hiddenContentBelow == true || hint.below) ? true : nil
|
|
1011
|
-
return SnapshotNode(
|
|
1012
|
-
index: node.index,
|
|
1013
|
-
type: node.type,
|
|
1014
|
-
label: node.label,
|
|
1015
|
-
identifier: node.identifier,
|
|
1016
|
-
value: node.value,
|
|
1017
|
-
rect: node.rect,
|
|
1018
|
-
enabled: node.enabled,
|
|
1019
|
-
focused: node.focused,
|
|
1020
|
-
selected: node.selected,
|
|
1021
|
-
hittable: node.hittable,
|
|
1022
|
-
depth: node.depth,
|
|
1023
|
-
parentIndex: node.parentIndex,
|
|
1024
|
-
hiddenContentAbove: hiddenContentAbove,
|
|
1025
|
-
hiddenContentBelow: hiddenContentBelow,
|
|
1026
|
-
actions: node.actions
|
|
1027
|
-
)
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
848
|
private func collapsedTabFallbackNodes(
|
|
1032
849
|
for containerSnapshot: XCUIElementSnapshot,
|
|
1033
850
|
resolveElements: () -> [XCUIElement],
|
|
1034
851
|
startingIndex: Int,
|
|
1035
852
|
depth: Int,
|
|
1036
|
-
parentIndex: Int
|
|
1037
|
-
|
|
853
|
+
parentIndex: Int,
|
|
854
|
+
viewport: CGRect
|
|
855
|
+
) -> [RawAXNode] {
|
|
1038
856
|
if !containerSnapshot.children.isEmpty { return [] }
|
|
1039
857
|
guard shouldExpandCollapsedTabContainer(containerSnapshot) else { return [] }
|
|
1040
858
|
let containerFrame = containerSnapshot.frame
|
|
@@ -1047,7 +865,8 @@ extension RunnerTests {
|
|
|
1047
865
|
collapsedTabCandidateNode(
|
|
1048
866
|
element: element,
|
|
1049
867
|
containerSnapshot: containerSnapshot,
|
|
1050
|
-
containerFrame: containerFrame
|
|
868
|
+
containerFrame: containerFrame,
|
|
869
|
+
viewport: viewport
|
|
1051
870
|
)
|
|
1052
871
|
}
|
|
1053
872
|
.sorted { left, right in
|
|
@@ -1073,7 +892,7 @@ extension RunnerTests {
|
|
|
1073
892
|
if uniqueCandidates.count < 2 { return [] }
|
|
1074
893
|
|
|
1075
894
|
return uniqueCandidates.enumerated().map { offset, node in
|
|
1076
|
-
|
|
895
|
+
RawAXNode(
|
|
1077
896
|
index: startingIndex + offset,
|
|
1078
897
|
type: node.type,
|
|
1079
898
|
label: node.label,
|
|
@@ -1095,9 +914,10 @@ extension RunnerTests {
|
|
|
1095
914
|
private func collapsedTabCandidateNode(
|
|
1096
915
|
element: XCUIElement,
|
|
1097
916
|
containerSnapshot: XCUIElementSnapshot,
|
|
1098
|
-
containerFrame: CGRect
|
|
1099
|
-
|
|
1100
|
-
|
|
917
|
+
containerFrame: CGRect,
|
|
918
|
+
viewport: CGRect
|
|
919
|
+
) -> RawAXNode? {
|
|
920
|
+
var node: RawAXNode?
|
|
1101
921
|
let exceptionMessage = RunnerObjCExceptionCatcher.catchException({
|
|
1102
922
|
if !element.exists { return }
|
|
1103
923
|
let elementType = element.elementType
|
|
@@ -1125,7 +945,7 @@ extension RunnerTests {
|
|
|
1125
945
|
return
|
|
1126
946
|
}
|
|
1127
947
|
|
|
1128
|
-
node =
|
|
948
|
+
node = RawAXNode(
|
|
1129
949
|
index: 0,
|
|
1130
950
|
type: elementTypeName(elementType),
|
|
1131
951
|
label: label.isEmpty ? nil : label,
|
|
@@ -1135,7 +955,11 @@ extension RunnerTests {
|
|
|
1135
955
|
enabled: element.isEnabled,
|
|
1136
956
|
focused: elementHasFocus(element) ? true : nil,
|
|
1137
957
|
selected: element.isSelected ? true : nil,
|
|
1138
|
-
hittable:
|
|
958
|
+
hittable: SnapshotGeometry.isGeometricallyActionable(
|
|
959
|
+
enabled: element.isEnabled,
|
|
960
|
+
frame: frame,
|
|
961
|
+
viewport: viewport
|
|
962
|
+
),
|
|
1139
963
|
depth: 0,
|
|
1140
964
|
parentIndex: nil,
|
|
1141
965
|
hiddenContentAbove: nil,
|
|
@@ -1261,42 +1085,27 @@ extension RunnerTests {
|
|
|
1261
1085
|
element: XCUIElement,
|
|
1262
1086
|
index: Int,
|
|
1263
1087
|
parentIndex: Int?,
|
|
1264
|
-
viewport: CGRect
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
var node: SnapshotNode?
|
|
1088
|
+
viewport: CGRect
|
|
1089
|
+
) -> RawAXNode? {
|
|
1090
|
+
var node: RawAXNode?
|
|
1268
1091
|
let exceptionMessage = RunnerObjCExceptionCatcher.catchException({
|
|
1269
1092
|
if !element.exists { return }
|
|
1093
|
+
// Declared residue: a flat element query has no hierarchy for geometryless semantics to
|
|
1094
|
+
// attach to, so frameless elements are dropped at acquisition rather than presented.
|
|
1270
1095
|
let frame = element.frame
|
|
1271
1096
|
if frame.isNull || frame.isEmpty { return }
|
|
1272
|
-
let visible = isVisibleInViewport(frame, viewport)
|
|
1273
|
-
if options.interactiveOnly && !visible { return }
|
|
1274
|
-
#if os(macOS)
|
|
1275
|
-
if !visible { return }
|
|
1276
|
-
#endif
|
|
1277
1097
|
let label = element.label.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
1278
1098
|
let identifier = element.identifier.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
1279
1099
|
let valueText = snapshotValueText(element)
|
|
1280
1100
|
let elementType = element.elementType
|
|
1281
1101
|
let enabled = element.isEnabled
|
|
1282
|
-
let hittable =
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
identifier: identifier,
|
|
1287
|
-
valueText: valueText,
|
|
1288
|
-
visible: visible
|
|
1102
|
+
let hittable = SnapshotGeometry.isGeometricallyActionable(
|
|
1103
|
+
enabled: enabled,
|
|
1104
|
+
frame: frame,
|
|
1105
|
+
viewport: viewport
|
|
1289
1106
|
)
|
|
1290
|
-
if !flatSnapshotFilterDecision(
|
|
1291
|
-
filterNode,
|
|
1292
|
-
options: options,
|
|
1293
|
-
visibilityPolicy: .interactiveOnly,
|
|
1294
|
-
insideMatchedScope: false
|
|
1295
|
-
).include {
|
|
1296
|
-
return
|
|
1297
|
-
}
|
|
1298
1107
|
|
|
1299
|
-
node =
|
|
1108
|
+
node = RawAXNode(
|
|
1300
1109
|
index: index,
|
|
1301
1110
|
type: elementTypeName(elementType),
|
|
1302
1111
|
label: label.isEmpty ? nil : label,
|
|
@@ -1320,19 +1129,4 @@ extension RunnerTests {
|
|
|
1320
1129
|
return node
|
|
1321
1130
|
}
|
|
1322
1131
|
|
|
1323
|
-
private func isScrollableContainer(_ snapshot: XCUIElementSnapshot, visible: Bool) -> Bool {
|
|
1324
|
-
return isScrollableContainer(
|
|
1325
|
-
elementType: snapshot.elementType,
|
|
1326
|
-
hasChildren: !snapshot.children.isEmpty,
|
|
1327
|
-
visible: visible
|
|
1328
|
-
)
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
private func isScrollableContainer(
|
|
1332
|
-
elementType: XCUIElement.ElementType,
|
|
1333
|
-
hasChildren: Bool,
|
|
1334
|
-
visible: Bool
|
|
1335
|
-
) -> Bool {
|
|
1336
|
-
return visible && hasChildren && Self.scrollContainerTypes.contains(elementType)
|
|
1337
|
-
}
|
|
1338
1132
|
}
|