Files
callstack__agent-device/test/integration/interaction-contract/resolution-disclosure-mutation.contract.test.ts
Michał Pierzchała cd9a7ce41b test(android): add comprehensive emulator E2E coverage (#1482)
* test(android): add catalog emulator smoke coverage

* test(android): use stable snapshot diff mutation

* test(android): assert actual back destination

* test(android): separate keyboard and fill IMEs

* fix(ci): keep Android timing report in one shell

* refactor(test): simplify simulator e2e coverage

* test(android): assert stable diff landmarks

* fix(android): release snapshot helper gracefully

* fix(android): fully release snapshot helper runtime

* test(android): report coverage classifications

* fix(android): stabilize accessibility root capture

* fix(android): bound UiAutomation connection

* ci: upload worktree daemon diagnostics

* fix(android): cancel stalled wait captures

* fix(android): bound helper fallback lifecycle

* fix(android): harden emulator e2e lifecycle

* fix: align e2e changes with kernel package

* test(android): prove alert helper reuse directly

* fix(android): cancel stalled settle captures

* fix(android): separate helper retirement budgets
2026-07-30 15:10:21 +02:00

68 lines
2.7 KiB
TypeScript

import assert from 'node:assert/strict';
import { test } from 'vitest';
import { ref, selector } from '../../../src/commands/interaction/runtime/selector-read-utils.ts';
import { drawerWithVisibleTwinSnapshot } from './fixtures.ts';
import { createContractDevice } from './runtime-harness.ts';
// ADR 0012 mutation contract, daemon half: diagnosticRef tokens are not refs.
// The MCP half (never ref-issued/pinned) lives in src/mcp/__tests__/command-tools.test.ts.
test('resolution mutation contract: a diagnosticRef is not a resolvable @ref target', async () => {
const device = createContractDevice(drawerWithVisibleTwinSnapshot(), {
tap: async () => ({ ok: true }),
});
const result = await device.interactions.click(selector('label=Profile'), {
session: 'default',
});
assert.equal(result.kind, 'selector');
const resolution = result.resolution;
assert.equal(resolution?.kind, 'disambiguated');
if (resolution?.kind !== 'disambiguated') return;
const alternativeDiagnosticRef = resolution.alternatives[0]?.diagnosticRef;
assert.ok(
alternativeDiagnosticRef,
'the disambiguated resolution must carry a losing alternative',
);
// Acting on it without a fresh snapshot gets the ordinary unknown-ref refusal.
await assert.rejects(
() => device.interactions.press(ref(`@${alternativeDiagnosticRef}`), { session: 'default' }),
(error: unknown) => {
assert.ok(error instanceof Error);
assert.equal((error as { code?: string }).code, 'COMMAND_FAILED');
assert.match(error.message, new RegExp(`Ref @${alternativeDiagnosticRef} not found`));
const details = (error as { details?: Record<string, unknown> }).details;
assert.match(String(details?.hint), /refs expire/i);
return true;
},
);
});
test('resolution mutation contract: the winner diagnosticRef is also not a resolvable @ref target', async () => {
const device = createContractDevice(drawerWithVisibleTwinSnapshot(), {
tap: async () => ({ ok: true }),
});
const result = await device.interactions.click(selector('label=Profile'), {
session: 'default',
});
assert.equal(result.kind, 'selector');
const resolution = result.resolution;
assert.equal(resolution?.kind, 'disambiguated');
if (resolution?.kind !== 'disambiguated') return;
const winnerDiagnosticRef = resolution.winnerDiagnostic.diagnosticRef;
// The winner's token is equally non-actionable.
await assert.rejects(
() => device.interactions.press(ref(`@${winnerDiagnosticRef}`), { session: 'default' }),
(error: unknown) => {
assert.ok(error instanceof Error);
assert.equal((error as { code?: string }).code, 'COMMAND_FAILED');
return true;
},
);
});