agent-device 0.21.12 → 0.21.14

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