From 6f5c2eacce006d24d3bd0d3a9a8e43b189f860e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 15 Oct 2026 13:28:40 +0200 Subject: [PATCH 1/5] refactor(tests): name platform-apple tests for the module they test Pure moves and renames. Content changes are import specifiers, the Swift sources path in interactions.test.ts, and references to the old paths in the macOS workflow, docs, comments and the command-coverage and fault-matrix evidence. Co-Authored-By: Claude Opus 5.5 --- .device-evidence/CHECKLIST-runner-failures.md | 2 +- .github/workflows/macos.yml | 2 +- .../adr/0005-ios-runner-interaction-lifecycle.md | 2 +- docs/ios-runner-protocol-optimizations.md | 4 ++-- packages/contracts/src/interactor-types.ts | 2 +- ....ts => interactor-screenshot-backend.test.ts} | 0 ...st.ts => interactor-watchos-sentinel.test.ts} | 0 ...ch.test.ts => runner-client-mac-arch.test.ts} | 0 .../src/foldable/fold-helper-cache.test.ts | 2 +- .../{core/__tests__ => }/interactions.test.ts | 16 ++++++++-------- ...test.ts => runner-client-busy-resend.test.ts} | 0 ...st.ts => runner-client-command-retry.test.ts} | 0 ....ts => runner-client-recovery-wiring.test.ts} | 0 ...ner-command-traits-readiness-routing.test.ts} | 0 ....test.ts => runner-contract-response.test.ts} | 0 ...unner-lifecycle-request-cancellation.test.ts} | 0 ...=> runner-session-close-finalization.test.ts} | 0 .../__tests__/runner-session-lifecycle.test.ts | 2 +- ... runner-startup-transport-early-exit.test.ts} | 0 .../runner-swift-settlement-fixtures.ts | 2 +- ... => runner-xctestrun-start-admission.test.ts} | 0 ...er-xctestrun-startup-failure-reasons.test.ts} | 0 .../platform-apple/src/runner/runner-exchange.ts | 2 +- ...time.test.ts => cache-native-runtime.test.ts} | 0 packages/test-kit/src/boundary-fault-matrix.ts | 4 +++- .../integration/command-coverage/declarations.ts | 2 +- 26 files changed, 22 insertions(+), 20 deletions(-) rename packages/platform-apple/src/__tests__/{screenshot-backend.test.ts => interactor-screenshot-backend.test.ts} (100%) rename packages/platform-apple/src/__tests__/{watchos-sentinel.test.ts => interactor-watchos-sentinel.test.ts} (100%) rename packages/platform-apple/src/core/__tests__/{runner-mac-arch.test.ts => runner-client-mac-arch.test.ts} (100%) rename packages/platform-apple/src/{core/__tests__ => }/interactions.test.ts (97%) rename packages/platform-apple/src/runner/__tests__/{runner-command-busy-resend.test.ts => runner-client-busy-resend.test.ts} (100%) rename packages/platform-apple/src/runner/__tests__/{runner-command-retry.test.ts => runner-client-command-retry.test.ts} (100%) rename packages/platform-apple/src/runner/__tests__/{runner-recovery-wiring.test.ts => runner-client-recovery-wiring.test.ts} (100%) rename packages/platform-apple/src/runner/__tests__/{runner-readiness-routing.test.ts => runner-command-traits-readiness-routing.test.ts} (100%) rename packages/platform-apple/src/runner/__tests__/{runner-response.test.ts => runner-contract-response.test.ts} (100%) rename packages/platform-apple/src/runner/__tests__/{runner-request-cancellation.test.ts => runner-lifecycle-request-cancellation.test.ts} (100%) rename packages/platform-apple/src/runner/__tests__/{runner-close-finalization.test.ts => runner-session-close-finalization.test.ts} (100%) rename packages/platform-apple/src/runner/__tests__/{runner-early-exit-diagnosis.test.ts => runner-startup-transport-early-exit.test.ts} (100%) rename packages/platform-apple/src/runner/__tests__/{runner-start-admission.test.ts => runner-xctestrun-start-admission.test.ts} (100%) rename packages/platform-apple/src/runner/__tests__/{runner-startup-failure-reasons.test.ts => runner-xctestrun-startup-failure-reasons.test.ts} (100%) rename packages/platform-apple/src/snapshot-source/{native-runtime.test.ts => cache-native-runtime.test.ts} (100%) diff --git a/.device-evidence/CHECKLIST-runner-failures.md b/.device-evidence/CHECKLIST-runner-failures.md index cc94966a48..b69fcb13c4 100644 --- a/.device-evidence/CHECKLIST-runner-failures.md +++ b/.device-evidence/CHECKLIST-runner-failures.md @@ -268,7 +268,7 @@ diagnostic a row keys on. `runner-startup-failure-fixtures.ts` so the rows read as host-gated, not unexamined. #2680 §4 needs a build that fails for an unrelated reason while naming no signing fact; the -classifier's behaviour there is pinned by `runner-startup-failure-reasons.test.ts` and needs no +classifier's behaviour there is pinned by `runner-xctestrun-startup-failure-reasons.test.ts` and needs no device claim to hold. ### #2683 — what the phone actually reported diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 38d3deff41..9c3f5de1d9 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -168,7 +168,7 @@ jobs: run: | pnpm build pnpm exec vitest run \ - packages/platform-apple/src/snapshot-source/native-runtime.test.ts \ + packages/platform-apple/src/snapshot-source/cache-native-runtime.test.ts \ packages/platform-apple/src/foldable/fold-helper-cache.test.ts \ packages/platform-apple/src/foldable/simulator-hid-native.test.ts \ packages/capture-kit/src/recording/__tests__/recording-scripts.test.ts diff --git a/docs/adr/0005-ios-runner-interaction-lifecycle.md b/docs/adr/0005-ios-runner-interaction-lifecycle.md index 01d91a6836..68f6e0ec2e 100644 --- a/docs/adr/0005-ios-runner-interaction-lifecycle.md +++ b/docs/adr/0005-ios-runner-interaction-lifecycle.md @@ -69,7 +69,7 @@ What a `RUNNER_BUSY` refusal then costs the caller turns on the daemon's own per trait, not on any runner-side classification of the command: `RUNNER_COMMAND_TRAITS` in `packages/platform-apple/src/runner/runner-command-traits.ts`, read through `isReadOnlyRunnerCommand` where `runAppleRunnerCommand` decides whether to wrap the send in a resend -loop. The asymmetry is shipped, and asserted in `runner-command-busy-resend.test.ts`: a read-only +loop. The asymmetry is shipped, and asserted in `runner-client-busy-resend.test.ts`: a read-only command treats the refusal as *not yet*, waiting the drain out on the busy-specific budget sized to outlast it and resending until the runner answers or the window ends; a mutating command treats the same refusal as *not mine to send again* — one attempt, and the refusal reaches the caller unwrapped diff --git a/docs/ios-runner-protocol-optimizations.md b/docs/ios-runner-protocol-optimizations.md index ab7aa62964..d09c3ecc31 100644 --- a/docs/ios-runner-protocol-optimizations.md +++ b/docs/ios-runner-protocol-optimizations.md @@ -28,8 +28,8 @@ Acceptance criteria: iOS simulator validation: -- Unit: `pnpm exec vitest run packages/platform-apple/src/runner/__tests__/runner-command-retry.test.ts`. -- Unit bundle: `pnpm exec vitest run packages/platform-apple/src/runner/__tests__/runner-client.test.ts packages/platform-apple/src/runner/__tests__/runner-session.test.ts packages/platform-apple/src/runner/__tests__/runner-command-retry.test.ts packages/platform-apple/src/runner/__tests__/runner-provider.test.ts`. +- Unit: `pnpm exec vitest run packages/platform-apple/src/runner/__tests__/runner-client-command-retry.test.ts`. +- Unit bundle: `pnpm exec vitest run packages/platform-apple/src/runner/__tests__/runner-client.test.ts packages/platform-apple/src/runner/__tests__/runner-session.test.ts packages/platform-apple/src/runner/__tests__/runner-client-command-retry.test.ts packages/platform-apple/src/runner/__tests__/runner-provider.test.ts`. - Build: `pnpm build:xcuitest`. - Manual sim smoke after build: - `pnpm build` diff --git a/packages/contracts/src/interactor-types.ts b/packages/contracts/src/interactor-types.ts index c927c27c74..270864341b 100644 --- a/packages/contracts/src/interactor-types.ts +++ b/packages/contracts/src/interactor-types.ts @@ -107,7 +107,7 @@ export const MAESTRO_NON_HITTABLE_FALLBACK_MESSAGE = 'tapped via non-hittable co * its only producer and the boundary that narrows it * (readTypeTextBackendResult, packages/platform-apple/src/interactions.ts) drops a * route it cannot name — so a Swift-side addition would silently vanish. The - * route-parity test in packages/platform-apple/src/core/__tests__/interactions.test.ts + * route-parity test in packages/platform-apple/src/interactions.test.ts * reads the Swift sources and fails instead. */ export const TEXT_ENTRY_ROUTES = [ diff --git a/packages/platform-apple/src/__tests__/screenshot-backend.test.ts b/packages/platform-apple/src/__tests__/interactor-screenshot-backend.test.ts similarity index 100% rename from packages/platform-apple/src/__tests__/screenshot-backend.test.ts rename to packages/platform-apple/src/__tests__/interactor-screenshot-backend.test.ts diff --git a/packages/platform-apple/src/__tests__/watchos-sentinel.test.ts b/packages/platform-apple/src/__tests__/interactor-watchos-sentinel.test.ts similarity index 100% rename from packages/platform-apple/src/__tests__/watchos-sentinel.test.ts rename to packages/platform-apple/src/__tests__/interactor-watchos-sentinel.test.ts diff --git a/packages/platform-apple/src/core/__tests__/runner-mac-arch.test.ts b/packages/platform-apple/src/core/__tests__/runner-client-mac-arch.test.ts similarity index 100% rename from packages/platform-apple/src/core/__tests__/runner-mac-arch.test.ts rename to packages/platform-apple/src/core/__tests__/runner-client-mac-arch.test.ts diff --git a/packages/platform-apple/src/foldable/fold-helper-cache.test.ts b/packages/platform-apple/src/foldable/fold-helper-cache.test.ts index 6dae3e3dd9..06bfe6b57a 100644 --- a/packages/platform-apple/src/foldable/fold-helper-cache.test.ts +++ b/packages/platform-apple/src/foldable/fold-helper-cache.test.ts @@ -221,7 +221,7 @@ test('an abort while a second caller waits on the fold-helper lock reports a can // // The compile runs in beforeAll, not in the test body: it is a real clang invocation (see the // unit slow-test budget in docs/agents/testing.md), and the snapshot-bridge sibling gate in -// native-runtime.test.ts keeps its compile out of test-case wall time the same way. +// cache-native-runtime.test.ts keeps its compile out of test-case wall time the same way. describe.skipIf(process.platform !== 'darwin')('fold helper warning gate', () => { let compiled: { exitCode: number; stderr: string }; beforeAll(async () => { diff --git a/packages/platform-apple/src/core/__tests__/interactions.test.ts b/packages/platform-apple/src/interactions.test.ts similarity index 97% rename from packages/platform-apple/src/core/__tests__/interactions.test.ts rename to packages/platform-apple/src/interactions.test.ts index 2834331578..6fbba09587 100644 --- a/packages/platform-apple/src/core/__tests__/interactions.test.ts +++ b/packages/platform-apple/src/interactions.test.ts @@ -6,15 +6,15 @@ import { iosRunnerOverrides, performGestureApple, resolveAppleBackRunnerCommand, -} from '../../interactions.ts'; -import { runAppleRunnerCommand } from '../runner-client.ts'; +} from './interactions.ts'; +import { runAppleRunnerCommand } from './core/runner-client.ts'; import { AppError } from '@agent-device/kernel/errors'; import { gestureRefusalMessage, PHYSICAL_IOS_MULTI_TOUCH_UNSUPPORTED_HINT, } from '@agent-device/contracts/gesture-admission'; import type { GesturePlan } from '@agent-device/contracts/gesture-plan-types'; -import type { RunnerCommand } from '../../runner/index.ts'; +import type { RunnerCommand } from './runner/index.ts'; import { TEXT_ENTRY_ROUTES } from '@agent-device/contracts/interactor-types'; import { IOS_TEST_DEVICE, @@ -22,15 +22,15 @@ import { MACOS_TEST_DEVICE, TVOS_TEST_SIMULATOR, VISIONOS_TEST_SIMULATOR, -} from './apple-core-stub-helpers.ts'; +} from './core/__tests__/apple-core-stub-helpers.ts'; -vi.mock('../runner-client.ts', async (importOriginal) => { - const actual = await importOriginal(); +vi.mock('./core/runner-client.ts', async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, runAppleRunnerCommand: vi.fn(actual.runAppleRunnerCommand) }; }); const runnerActual = - await vi.importActual('../runner-client.ts'); + await vi.importActual('./core/runner-client.ts'); const mockRunAppleRunnerCommand = vi.mocked(runAppleRunnerCommand); @@ -630,7 +630,7 @@ test('iosRunnerOverrides reports no route when the runner names one it does not test('TEXT_ENTRY_ROUTES names every route the Swift runner assigns', () => { const runnerTestsDir = path.resolve( import.meta.dirname, - '../../../../../apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests', + '../../../apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests', ); const swiftRoutes = new Set(); for (const entry of fs.readdirSync(runnerTestsDir)) { diff --git a/packages/platform-apple/src/runner/__tests__/runner-command-busy-resend.test.ts b/packages/platform-apple/src/runner/__tests__/runner-client-busy-resend.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-command-busy-resend.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-client-busy-resend.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-command-retry.test.ts b/packages/platform-apple/src/runner/__tests__/runner-client-command-retry.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-command-retry.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-client-command-retry.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-recovery-wiring.test.ts b/packages/platform-apple/src/runner/__tests__/runner-client-recovery-wiring.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-recovery-wiring.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-client-recovery-wiring.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-readiness-routing.test.ts b/packages/platform-apple/src/runner/__tests__/runner-command-traits-readiness-routing.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-readiness-routing.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-command-traits-readiness-routing.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-response.test.ts b/packages/platform-apple/src/runner/__tests__/runner-contract-response.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-response.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-contract-response.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-request-cancellation.test.ts b/packages/platform-apple/src/runner/__tests__/runner-lifecycle-request-cancellation.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-request-cancellation.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-lifecycle-request-cancellation.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-close-finalization.test.ts b/packages/platform-apple/src/runner/__tests__/runner-session-close-finalization.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-close-finalization.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-session-close-finalization.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-session-lifecycle.test.ts b/packages/platform-apple/src/runner/__tests__/runner-session-lifecycle.test.ts index 289f00c271..ab7a494392 100644 --- a/packages/platform-apple/src/runner/__tests__/runner-session-lifecycle.test.ts +++ b/packages/platform-apple/src/runner/__tests__/runner-session-lifecycle.test.ts @@ -532,7 +532,7 @@ test('a command abandoned by a cancelled transport keeps the runner occupied', a // An answered queued exchange forgives the abandoned charge: the serial queue makes it evidence that // the abandoned handling ahead of it finished, and whatever is still draining is stamped onto that // very reply. An answer the runner serves inline forgives nothing (#2965); that case is pinned in - // `runner-recovery-wiring.test.ts`, where the probe reaches a real session. + // `runner-client-recovery-wiring.test.ts`, where the probe reaches a real session. await serveOneCommand(device, session); assert.equal(session.commandCharges.hasOutstandingCharges, false); assert.equal(await detachIosRunnerSessionsForShutdown(), 1); diff --git a/packages/platform-apple/src/runner/__tests__/runner-early-exit-diagnosis.test.ts b/packages/platform-apple/src/runner/__tests__/runner-startup-transport-early-exit.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-early-exit-diagnosis.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-startup-transport-early-exit.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-swift-settlement-fixtures.ts b/packages/platform-apple/src/runner/__tests__/runner-swift-settlement-fixtures.ts index 41e75cb065..b1172a489a 100644 --- a/packages/platform-apple/src/runner/__tests__/runner-swift-settlement-fixtures.ts +++ b/packages/platform-apple/src/runner/__tests__/runner-swift-settlement-fixtures.ts @@ -37,7 +37,7 @@ const CASE_HEADER = /\bcase\s+(\.\w+(?:\s*,\s*\.\w+)*):/g; * command queue, which is exactly why a reply to one is no evidence about queued work. * * A reader here can only fail in two directions, and each is caught: a misread that names an extra - * command fails `runner-readiness-routing.test.ts`, which compares this list against the daemon's + * command fails `runner-command-traits-readiness-routing.test.ts`, which compares this list against the daemon's * `readinessProbe` trait in both directions, and a misread that loses an arm makes a real probe look * queued, which that same tie reports. What is left to guard locally is the case both miss — a `case` * these two patterns do not recognize, which would otherwise drop an arm and leave a set that still diff --git a/packages/platform-apple/src/runner/__tests__/runner-start-admission.test.ts b/packages/platform-apple/src/runner/__tests__/runner-xctestrun-start-admission.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-start-admission.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-xctestrun-start-admission.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-startup-failure-reasons.test.ts b/packages/platform-apple/src/runner/__tests__/runner-xctestrun-startup-failure-reasons.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-startup-failure-reasons.test.ts rename to packages/platform-apple/src/runner/__tests__/runner-xctestrun-startup-failure-reasons.test.ts diff --git a/packages/platform-apple/src/runner/runner-exchange.ts b/packages/platform-apple/src/runner/runner-exchange.ts index a7254a70e1..6608635e19 100644 --- a/packages/platform-apple/src/runner/runner-exchange.ts +++ b/packages/platform-apple/src/runner/runner-exchange.ts @@ -296,7 +296,7 @@ async function sendRunnerCommandAfterPreflight(params: { // nobody is waiting for any more. A readiness probe is charged no more than the preflight's own // probe is: the runner serves it inline, so its reply says nothing about the queued work a charge // stands for, and charging it would let one probe settle another command's debt (#2965). The trait - // that names the probe is pinned to the runner's inline routing by `runner-readiness-routing.test.ts`. + // that names the probe is pinned to the runner's inline routing by `runner-command-traits-readiness-routing.test.ts`. const charged = !isRunnerReadinessProbeCommand(runnerCommand); if (charged) session.commandCharges.charge(runnerCommand.commandId); try { diff --git a/packages/platform-apple/src/snapshot-source/native-runtime.test.ts b/packages/platform-apple/src/snapshot-source/cache-native-runtime.test.ts similarity index 100% rename from packages/platform-apple/src/snapshot-source/native-runtime.test.ts rename to packages/platform-apple/src/snapshot-source/cache-native-runtime.test.ts diff --git a/packages/test-kit/src/boundary-fault-matrix.ts b/packages/test-kit/src/boundary-fault-matrix.ts index 8ce74ef7dd..7b55945c2a 100644 --- a/packages/test-kit/src/boundary-fault-matrix.ts +++ b/packages/test-kit/src/boundary-fault-matrix.ts @@ -144,7 +144,9 @@ export const BOUNDARY_FAULT_MATRIX = { 'lost-response-after-mutation': { mutation: { kind: 'covered', - evidence: ['packages/platform-apple/src/runner/__tests__/runner-recovery-wiring.test.ts'], + evidence: [ + 'packages/platform-apple/src/runner/__tests__/runner-client-recovery-wiring.test.ts', + ], invariants: ['no-mutation-replay', 'typed-error-identity'], }, read: { diff --git a/test/integration/command-coverage/declarations.ts b/test/integration/command-coverage/declarations.ts index 1b02aff3bb..28ac621948 100644 --- a/test/integration/command-coverage/declarations.ts +++ b/test/integration/command-coverage/declarations.ts @@ -1052,7 +1052,7 @@ const COMMAND_COVERAGE_DECLARATIONS = { 'fixture gesture counters prove pan/fling/pinch/rotate', ), macos: macos.contract( - 'packages/platform-apple/src/core/__tests__/interactions.test.ts', + 'packages/platform-apple/src/interactions.test.ts', 'performGestureApple composes macOS one-contact plans with the drag executor', 'macOS gesture dispatch preserves the one-contact drag plan', ), From 167bb60c08a15ada5c776c8d94fac6c8609a707e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 15 Oct 2026 13:28:40 +0200 Subject: [PATCH 2/5] refactor(platform-apple): split the runner response test by the module it covers decodeRunnerResponseBody and its siblings live in runner-contract.ts; parseRunnerResponse lives in runner-exchange.ts. Each half now sits beside its own module's name. Co-Authored-By: Claude Opus 5.5 --- .../runner-contract-response.test.ts | 61 ----------------- .../runner-exchange-response.test.ts | 67 +++++++++++++++++++ 2 files changed, 67 insertions(+), 61 deletions(-) create mode 100644 packages/platform-apple/src/runner/__tests__/runner-exchange-response.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-contract-response.test.ts b/packages/platform-apple/src/runner/__tests__/runner-contract-response.test.ts index d626730d90..977340b269 100644 --- a/packages/platform-apple/src/runner/__tests__/runner-contract-response.test.ts +++ b/packages/platform-apple/src/runner/__tests__/runner-contract-response.test.ts @@ -7,14 +7,9 @@ import { isRunnerResponseOk, readRunnerResponseData, } from '../runner-contract.ts'; -import { isStructuredRunnerFailure } from '../runner-error-classification.ts'; -import { parseRunnerResponse } from '../runner-exchange.ts'; -import type { RunnerSessionState } from '../runner-session-types.ts'; // A body cut off mid-write: the shape a runner that died while answering leaves behind. const TRUNCATED_BODY = '{"ok":true,"data":{"nodes":[{"label":"Sign In"'; -// `ok` is a Swift `Bool`, so this is what a private truthiness rule used to accept as an answer. -const STRINGLY_TYPED_BODY = '{"ok":"true","data":{"tapped":true}}'; describe('decodeRunnerResponseBody', () => { test('decodes the runner envelope', () => { @@ -111,59 +106,3 @@ describe('buildRunnerResponseError', () => { assert.equal(error.details?.hint, undefined); }); }); - -describe('parseRunnerResponse', () => { - test('refuses a body whose ok is not the boolean true', async () => { - const session: { state: RunnerSessionState } = { state: 'starting' }; - - await assert.rejects( - () => parseRunnerResponse(new Response(STRINGLY_TYPED_BODY), session), - (error: unknown) => { - assert.ok(error instanceof AppError); - assert.equal(error.code, 'COMMAND_FAILED'); - assert.deepEqual(error.details?.runner, { ok: 'true', data: { tapped: true } }); - return true; - }, - ); - - assert.equal(session.state, 'starting'); - }); - - test('refuses a body that is not readable JSON', async () => { - const session: { state: RunnerSessionState } = { state: 'starting' }; - - await assert.rejects( - () => parseRunnerResponse(new Response(TRUNCATED_BODY), session), - (error: unknown) => { - assert.ok(error instanceof AppError); - assert.equal(error.code, 'COMMAND_FAILED'); - assert.equal(error.details?.text, TRUNCATED_BODY); - // Transport-shaped: no `runner` detail, so the session keeps its recency bets (#2552). - assert.equal(error.details?.runner, undefined); - return true; - }, - ); - - assert.equal(session.state, 'starting'); - }); - - test('reads a JSON scalar body as transport-shaped, not as an empty reply', async () => { - // The chain #2965 turns on: an error carrying a `runner` detail counts as an answer and discharges - // the command's charge. A bare `null` is not an envelope the runner's encoder emits, so decoding it - // into `{}` and erroring from that would have answered a command the runner may still be running. - const session: { state: RunnerSessionState } = { state: 'starting' }; - - await assert.rejects( - () => parseRunnerResponse(new Response('null'), session), - (error: unknown) => { - assert.ok(error instanceof AppError); - assert.equal(error.message, 'Invalid runner response'); - assert.equal(error.details?.runner, undefined); - assert.equal(isStructuredRunnerFailure(error), false); - return true; - }, - ); - - assert.equal(session.state, 'starting'); - }); -}); diff --git a/packages/platform-apple/src/runner/__tests__/runner-exchange-response.test.ts b/packages/platform-apple/src/runner/__tests__/runner-exchange-response.test.ts new file mode 100644 index 0000000000..21d6d1211b --- /dev/null +++ b/packages/platform-apple/src/runner/__tests__/runner-exchange-response.test.ts @@ -0,0 +1,67 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'vitest'; +import { AppError } from '@agent-device/kernel/errors'; +import { isStructuredRunnerFailure } from '../runner-error-classification.ts'; +import { parseRunnerResponse } from '../runner-exchange.ts'; +import type { RunnerSessionState } from '../runner-session-types.ts'; + +// A body cut off mid-write: the shape a runner that died while answering leaves behind. +const TRUNCATED_BODY = '{"ok":true,"data":{"nodes":[{"label":"Sign In"'; +// `ok` is a Swift `Bool`, so this is what a private truthiness rule used to accept as an answer. +const STRINGLY_TYPED_BODY = '{"ok":"true","data":{"tapped":true}}'; + +describe('parseRunnerResponse', () => { + test('refuses a body whose ok is not the boolean true', async () => { + const session: { state: RunnerSessionState } = { state: 'starting' }; + + await assert.rejects( + () => parseRunnerResponse(new Response(STRINGLY_TYPED_BODY), session), + (error: unknown) => { + assert.ok(error instanceof AppError); + assert.equal(error.code, 'COMMAND_FAILED'); + assert.deepEqual(error.details?.runner, { ok: 'true', data: { tapped: true } }); + return true; + }, + ); + + assert.equal(session.state, 'starting'); + }); + + test('refuses a body that is not readable JSON', async () => { + const session: { state: RunnerSessionState } = { state: 'starting' }; + + await assert.rejects( + () => parseRunnerResponse(new Response(TRUNCATED_BODY), session), + (error: unknown) => { + assert.ok(error instanceof AppError); + assert.equal(error.code, 'COMMAND_FAILED'); + assert.equal(error.details?.text, TRUNCATED_BODY); + // Transport-shaped: no `runner` detail, so the session keeps its recency bets (#2552). + assert.equal(error.details?.runner, undefined); + return true; + }, + ); + + assert.equal(session.state, 'starting'); + }); + + test('reads a JSON scalar body as transport-shaped, not as an empty reply', async () => { + // The chain #2965 turns on: an error carrying a `runner` detail counts as an answer and discharges + // the command's charge. A bare `null` is not an envelope the runner's encoder emits, so decoding it + // into `{}` and erroring from that would have answered a command the runner may still be running. + const session: { state: RunnerSessionState } = { state: 'starting' }; + + await assert.rejects( + () => parseRunnerResponse(new Response('null'), session), + (error: unknown) => { + assert.ok(error instanceof AppError); + assert.equal(error.message, 'Invalid runner response'); + assert.equal(error.details?.runner, undefined); + assert.equal(isStructuredRunnerFailure(error), false); + return true; + }, + ); + + assert.equal(session.state, 'starting'); + }); +}); From 214001be988edd8effaebebac40f68d710fad999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 15 Oct 2026 14:16:52 +0200 Subject: [PATCH 3/5] refactor(platform-apple): name the runner dispatch-disclosure driver for the runner entry The driver exercises the session executor, command recovery and press-series sequencing against the contracts table, so it takes the runner entry's name. The owning-path string in the contracts fixture follows. Co-Authored-By: Claude Opus 5.5 --- packages/contracts/src/dispatch-disclosure.fixtures.ts | 2 +- ...tch-disclosure.test.ts => index-dispatch-disclosure.test.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/platform-apple/src/runner/__tests__/{runner-dispatch-disclosure.test.ts => index-dispatch-disclosure.test.ts} (100%) diff --git a/packages/contracts/src/dispatch-disclosure.fixtures.ts b/packages/contracts/src/dispatch-disclosure.fixtures.ts index bcf8d9ab65..0d318fe712 100644 --- a/packages/contracts/src/dispatch-disclosure.fixtures.ts +++ b/packages/contracts/src/dispatch-disclosure.fixtures.ts @@ -42,7 +42,7 @@ export const DISPATCH_DISCLOSURE_DRIVER_OWNERS: Readonly> 'daemon.route.': 'src/__tests__/daemon-composition/request-dispatch-disclosure.test.ts', 'post-action-guard.': 'src/__tests__/daemon-composition/interaction/interaction-dispatch-disclosure.test.ts', - 'ios-runner.': 'packages/platform-apple/src/runner/__tests__/runner-dispatch-disclosure.test.ts', + 'ios-runner.': 'packages/platform-apple/src/runner/__tests__/index-dispatch-disclosure.test.ts', 'ios-runner.pre-send.': 'packages/platform-apple/src/runner/__tests__/runner-lifecycle-dispatch-disclosure.test.ts', 'ios-runner.transport.': diff --git a/packages/platform-apple/src/runner/__tests__/runner-dispatch-disclosure.test.ts b/packages/platform-apple/src/runner/__tests__/index-dispatch-disclosure.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-dispatch-disclosure.test.ts rename to packages/platform-apple/src/runner/__tests__/index-dispatch-disclosure.test.ts From acf662f0c109bd800fac018e350b72143df4cb38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 15 Oct 2026 14:35:13 +0200 Subject: [PATCH 4/5] refactor(platform-apple): name the runner-request conformance drivers for the package and runner entries Pure renames. The runner-requests.json producer paths and the comment that names the runner-side driver follow in the next commit. Co-Authored-By: Claude Opus 5.5 --- .../{runner-requests.test.ts => index-runner-requests.test.ts} | 0 .../{runner-requests.test.ts => index-runner-requests.test.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename packages/platform-apple/src/__tests__/{runner-requests.test.ts => index-runner-requests.test.ts} (100%) rename packages/platform-apple/src/runner/__tests__/{runner-requests.test.ts => index-runner-requests.test.ts} (100%) diff --git a/packages/platform-apple/src/__tests__/runner-requests.test.ts b/packages/platform-apple/src/__tests__/index-runner-requests.test.ts similarity index 100% rename from packages/platform-apple/src/__tests__/runner-requests.test.ts rename to packages/platform-apple/src/__tests__/index-runner-requests.test.ts diff --git a/packages/platform-apple/src/runner/__tests__/runner-requests.test.ts b/packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts similarity index 100% rename from packages/platform-apple/src/runner/__tests__/runner-requests.test.ts rename to packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts From 9eb850d75e9f2e2580e844fd2d263ad6b72047b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 15 Oct 2026 14:35:20 +0200 Subject: [PATCH 5/5] refactor(platform-apple): point runner-requests.json at the renamed conformance drivers The producer paths move with the two drivers; the endsWith contract in the runner-side driver already accepts index-runner-requests.test.ts. Co-Authored-By: Claude Opus 5.5 --- contracts/fixtures/runner-requests.json | 128 +++++++++--------- .../__tests__/index-runner-requests.test.ts | 2 +- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/contracts/fixtures/runner-requests.json b/contracts/fixtures/runner-requests.json index c5586e3c26..2345dbb582 100644 --- a/contracts/fixtures/runner-requests.json +++ b/contracts/fixtures/runner-requests.json @@ -1,73 +1,73 @@ [ - {"name": "ios-device.physical-device-control.activate", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "activate", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-device.physical-device-control.terminate", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "terminate", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-device.physical-device-screenshot.coredevice-file", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "screenshot", "appBundleId": "com.example.app", "fullscreen": true, "inlineScreenshot": false, "commandId": ""}}, - {"name": "ios-device.physical-device-screenshot.xctest-inline", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "screenshot", "appBundleId": "com.example.app", "inlineScreenshot": true, "commandId": ""}}, + {"name": "ios-device.physical-device-control.activate", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "activate", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-device.physical-device-control.terminate", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "terminate", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-device.physical-device-screenshot.coredevice-file", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "screenshot", "appBundleId": "com.example.app", "fullscreen": true, "inlineScreenshot": false, "commandId": ""}}, + {"name": "ios-device.physical-device-screenshot.xctest-inline", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "screenshot", "appBundleId": "com.example.app", "inlineScreenshot": true, "commandId": ""}}, {"name": "ios-device.recording-start-abort.stop", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "recordStop", "appBundleId": "com.example.app"}}, {"name": "ios-device.recording-start.fps", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "recordStart", "outPath": "agent-device-recording-1700000000000.mp4", "fps": 30, "appBundleId": "com.example.app"}}, {"name": "ios-device.recording-stop.no-app", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "recordStop"}}, {"name": "ios-device.recording-stop.session", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "recordStop", "appBundleId": "com.example.app"}}, - {"name": "ios-simulator.alert.accept", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "alert", "action": "accept", "appBundleId": "com.example.app", "timeoutMs": 10000, "commandId": ""}}, - {"name": "ios-simulator.alert.dismiss", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "alert", "action": "dismiss", "appBundleId": "com.example.app", "timeoutMs": 10000, "commandId": ""}}, - {"name": "ios-simulator.alert.get", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "alert", "action": "get", "appBundleId": "com.example.app", "timeoutMs": 10000, "commandId": ""}}, - {"name": "ios-simulator.interactions-double-tap.single", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "doubleTap", "x": 10, "y": 20}], "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-fill.non-hittable-fallback", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "type", "x": 10, "y": 20, "text": "hello", "textEntryMode": "replace", "allowNonHittableCoordinateFallback": true, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-fill.replace", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "type", "x": 10, "y": 20, "text": "hello", "delayMs": 10, "textEntryMode": "replace", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-focus.synthesized", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-gesture-viewport.read", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "gestureViewport", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-gesture.single", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "gesture", "gesturePlan": {"topology": "single", "intent": "pan", "executionProfile": "timed-pan", "durationMs": 120, "viewport": {"x": 0, "y": 0, "width": 390, "height": 844}, "pointers": [{"pointerId": 0, "samples": [{"offsetMs": 0, "point": {"x": 100, "y": 400}}, {"offsetMs": 120, "point": {"x": 100, "y": 200}}]}]}, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-gesture.two", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "gesture", "gesturePlan": {"topology": "two", "intent": "pinch", "durationMs": 250, "viewport": {"x": 0, "y": 0, "width": 390, "height": 844}, "pointers": [{"pointerId": 0, "samples": [{"offsetMs": 0, "point": {"x": 150, "y": 422}}, {"offsetMs": 250, "point": {"x": 100, "y": 422}}]}, {"pointerId": 1, "samples": [{"offsetMs": 0, "point": {"x": 240, "y": 422}}, {"offsetMs": 250, "point": {"x": 290, "y": 422}}]}]}, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-long-press.duration", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "longPress", "x": 10, "y": 20, "durationMs": 600, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-press-series.double-tap", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "doubleTap", "x": 10, "y": 20, "pauseMs": 50}, {"kind": "doubleTap", "x": 10, "y": 20}], "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-press-series.long-press", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "longPress", "x": 10, "y": 20, "durationMs": 600, "pauseMs": 50}, {"kind": "longPress", "x": 10, "y": 20, "durationMs": 600}], "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-press-series.tap", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "tap", "x": 10, "y": 20, "synthesized": true, "pauseMs": 50}, {"kind": "tap", "x": 10, "y": 20, "synthesized": true}], "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-scroll.amount", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "scroll", "direction": "down", "amount": 0.65, "durationMs": 400, "scrollReleaseBehavior": "controlled", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-scroll.inertial", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "scroll", "direction": "left", "amount": 0.5, "durationMs": 400, "scrollReleaseBehavior": "inertial", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-scroll.pixels", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "scroll", "direction": "up", "pixels": 200, "durationMs": 300, "scrollReleaseBehavior": "controlled", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-single-press-double-tap.single", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "doubleTap", "x": 10, "y": 20}], "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-single-press-long-press.hold", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "longPress", "x": 10, "y": 20, "durationMs": 600, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-single-press-tap.synthesized", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-tap-element-selector.expected-point", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "selectorKey": "label", "selectorValue": "Go", "allowNonHittableCoordinateFallback": true, "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-tap.synthesized", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-type.append", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "type", "text": "hello", "delayMs": 10, "textEntryMode": "append", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactions-type.newline", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "type", "text": "\n", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-action-button.press", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "actionButton", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-app-state.read", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "appState", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-app-switcher.open", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "appSwitcher", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-back.in-app", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "backInApp", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-back.system", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "backSystem", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-find-text.text", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "findText", "text": "Ready", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-home.press", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "home", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-keyboard-dismiss.dismiss", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "keyboardDismiss", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-keyboard-enter.return", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "keyboardReturn", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-read-text.point", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "readText", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-set-orientation.rotate", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "rotate", "orientation": "landscape-left", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.interactor-snapshot.every-option", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "snapshot", "appBundleId": "com.example.app", "interactiveOnly": true, "preferredBackend": "tree", "customActions": true, "depth": 3, "scope": "Go", "raw": true, "commandId": ""}}, - {"name": "ios-simulator.interactor-snapshot.observe-only", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "snapshot", "appBundleId": "com.example.app", "observeOnly": true, "commandId": ""}}, - {"name": "ios-simulator.interactor-write-clipboard.text", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "pasteboardWrite", "text": "one-time code 246810", "commandId": ""}}, + {"name": "ios-simulator.alert.accept", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "alert", "action": "accept", "appBundleId": "com.example.app", "timeoutMs": 10000, "commandId": ""}}, + {"name": "ios-simulator.alert.dismiss", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "alert", "action": "dismiss", "appBundleId": "com.example.app", "timeoutMs": 10000, "commandId": ""}}, + {"name": "ios-simulator.alert.get", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "alert", "action": "get", "appBundleId": "com.example.app", "timeoutMs": 10000, "commandId": ""}}, + {"name": "ios-simulator.interactions-double-tap.single", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "doubleTap", "x": 10, "y": 20}], "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-fill.non-hittable-fallback", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "type", "x": 10, "y": 20, "text": "hello", "textEntryMode": "replace", "allowNonHittableCoordinateFallback": true, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-fill.replace", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "type", "x": 10, "y": 20, "text": "hello", "delayMs": 10, "textEntryMode": "replace", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-focus.synthesized", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-gesture-viewport.read", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "gestureViewport", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-gesture.single", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "gesture", "gesturePlan": {"topology": "single", "intent": "pan", "executionProfile": "timed-pan", "durationMs": 120, "viewport": {"x": 0, "y": 0, "width": 390, "height": 844}, "pointers": [{"pointerId": 0, "samples": [{"offsetMs": 0, "point": {"x": 100, "y": 400}}, {"offsetMs": 120, "point": {"x": 100, "y": 200}}]}]}, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-gesture.two", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "gesture", "gesturePlan": {"topology": "two", "intent": "pinch", "durationMs": 250, "viewport": {"x": 0, "y": 0, "width": 390, "height": 844}, "pointers": [{"pointerId": 0, "samples": [{"offsetMs": 0, "point": {"x": 150, "y": 422}}, {"offsetMs": 250, "point": {"x": 100, "y": 422}}]}, {"pointerId": 1, "samples": [{"offsetMs": 0, "point": {"x": 240, "y": 422}}, {"offsetMs": 250, "point": {"x": 290, "y": 422}}]}]}, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-long-press.duration", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "longPress", "x": 10, "y": 20, "durationMs": 600, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-press-series.double-tap", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "doubleTap", "x": 10, "y": 20, "pauseMs": 50}, {"kind": "doubleTap", "x": 10, "y": 20}], "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-press-series.long-press", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "longPress", "x": 10, "y": 20, "durationMs": 600, "pauseMs": 50}, {"kind": "longPress", "x": 10, "y": 20, "durationMs": 600}], "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-press-series.tap", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "tap", "x": 10, "y": 20, "synthesized": true, "pauseMs": 50}, {"kind": "tap", "x": 10, "y": 20, "synthesized": true}], "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-scroll.amount", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "scroll", "direction": "down", "amount": 0.65, "durationMs": 400, "scrollReleaseBehavior": "controlled", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-scroll.inertial", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "scroll", "direction": "left", "amount": 0.5, "durationMs": 400, "scrollReleaseBehavior": "inertial", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-scroll.pixels", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "scroll", "direction": "up", "pixels": 200, "durationMs": 300, "scrollReleaseBehavior": "controlled", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-single-press-double-tap.single", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "sequence", "steps": [{"kind": "doubleTap", "x": 10, "y": 20}], "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-single-press-long-press.hold", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "longPress", "x": 10, "y": 20, "durationMs": 600, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-single-press-tap.synthesized", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-tap-element-selector.expected-point", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "selectorKey": "label", "selectorValue": "Go", "allowNonHittableCoordinateFallback": true, "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-tap.synthesized", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "synthesized": true, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-type.append", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "type", "text": "hello", "delayMs": 10, "textEntryMode": "append", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactions-type.newline", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "type", "text": "\n", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-action-button.press", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "actionButton", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-app-state.read", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "appState", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-app-switcher.open", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "appSwitcher", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-back.in-app", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "backInApp", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-back.system", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "backSystem", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-find-text.text", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "findText", "text": "Ready", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-home.press", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "home", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-keyboard-dismiss.dismiss", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "keyboardDismiss", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-keyboard-enter.return", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "keyboardReturn", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-read-text.point", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "readText", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-set-orientation.rotate", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "rotate", "orientation": "landscape-left", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.interactor-snapshot.every-option", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "snapshot", "appBundleId": "com.example.app", "interactiveOnly": true, "preferredBackend": "tree", "customActions": true, "depth": 3, "scope": "Go", "raw": true, "commandId": ""}}, + {"name": "ios-simulator.interactor-snapshot.observe-only", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "snapshot", "appBundleId": "com.example.app", "observeOnly": true, "commandId": ""}}, + {"name": "ios-simulator.interactor-write-clipboard.text", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "pasteboardWrite", "text": "one-time code 246810", "commandId": ""}}, {"name": "ios-simulator.recording-clock-anchor.snapshot", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "snapshot", "appBundleId": "com.example.app", "interactiveOnly": true, "depth": 1}}, {"name": "ios-simulator.recording-start.default", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "recordStart", "outPath": "capture.mp4", "appBundleId": "com.example.app"}}, - {"name": "ios-simulator.runner-adoption.uptime", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, - {"name": "ios-simulator.runner-client-prepare.uptime", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, - {"name": "ios-simulator.runner-client-target-reset.relaunch", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "targetReset", "commandId": ""}}, - {"name": "ios-simulator.runner-command-recovery.status", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "status", "statusCommandId": ""}}, - {"name": "ios-simulator.runner-disposal.shutdown", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "shutdown", "commandId": ""}}, - {"name": "ios-simulator.runner-lifecycle-prepare.uptime", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, - {"name": "ios-simulator.runner-selector-query.label", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "querySelector", "selectorKey": "label", "selectorValue": "Go", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "ios-simulator.runner-session-readiness.uptime", "producer": "packages/platform-apple/src/runner/__tests__/runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, - {"name": "macos.desktop-scroll.amount", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "desktopScroll", "direction": "down", "amount": 0.5, "durationMs": 300, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.desktop-scroll.pixels", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "desktopScroll", "direction": "up", "pixels": 200, "durationMs": 300, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.interactions-drag.single", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "drag", "x": 100, "y": 400, "x2": 100, "y2": 200, "durationMs": 120, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.interactions-focus.coordinate", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.interactions-mouse-click.middle", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "mouseClick", "x": 10, "y": 20, "button": "middle", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.interactions-mouse-click.secondary", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "mouseClick", "x": 10, "y": 20, "button": "secondary", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.interactions-single-press-tap.coordinate", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "macos.interactions-tap.coordinate", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.runner-adoption.uptime", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, + {"name": "ios-simulator.runner-client-prepare.uptime", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, + {"name": "ios-simulator.runner-client-target-reset.relaunch", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "targetReset", "commandId": ""}}, + {"name": "ios-simulator.runner-command-recovery.status", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "status", "statusCommandId": ""}}, + {"name": "ios-simulator.runner-disposal.shutdown", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "shutdown", "commandId": ""}}, + {"name": "ios-simulator.runner-lifecycle-prepare.uptime", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, + {"name": "ios-simulator.runner-selector-query.label", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "querySelector", "selectorKey": "label", "selectorValue": "Go", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "ios-simulator.runner-session-readiness.uptime", "producer": "packages/platform-apple/src/runner/__tests__/index-runner-requests.test.ts", "request": {"command": "uptime", "commandId": ""}}, + {"name": "macos.desktop-scroll.amount", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "desktopScroll", "direction": "down", "amount": 0.5, "durationMs": 300, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.desktop-scroll.pixels", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "desktopScroll", "direction": "up", "pixels": 200, "durationMs": 300, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.interactions-drag.single", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "drag", "x": 100, "y": 400, "x2": 100, "y2": 200, "durationMs": 120, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.interactions-focus.coordinate", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.interactions-mouse-click.middle", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "mouseClick", "x": 10, "y": 20, "button": "middle", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.interactions-mouse-click.secondary", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "mouseClick", "x": 10, "y": 20, "button": "secondary", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.interactions-single-press-tap.coordinate", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "macos.interactions-tap.coordinate", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "tap", "x": 10, "y": 20, "appBundleId": "com.example.app", "commandId": ""}}, {"name": "macos.recording-start.output-path", "producer": "src/__tests__/screen-recording-runner-requests.test.ts", "request": {"command": "recordStart", "outPath": "/tmp/capture.mp4", "appBundleId": "com.example.app"}}, - {"name": "macos.screenshot-runner.fullscreen", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "screenshot", "appBundleId": "com.example.app", "fullscreen": true, "inlineScreenshot": false, "commandId": ""}}, - {"name": "tvos.interactions-scroll.remote-press", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "down", "durationMs": 300, "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "tvos.interactions-swipe.single", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "swipe", "direction": "up", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "tvos.interactor-back.remote-press", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "menu", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "tvos.interactor-home.remote-press", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "home", "appBundleId": "com.example.app", "commandId": ""}}, - {"name": "tvos.interactor-tv-remote.hold", "producer": "packages/platform-apple/src/__tests__/runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "select", "durationMs": 500, "appBundleId": "com.example.app", "commandId": ""}} + {"name": "macos.screenshot-runner.fullscreen", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "screenshot", "appBundleId": "com.example.app", "fullscreen": true, "inlineScreenshot": false, "commandId": ""}}, + {"name": "tvos.interactions-scroll.remote-press", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "down", "durationMs": 300, "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "tvos.interactions-swipe.single", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "swipe", "direction": "up", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "tvos.interactor-back.remote-press", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "menu", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "tvos.interactor-home.remote-press", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "home", "appBundleId": "com.example.app", "commandId": ""}}, + {"name": "tvos.interactor-tv-remote.hold", "producer": "packages/platform-apple/src/__tests__/index-runner-requests.test.ts", "request": {"command": "remotePress", "remoteButton": "select", "durationMs": 500, "appBundleId": "com.example.app", "commandId": ""}} ] diff --git a/packages/platform-apple/src/__tests__/index-runner-requests.test.ts b/packages/platform-apple/src/__tests__/index-runner-requests.test.ts index c90ce9f2ce..ebd939a40a 100644 --- a/packages/platform-apple/src/__tests__/index-runner-requests.test.ts +++ b/packages/platform-apple/src/__tests__/index-runner-requests.test.ts @@ -26,7 +26,7 @@ import { mkdtempForTest } from './tmp-dir.ts'; // Every Apple runner request site outside `runner/`, driven through its production entry point and // pinned to contracts/fixtures/runner-requests.json. The drives never write a request themselves; -// runner/__tests__/runner-requests.test.ts reads this source to keep it that way. +// runner/__tests__/index-runner-requests.test.ts reads this source to keep it that way. const APP = 'com.example.app'; const XCTEST_DEVICE: DeviceInfo = { ...IOS_DEVICE, iosPhysicalDeviceBackend: 'xctest' };