diff --git a/src/daemon/handlers/interaction-touch-response.ts b/src/daemon/handlers/interaction-touch-response.ts index 4bf01317f..305069e33 100644 --- a/src/daemon/handlers/interaction-touch-response.ts +++ b/src/daemon/handlers/interaction-touch-response.ts @@ -179,23 +179,25 @@ function sanitizeWireBackendData( return Object.keys(sanitized).length > 0 ? sanitized : undefined; } +const OMITTED_WIRE_BACKEND_FIELDS = new Set([ + 'gestureStartUptimeMs', + 'gestureEndUptimeMs', + 'currentUptimeMs', + 'sequenceResults', +]); + +const DEFAULT_WIRE_BACKEND_FIELD_VALUES = new Map([ + ['count', 1], + ['intervalMs', 0], + ['holdMs', 0], + ['jitterPx', 0], + ['doubleTap', false], +]); + function shouldKeepWireBackendField(key: string, value: unknown): boolean { - switch (key) { - case 'gestureStartUptimeMs': - case 'gestureEndUptimeMs': - case 'sequenceResults': - return false; - case 'count': - return value !== 1; - case 'intervalMs': - case 'holdMs': - case 'jitterPx': - return value !== 0; - case 'doubleTap': - return value !== false; - default: - return true; - } + if (OMITTED_WIRE_BACKEND_FIELDS.has(key)) return false; + if (!DEFAULT_WIRE_BACKEND_FIELD_VALUES.has(key)) return true; + return value !== DEFAULT_WIRE_BACKEND_FIELD_VALUES.get(key); } function buildTouchMessage( diff --git a/test/integration/interaction-contract/interaction-response-shape.contract.test.ts b/test/integration/interaction-contract/interaction-response-shape.contract.test.ts index 328e2b7a0..be40cf663 100644 --- a/test/integration/interaction-contract/interaction-response-shape.contract.test.ts +++ b/test/integration/interaction-contract/interaction-response-shape.contract.test.ts @@ -40,9 +40,20 @@ const SELECTOR_KEYS = [ const POINT_KEYS = ['message', 'targetKind', 'x', 'y'] as const; +const NOISY_DEFAULT_TAP_RESULT = { + count: 1, + currentUptimeMs: 1_418_719_052.9, + doubleTap: false, + gestureEndUptimeMs: 1_418_719_052.338875, + gestureStartUptimeMs: 1_418_718_741.4275, + holdMs: 0, + intervalMs: 0, + jitterPx: 0, +}; + test('interaction response shape: press @ref uses the canonical ref envelope', async () => { await withIosContractDaemon( - [runnerSnapshotEntry(RUNNER_CONTINUE_NODES), runnerTapEntry({})], + [runnerSnapshotEntry(RUNNER_CONTINUE_NODES), runnerTapEntry(NOISY_DEFAULT_TAP_RESULT)], async (daemon, transcript) => { assertRpcOk(await daemon.callCommand('snapshot', [], { snapshotInteractiveOnly: true })); @@ -117,17 +128,20 @@ test('interaction response shape: press selector uses the canonical selector env }); test('interaction response shape: fill selector uses the canonical selector envelope', async () => { - await withIosContractDaemon([runnerTypeEntry({ x: 200, y: 322 })], async (daemon, transcript) => { - const data = assertRpcOk(await daemon.callCommand('fill', ['label=Continue', 'Hello'])); - assertRunnerRequest(transcript, 'ios.runner.type', selectorTypeRequest('Hello')); + await withIosContractDaemon( + [runnerTypeEntry({ ...NOISY_DEFAULT_TAP_RESULT, x: 200, y: 322 })], + async (daemon, transcript) => { + const data = assertRpcOk(await daemon.callCommand('fill', ['label=Continue', 'Hello'])); + assertRunnerRequest(transcript, 'ios.runner.type', selectorTypeRequest('Hello')); - assertCanonicalDirectSelector(data, { - message: 'Filled 5 chars', - x: 200, - y: 322, - extra: { delayMs: 0, text: 'Hello' }, - }); - }); + assertCanonicalDirectSelector(data, { + message: 'Filled 5 chars', + x: 200, + y: 322, + extra: { delayMs: 0, text: 'Hello' }, + }); + }, + ); }); test('interaction response shape: longpress selector uses the canonical selector envelope', async () => { @@ -317,6 +331,7 @@ function assertExactKeys(data: WireData, expectedKeys: readonly string[]): void function assertNoWireNoise(data: WireData): void { for (const key of [ 'count', + 'currentUptimeMs', 'doubleTap', 'gestureEndUptimeMs', 'gestureStartUptimeMs',