mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
59d28e8446
* refactor: add provider-first device lab tests * refactor: tighten device lab provider seams * test: cover provider lab contracts * docs: record device lab harness direction * ci: run device lab integration tests * test: move device lab under integration * test: extract device lab helpers * refactor: centralize apps filter defaults * test: drop lab-covered unit tests * test: fold platform happy paths into device lab * test: reuse device lab helpers * test: move device lab to in-process harness * test: replace session handler cases with device lab * test: harden device lab scenario contracts * docs: define unit test retention policy * test: expand provider device lab coverage * test: harden provider device lab coverage * test: cover manifest install and runner session contracts * chore: remove unused provider cleanup code * test: split android find device lab scenario * test: track provider lab architecture progress * test: clarify provider lab roadmap progress * test: advance provider lab session coverage * test: move menubar click routing to device lab * test: move menubar snapshots to device lab * refactor: centralize screenshot flag plumbing * refactor: colocate screenshot flag metadata * test: cover all public commands in device lab * test: move macos wait success to device lab * test: drop redundant perf and diff units * test: move push payload paths to device lab * test: move network parsing to device lab * test: move log cleanup to device lab * test: move log restart and boot to device lab * test: move ios physical boot to device lab * test: cover perf startup in device lab * test: extract android and ios device lab worlds * test: trim device lab world surface * test: split snapshot capture unit coverage * test: deepen device lab coverage and trim handler units * test: clean up device lab migration scaffolding * test: report device lab public command coverage * refactor: make Apple provider seams semantic * refactor: tighten device inventory and Linux provider seams * refactor: tighten request provider scoping * refactor: add semantic macos host provider * test: broaden device lab find coverage * test: cover workflow flags in device lab * refactor: promote linux input provider seam * test: clarify device lab flag coverage * test: classify snapshot force-full progress * test: enforce device lab progress in ci * test: stabilize device lab ci * test: move packaged metro smoke to integration * test: drop stale provider seam coverage * test: harden provider scope regression coverage * refactor: remove stale platform barrels * refactor: keep linux clipboard and screenshots semantic * refactor: move macos host tools behind provider * fix: honor remote artifact output paths * test: deepen runtime coverage for daemon and runner paths * test: share loopback test helpers * refactor: make daemon runtime importable * fix: honor replay target metadata * chore: tighten final device lab quality gates * test: share device lab setup helpers * test: remove generic apple lab fallback * test: deduplicate device lab helpers * chore: tighten fallow duplication signal * refactor: share apple diagnostic helpers * fix: detect active android ime during fill verification * test: consolidate provider-backed integration suite * ci: fix fallow and iOS smoke setup * chore: consolidate cleanup after ci fixes * test: split vitest unit and integration projects * docs: mention MCP discovery metadata * docs: add agent skills context pointers * fix: close provider recording coverage gaps * fix: restore mcp compatibility smoke * test: cover provider edge regressions * test: consolidate loopback helpers * docs: remove stale provider routing reference * fix: harden final provider review issues * chore: defer mcp cleanup from provider refactor
133 lines
3.9 KiB
TypeScript
133 lines
3.9 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { isDeepStrictEqual } from 'node:util';
|
|
import type { Platform } from '../../../src/utils/device.ts';
|
|
|
|
export interface ProviderScenarioProviderScope {
|
|
deviceId?: string;
|
|
platform?: Platform;
|
|
}
|
|
|
|
export interface ProviderScenarioProviderEntry<
|
|
TResult = unknown,
|
|
> extends ProviderScenarioProviderScope {
|
|
command: string;
|
|
request?: unknown;
|
|
result?: TResult;
|
|
error?: Error | string;
|
|
}
|
|
|
|
export interface ProviderScenarioProviderCall<
|
|
TResult = unknown,
|
|
> extends ProviderScenarioProviderScope {
|
|
command: string;
|
|
request?: unknown;
|
|
result?: TResult;
|
|
}
|
|
|
|
export interface ProviderScenarioTranscript {
|
|
readonly calls: readonly ProviderScenarioProviderCall[];
|
|
readonly remaining: readonly ProviderScenarioProviderEntry[];
|
|
next<TResult = unknown>(
|
|
command: string,
|
|
request?: unknown,
|
|
scope?: ProviderScenarioProviderScope,
|
|
): TResult;
|
|
assertComplete(): void;
|
|
}
|
|
|
|
export function createProviderTranscript(
|
|
entries: readonly ProviderScenarioProviderEntry[],
|
|
options: { ordered?: boolean } = {},
|
|
): ProviderScenarioTranscript {
|
|
const pending = [...entries];
|
|
const calls: ProviderScenarioProviderCall[] = [];
|
|
|
|
return {
|
|
get calls() {
|
|
return [...calls];
|
|
},
|
|
get remaining() {
|
|
return [...pending];
|
|
},
|
|
next<TResult = unknown>(
|
|
command: string,
|
|
request?: unknown,
|
|
scope: ProviderScenarioProviderScope = {},
|
|
): TResult {
|
|
const entryIndex = options.ordered
|
|
? 0
|
|
: pending.findIndex((candidate) =>
|
|
providerEntryMatches(candidate, command, request, scope),
|
|
);
|
|
const entry = entryIndex >= 0 ? pending.splice(entryIndex, 1)[0] : undefined;
|
|
assert.ok(entry, `Unexpected provider call: ${formatCall(command, scope)}`);
|
|
assert.equal(command, entry.command, 'Provider command mismatch');
|
|
assertScope(scope, entry);
|
|
if (Object.hasOwn(entry, 'request')) {
|
|
assert.deepEqual(request, entry.request, 'Provider request mismatch');
|
|
}
|
|
|
|
const call = {
|
|
command,
|
|
request,
|
|
deviceId: scope.deviceId,
|
|
platform: scope.platform,
|
|
result: entry.result as TResult,
|
|
};
|
|
calls.push(call);
|
|
|
|
if (entry.error) {
|
|
throw entry.error instanceof Error ? entry.error : new Error(entry.error);
|
|
}
|
|
|
|
return entry.result as TResult;
|
|
},
|
|
assertComplete() {
|
|
assert.equal(
|
|
pending.length,
|
|
0,
|
|
`Unconsumed provider transcript entries: ${pending.map(formatEntry).join(', ')}`,
|
|
);
|
|
},
|
|
};
|
|
}
|
|
|
|
export function createOrderedProviderTranscript(
|
|
entries: readonly ProviderScenarioProviderEntry[],
|
|
): ProviderScenarioTranscript {
|
|
return createProviderTranscript(entries, { ordered: true });
|
|
}
|
|
|
|
function providerEntryMatches(
|
|
entry: ProviderScenarioProviderEntry,
|
|
command: string,
|
|
request: unknown,
|
|
scope: ProviderScenarioProviderScope,
|
|
): boolean {
|
|
if (entry.command !== command) return false;
|
|
if (entry.deviceId && entry.deviceId !== scope.deviceId) return false;
|
|
if (entry.platform && entry.platform !== scope.platform) return false;
|
|
return !Object.hasOwn(entry, 'request') || isDeepStrictEqual(request, entry.request);
|
|
}
|
|
|
|
function assertScope(
|
|
actual: ProviderScenarioProviderScope,
|
|
expected: ProviderScenarioProviderEntry,
|
|
): void {
|
|
if (expected.deviceId) {
|
|
assert.equal(actual.deviceId, expected.deviceId, 'Provider device id mismatch');
|
|
}
|
|
if (expected.platform) {
|
|
assert.equal(actual.platform, expected.platform, 'Provider platform mismatch');
|
|
}
|
|
}
|
|
|
|
function formatCall(command: string, scope: ProviderScenarioProviderScope): string {
|
|
return formatEntry({ command, ...scope });
|
|
}
|
|
|
|
function formatEntry(entry: { command: string; deviceId?: string; platform?: Platform }): string {
|
|
const scope = [entry.platform, entry.deviceId].filter(Boolean).join(':');
|
|
return scope ? `${scope}.${entry.command}` : entry.command;
|
|
}
|