@ait-co/devtools 0.1.126 → 0.1.128
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.
- package/dist/debug-server-1dhDA3aw.js.map +1 -1
- package/dist/debug-server-Dctc9GAh.js.map +1 -1
- package/dist/mcp/cli.js +107 -19
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/panel/index.js +1 -1
- package/dist/{pool-B9wSRPOU.d.ts → pool-DBLKNeRC.d.ts} +2 -2
- package/dist/{pool-B9wSRPOU.d.ts.map → pool-DBLKNeRC.d.ts.map} +1 -1
- package/dist/{relay-worker-7biDlEjo.d.ts → relay-worker-TReZtzGl.d.ts} +10 -2
- package/dist/relay-worker-TReZtzGl.d.ts.map +1 -0
- package/dist/test-runner/bin.js +105 -17
- package/dist/test-runner/bin.js.map +1 -1
- package/dist/test-runner/config.d.ts +1 -1
- package/dist/test-runner/pool.d.ts +1 -1
- package/dist/test-runner/relay-worker.d.ts +2 -2
- package/dist/test-runner/relay-worker.js +55 -9
- package/dist/test-runner/relay-worker.js.map +1 -1
- package/dist/test-runner/report.d.ts +1 -1
- package/dist/test-runner/rpc.js +12 -3
- package/dist/test-runner/rpc.js.map +1 -1
- package/package.json +1 -1
- package/dist/relay-worker-7biDlEjo.d.ts.map +0 -1
|
@@ -3,6 +3,14 @@ import { parseCaptureLines } from "./capture.js";
|
|
|
3
3
|
import { injectAndRunBundle } from "./rpc.js";
|
|
4
4
|
//#region src/test-runner/relay-worker.ts
|
|
5
5
|
/**
|
|
6
|
+
* Sentinel string embedded in the error message by `injectAndRunBundle` when
|
|
7
|
+
* the per-file evaluate race hits the timeout. Used by the retry guard so only
|
|
8
|
+
* genuine timeouts get a second attempt — not bundle errors or parse failures.
|
|
9
|
+
*
|
|
10
|
+
* Exported for unit tests that assert the retry path is taken.
|
|
11
|
+
*/
|
|
12
|
+
const EVALUATE_TIMEOUT_MARKER = "rpc: evaluate timed out after";
|
|
13
|
+
/**
|
|
6
14
|
* Runs all `files` sequentially over the given CDP `connection`.
|
|
7
15
|
*
|
|
8
16
|
* For each file:
|
|
@@ -45,15 +53,53 @@ async function runTestFilesOverRelay(connection, files, opts) {
|
|
|
45
53
|
let fileEntry;
|
|
46
54
|
try {
|
|
47
55
|
const { code } = await bundleTestFile(file, opts?.bundleOptions);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Runs one evaluate attempt and returns a FileResult, or `null` when the
|
|
58
|
+
* result is a genuine timeout and the caller should retry.
|
|
59
|
+
*
|
|
60
|
+
* We need to distinguish:
|
|
61
|
+
* - `rpcResult.ok = false` + timeout error → retry candidate (`return null`)
|
|
62
|
+
* - `rpcResult.ok = false` + other error → final error, no retry
|
|
63
|
+
* - `injectAndRunBundle` throws → CDP exceptionDetails (page
|
|
64
|
+
* engine threw); treated as a final (non-retryable) error.
|
|
65
|
+
*
|
|
66
|
+
* The Promise.race timeout in rpc.ts RETURNS `{ok:false, error: '…'}` (it
|
|
67
|
+
* does NOT throw/reject). Only genuine CDP `exceptionDetails` cause a throw.
|
|
68
|
+
* This distinction is what makes the EVALUATE_TIMEOUT_MARKER gate below
|
|
69
|
+
* reachable — the timeout result surfaces as `rpcResult.ok=false` with the
|
|
70
|
+
* marker string, not as a caught exception.
|
|
71
|
+
*/
|
|
72
|
+
const attempt = async () => {
|
|
73
|
+
let rpcResult;
|
|
74
|
+
try {
|
|
75
|
+
rpcResult = await injectAndRunBundle(connection, code, opts?.timeoutMs);
|
|
76
|
+
} catch (e) {
|
|
77
|
+
return {
|
|
78
|
+
file,
|
|
79
|
+
result: { error: e instanceof Error ? e.message : String(e) }
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (rpcResult.ok) return {
|
|
83
|
+
file,
|
|
84
|
+
result: rpcResult.report
|
|
85
|
+
};
|
|
86
|
+
if (rpcResult.error.includes("rpc: evaluate timed out after")) return null;
|
|
87
|
+
return {
|
|
88
|
+
file,
|
|
89
|
+
result: { error: rpcResult.error }
|
|
90
|
+
};
|
|
56
91
|
};
|
|
92
|
+
const firstResult = await attempt();
|
|
93
|
+
if (firstResult !== null) fileEntry = firstResult;
|
|
94
|
+
else {
|
|
95
|
+
process.stderr.write(`relay-worker: evaluate timed out for ${file} — retrying once\n`);
|
|
96
|
+
const retryResult = await attempt();
|
|
97
|
+
if (retryResult !== null) fileEntry = retryResult;
|
|
98
|
+
else fileEntry = {
|
|
99
|
+
file,
|
|
100
|
+
result: { error: `${EVALUATE_TIMEOUT_MARKER} ${opts?.timeoutMs ?? 3e4}ms (after retry)` }
|
|
101
|
+
};
|
|
102
|
+
}
|
|
57
103
|
} catch (e) {
|
|
58
104
|
fileEntry = {
|
|
59
105
|
file,
|
|
@@ -137,6 +183,6 @@ function flattenResults(report) {
|
|
|
137
183
|
return out;
|
|
138
184
|
}
|
|
139
185
|
//#endregion
|
|
140
|
-
export { flattenResults, runTestFilesOverRelay };
|
|
186
|
+
export { EVALUATE_TIMEOUT_MARKER, flattenResults, runTestFilesOverRelay };
|
|
141
187
|
|
|
142
188
|
//# sourceMappingURL=relay-worker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay-worker.js","names":[],"sources":["../../src/test-runner/relay-worker.ts"],"sourcesContent":["/**\n * Orchestrator: runs a list of test files sequentially over a CDP relay.\n *\n * Each file goes through: bundle → inject → run → collect.\n * This is the transport layer: it does NOT integrate with Vitest's pool or the\n * MCP surface. The Vitest custom pool (`pool.ts`) and the `run_tests` MCP tool\n * are separate callers that build on this orchestrator.\n *\n * Single-attach constraint: only one page is active at a time. Files run\n * sequentially; parallel execution across targets is out of scope.\n *\n * The 30-second per-file timeout is inherited from `injectAndRunBundle`.\n * For suites that exceed it, split the file into smaller pieces.\n *\n * SECRET-HANDLING: file paths are surfaced in reports; relay URLs are not.\n */\n\nimport type { CdpConnection, ConsoleApiCalledEvent } from '../mcp/cdp-connection.js';\nimport { type BundleOptions, bundleTestFile } from './bundle.js';\nimport { type AitCaptureLine, parseCaptureLines } from './capture.js';\nimport { injectAndRunBundle } from './rpc.js';\nimport type { RunReport, TestResult } from './runtime.js';\n\n/** Per-file result in the aggregate `RunReport`. */\nexport interface FileResult {\n /** Absolute or relative path to the test file. */\n file: string;\n /** Full run report for this file, or an error if bundling/injection failed. */\n result: RunReport | { error: string };\n}\n\n/** Aggregate report returned by `runTestFilesOverRelay`. */\nexport interface RelayRunReport {\n /** ISO timestamp of when the run started. */\n startedAt: string;\n /** Total elapsed wall-clock milliseconds. */\n duration: number;\n /** Per-file results in execution order. */\n files: FileResult[];\n /** Flattened totals across all files. */\n totals: {\n passed: number;\n failed: number;\n skipped: number;\n total: number;\n };\n /**\n * `__AIT_CAPTURE__` lines harvested from the page console during the run\n * (additive field, devtools#696). Empty unless `collectCaptures` was set.\n * Each entry is opaque (`{ category, json }`) — devtools does not interpret\n * the record shape, only forwards it for downstream 2.x↔3.0 diffing.\n *\n * SECRET-HANDLING: only lines matching the `__AIT_CAPTURE__ ` allowlist\n * prefix reach here; relay/wss/scheme noise lines are dropped in\n * `parseCaptureLines`.\n */\n captures: AitCaptureLine[];\n}\n\n/** Options for `runTestFilesOverRelay`. */\nexport interface RelayRunOptions {\n /**\n * Options forwarded to `bundleTestFile` for each file.\n */\n bundleOptions?: BundleOptions;\n /**\n * Per-file evaluate timeout in milliseconds. Defaults to 30 000.\n * Increase for long-running suites or split the file.\n */\n timeoutMs?: number;\n /**\n * When `true`, registers a live `Runtime.consoleAPICalled` listener for the\n * duration of the run and harvests `__AIT_CAPTURE__` lines into\n * `RelayRunReport.captures`. Defaults to **false** so the build-only\n * eval/e2e path (and the Vitest pool) pay no listener/state overhead —\n * `captures` is then an empty array.\n *\n * The listener is registered just BEFORE the first file runs and removed in a\n * `finally` so it never accumulates across runs (no ring-buffer drain — the\n * default 500-entry buffer would silently drop lines via `shift`).\n */\n collectCaptures?: boolean;\n}\n\n/**\n * Runs all `files` sequentially over the given CDP `connection`.\n *\n * For each file:\n * 1. Bundle with esbuild (includes SDK shim + runtime).\n * 2. Inject into the attached page via `Runtime.evaluate`.\n * 3. Await the `RunReport` JSON response.\n * 4. Accumulate results.\n *\n * Returns a `RelayRunReport` with per-file results and flattened totals.\n *\n * This function does NOT open or manage the relay connection — the caller\n * is responsible for attaching and closing it.\n *\n * TODO (#645): implement the Vitest `PoolRunnerInitializer` interface here\n * so that `runTestFilesOverRelay` can be used as a Vitest pool entry.\n *\n * @param connection - Active CDP connection (relay or local kind).\n * @param files - Absolute paths to test files, run in order.\n * @param opts - Optional per-run overrides.\n */\nexport async function runTestFilesOverRelay(\n connection: CdpConnection,\n files: string[],\n opts?: RelayRunOptions,\n): Promise<RelayRunReport> {\n const wallStart = Date.now();\n const startedAt = new Date(wallStart).toISOString();\n const fileResults: FileResult[] = [];\n\n // Enable CDP domains ONCE up front. Without this the relay connection has not\n // opened its client websocket, so the very first `Runtime.evaluate` (in\n // `injectAndRunBundle`) explodes AND `Runtime.consoleAPICalled` never streams\n // — the console capture harvest would be structurally 0. `enableDomains()` is\n // idempotent (see chii-connection: early-returns when the ws is already OPEN,\n // and shares an in-flight promise), so calling it here is safe even when a\n // caller (the MCP `run_tests` path) already enabled it.\n //\n // Failure here (e.g. no target attached yet) must NOT throw the whole run: the\n // per-file inject below produces a structured error result instead. We warn on\n // stderr (secret-free) and continue. SECRET-HANDLING: the message names the\n // failure only — no relay/wss URL.\n let domainsEnabled = false;\n try {\n await connection.enableDomains();\n domainsEnabled = true;\n } catch (e) {\n process.stderr.write(\n `relay-worker: enableDomains() failed before run — console capture may be empty (${\n e instanceof Error ? e.message : String(e)\n })\\n`,\n );\n }\n\n // Live console capture (#696): when requested, accumulate every\n // `Runtime.consoleAPICalled` event into a local array via a LIVE listener\n // registered just before the run. We deliberately do NOT drain\n // `getBufferedEvents` after the fact — that ring buffer caps at 500 and\n // `shift()`s older entries, so a chatty run would silently lose capture lines.\n // The listener is removed in `finally` so it never bleeds into the next run.\n //\n // Gate the listener on `domainsEnabled`: if enableDomains() soft-failed, the\n // client ws never opened so `Runtime.consoleAPICalled` cannot stream —\n // registering would only add a dead listener that never fires. (The `finally`\n // unsubscribe is an undefined no-op in that case, so this stays safe.)\n const collectCaptures = opts?.collectCaptures === true;\n const liveConsole: ConsoleApiCalledEvent[] = [];\n let unsubscribeConsole: (() => void) | undefined;\n if (collectCaptures && domainsEnabled) {\n unsubscribeConsole = connection.on('Runtime.consoleAPICalled', (event) => {\n liveConsole.push(event);\n });\n }\n\n try {\n for (const file of files) {\n let fileEntry: FileResult;\n try {\n const { code } = await bundleTestFile(file, opts?.bundleOptions);\n const rpcResult = await injectAndRunBundle(connection, code, opts?.timeoutMs);\n if (rpcResult.ok) {\n fileEntry = { file, result: rpcResult.report };\n } else {\n fileEntry = { file, result: { error: rpcResult.error } };\n }\n } catch (e) {\n // Capture bundle/inject errors per-file so subsequent files still run.\n fileEntry = {\n file,\n result: {\n error: e instanceof Error ? e.message : String(e),\n },\n };\n }\n fileResults.push(fileEntry);\n }\n } finally {\n // Always remove the live listener — leaking it would accumulate across runs\n // on a reused connection (the Vitest pool keeps one connection for the whole\n // run; the MCP daemon keeps one for the session).\n unsubscribeConsole?.();\n }\n\n // Convert the accumulated console events to `__AIT_CAPTURE__` lines. Each\n // event's args are rendered to a single line text (inlined console rendering —\n // no tools.ts import, to keep this module off the heavy MCP graph), then the\n // allowlist-prefix parser keeps only genuine capture lines.\n const captures = collectCaptures\n ? parseCaptureLines(liveConsole.map((e) => ({ text: renderConsoleLineText(e) })))\n : [];\n\n const totals = fileResults.reduce(\n (acc, { result }) => {\n if ('error' in result) {\n // Treat whole-file errors as a single failure.\n acc.failed += 1;\n acc.total += 1;\n } else {\n acc.passed += result.passed;\n acc.failed += result.failed;\n acc.skipped += result.skipped;\n acc.total += result.passed + result.failed + result.skipped;\n }\n return acc;\n },\n { passed: 0, failed: 0, skipped: 0, total: 0 },\n );\n\n return {\n startedAt,\n duration: Date.now() - wallStart,\n files: fileResults,\n totals,\n captures,\n };\n}\n\n/**\n * Renders one `Runtime.consoleAPICalled` event to a single line of text, the\n * same way `tools.ts#normalizeConsoleMessage` does (args rendered + space-\n * joined). Inlined here (≈8 lines) so this module avoids importing `tools.ts`,\n * which would drag the heavy MCP/Node graph (server-lock, parent-watcher, …)\n * onto the test-runner entry.\n *\n * SECRET-HANDLING: this only stringifies console args; the caller's\n * allowlist-prefix parser then discards everything that is not a genuine\n * `__AIT_CAPTURE__` line.\n */\nfunction renderConsoleLineText(event: ConsoleApiCalledEvent): string {\n return event.args\n .map((arg) => {\n if (arg.value !== undefined) {\n if (typeof arg.value === 'string') return arg.value;\n try {\n return JSON.stringify(arg.value);\n } catch {\n return String(arg.value);\n }\n }\n if (arg.description !== undefined) return arg.description;\n if (arg.className !== undefined) return arg.className;\n return arg.subtype ?? arg.type;\n })\n .join(' ');\n}\n\n/**\n * Flattens all test results from a `RelayRunReport` into a single array.\n * Files that errored during bundle/inject produce a synthetic failed entry.\n */\nexport function flattenResults(report: RelayRunReport): Array<TestResult & { file: string }> {\n const out: Array<TestResult & { file: string }> = [];\n for (const { file, result } of report.files) {\n if ('error' in result) {\n out.push({\n file,\n name: `<bundle/inject error>`,\n status: 'fail',\n duration: 0,\n error: result.error,\n });\n } else {\n for (const t of result.tests) {\n out.push({ ...t, file });\n }\n }\n }\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyGA,eAAsB,sBACpB,YACA,OACA,MACyB;CACzB,MAAM,YAAY,KAAK,KAAK;CAC5B,MAAM,YAAY,IAAI,KAAK,UAAU,CAAC,aAAa;CACnD,MAAM,cAA4B,EAAE;CAcpC,IAAI,iBAAiB;AACrB,KAAI;AACF,QAAM,WAAW,eAAe;AAChC,mBAAiB;UACV,GAAG;AACV,UAAQ,OAAO,MACb,mFACE,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,CAC3C,KACF;;CAcH,MAAM,kBAAkB,MAAM,oBAAoB;CAClD,MAAM,cAAuC,EAAE;CAC/C,IAAI;AACJ,KAAI,mBAAmB,eACrB,sBAAqB,WAAW,GAAG,6BAA6B,UAAU;AACxE,cAAY,KAAK,MAAM;GACvB;AAGJ,KAAI;AACF,OAAK,MAAM,QAAQ,OAAO;GACxB,IAAI;AACJ,OAAI;IACF,MAAM,EAAE,SAAS,MAAM,eAAe,MAAM,MAAM,cAAc;IAChE,MAAM,YAAY,MAAM,mBAAmB,YAAY,MAAM,MAAM,UAAU;AAC7E,QAAI,UAAU,GACZ,aAAY;KAAE;KAAM,QAAQ,UAAU;KAAQ;QAE9C,aAAY;KAAE;KAAM,QAAQ,EAAE,OAAO,UAAU,OAAO;KAAE;YAEnD,GAAG;AAEV,gBAAY;KACV;KACA,QAAQ,EACN,OAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,EAClD;KACF;;AAEH,eAAY,KAAK,UAAU;;WAErB;AAIR,wBAAsB;;CAOxB,MAAM,WAAW,kBACb,kBAAkB,YAAY,KAAK,OAAO,EAAE,MAAM,sBAAsB,EAAE,EAAE,EAAE,CAAC,GAC/E,EAAE;CAEN,MAAM,SAAS,YAAY,QACxB,KAAK,EAAE,aAAa;AACnB,MAAI,WAAW,QAAQ;AAErB,OAAI,UAAU;AACd,OAAI,SAAS;SACR;AACL,OAAI,UAAU,OAAO;AACrB,OAAI,UAAU,OAAO;AACrB,OAAI,WAAW,OAAO;AACtB,OAAI,SAAS,OAAO,SAAS,OAAO,SAAS,OAAO;;AAEtD,SAAO;IAET;EAAE,QAAQ;EAAG,QAAQ;EAAG,SAAS;EAAG,OAAO;EAAG,CAC/C;AAED,QAAO;EACL;EACA,UAAU,KAAK,KAAK,GAAG;EACvB,OAAO;EACP;EACA;EACD;;;;;;;;;;;;;AAcH,SAAS,sBAAsB,OAAsC;AACnE,QAAO,MAAM,KACV,KAAK,QAAQ;AACZ,MAAI,IAAI,UAAU,KAAA,GAAW;AAC3B,OAAI,OAAO,IAAI,UAAU,SAAU,QAAO,IAAI;AAC9C,OAAI;AACF,WAAO,KAAK,UAAU,IAAI,MAAM;WAC1B;AACN,WAAO,OAAO,IAAI,MAAM;;;AAG5B,MAAI,IAAI,gBAAgB,KAAA,EAAW,QAAO,IAAI;AAC9C,MAAI,IAAI,cAAc,KAAA,EAAW,QAAO,IAAI;AAC5C,SAAO,IAAI,WAAW,IAAI;GAC1B,CACD,KAAK,IAAI;;;;;;AAOd,SAAgB,eAAe,QAA8D;CAC3F,MAAM,MAA4C,EAAE;AACpD,MAAK,MAAM,EAAE,MAAM,YAAY,OAAO,MACpC,KAAI,WAAW,OACb,KAAI,KAAK;EACP;EACA,MAAM;EACN,QAAQ;EACR,UAAU;EACV,OAAO,OAAO;EACf,CAAC;KAEF,MAAK,MAAM,KAAK,OAAO,MACrB,KAAI,KAAK;EAAE,GAAG;EAAG;EAAM,CAAC;AAI9B,QAAO"}
|
|
1
|
+
{"version":3,"file":"relay-worker.js","names":[],"sources":["../../src/test-runner/relay-worker.ts"],"sourcesContent":["/**\n * Orchestrator: runs a list of test files sequentially over a CDP relay.\n *\n * Each file goes through: bundle → inject → run → collect.\n * This is the transport layer: it does NOT integrate with Vitest's pool or the\n * MCP surface. The Vitest custom pool (`pool.ts`) and the `run_tests` MCP tool\n * are separate callers that build on this orchestrator.\n *\n * Single-attach constraint: only one page is active at a time. Files run\n * sequentially; parallel execution across targets is out of scope.\n *\n * The per-file timeout is inherited from `injectAndRunBundle` (default 60 s).\n * For suites that exceed it, split the file into smaller pieces.\n *\n * SECRET-HANDLING: file paths are surfaced in reports; relay URLs are not.\n */\n\nimport type { CdpConnection, ConsoleApiCalledEvent } from '../mcp/cdp-connection.js';\nimport { type BundleOptions, bundleTestFile } from './bundle.js';\nimport { type AitCaptureLine, parseCaptureLines } from './capture.js';\nimport { injectAndRunBundle } from './rpc.js';\nimport type { RunReport, TestResult } from './runtime.js';\n\n/** Per-file result in the aggregate `RunReport`. */\nexport interface FileResult {\n /** Absolute or relative path to the test file. */\n file: string;\n /** Full run report for this file, or an error if bundling/injection failed. */\n result: RunReport | { error: string };\n}\n\n/** Aggregate report returned by `runTestFilesOverRelay`. */\nexport interface RelayRunReport {\n /** ISO timestamp of when the run started. */\n startedAt: string;\n /** Total elapsed wall-clock milliseconds. */\n duration: number;\n /** Per-file results in execution order. */\n files: FileResult[];\n /** Flattened totals across all files. */\n totals: {\n passed: number;\n failed: number;\n skipped: number;\n total: number;\n };\n /**\n * `__AIT_CAPTURE__` lines harvested from the page console during the run\n * (additive field, devtools#696). Empty unless `collectCaptures` was set.\n * Each entry is opaque (`{ category, json }`) — devtools does not interpret\n * the record shape, only forwards it for downstream 2.x↔3.0 diffing.\n *\n * SECRET-HANDLING: only lines matching the `__AIT_CAPTURE__ ` allowlist\n * prefix reach here; relay/wss/scheme noise lines are dropped in\n * `parseCaptureLines`.\n */\n captures: AitCaptureLine[];\n}\n\n/** Options for `runTestFilesOverRelay`. */\nexport interface RelayRunOptions {\n /**\n * Options forwarded to `bundleTestFile` for each file.\n */\n bundleOptions?: BundleOptions;\n /**\n * Per-file evaluate timeout in milliseconds. Defaults to 30 000.\n * Increase for long-running suites or split the file.\n */\n timeoutMs?: number;\n /**\n * When `true`, registers a live `Runtime.consoleAPICalled` listener for the\n * duration of the run and harvests `__AIT_CAPTURE__` lines into\n * `RelayRunReport.captures`. Defaults to **false** so the build-only\n * eval/e2e path (and the Vitest pool) pay no listener/state overhead —\n * `captures` is then an empty array.\n *\n * The listener is registered just BEFORE the first file runs and removed in a\n * `finally` so it never accumulates across runs (no ring-buffer drain — the\n * default 500-entry buffer would silently drop lines via `shift`).\n */\n collectCaptures?: boolean;\n}\n\n/**\n * Sentinel string embedded in the error message by `injectAndRunBundle` when\n * the per-file evaluate race hits the timeout. Used by the retry guard so only\n * genuine timeouts get a second attempt — not bundle errors or parse failures.\n *\n * Exported for unit tests that assert the retry path is taken.\n */\nexport const EVALUATE_TIMEOUT_MARKER = 'rpc: evaluate timed out after';\n\n/**\n * Runs all `files` sequentially over the given CDP `connection`.\n *\n * For each file:\n * 1. Bundle with esbuild (includes SDK shim + runtime).\n * 2. Inject into the attached page via `Runtime.evaluate`.\n * 3. Await the `RunReport` JSON response.\n * 4. Accumulate results.\n *\n * Returns a `RelayRunReport` with per-file results and flattened totals.\n *\n * This function does NOT open or manage the relay connection — the caller\n * is responsible for attaching and closing it.\n *\n * TODO (#645): implement the Vitest `PoolRunnerInitializer` interface here\n * so that `runTestFilesOverRelay` can be used as a Vitest pool entry.\n *\n * @param connection - Active CDP connection (relay or local kind).\n * @param files - Absolute paths to test files, run in order.\n * @param opts - Optional per-run overrides.\n */\nexport async function runTestFilesOverRelay(\n connection: CdpConnection,\n files: string[],\n opts?: RelayRunOptions,\n): Promise<RelayRunReport> {\n const wallStart = Date.now();\n const startedAt = new Date(wallStart).toISOString();\n const fileResults: FileResult[] = [];\n\n // Enable CDP domains ONCE up front. Without this the relay connection has not\n // opened its client websocket, so the very first `Runtime.evaluate` (in\n // `injectAndRunBundle`) explodes AND `Runtime.consoleAPICalled` never streams\n // — the console capture harvest would be structurally 0. `enableDomains()` is\n // idempotent (see chii-connection: early-returns when the ws is already OPEN,\n // and shares an in-flight promise), so calling it here is safe even when a\n // caller (the MCP `run_tests` path) already enabled it.\n //\n // Failure here (e.g. no target attached yet) must NOT throw the whole run: the\n // per-file inject below produces a structured error result instead. We warn on\n // stderr (secret-free) and continue. SECRET-HANDLING: the message names the\n // failure only — no relay/wss URL.\n let domainsEnabled = false;\n try {\n await connection.enableDomains();\n domainsEnabled = true;\n } catch (e) {\n process.stderr.write(\n `relay-worker: enableDomains() failed before run — console capture may be empty (${\n e instanceof Error ? e.message : String(e)\n })\\n`,\n );\n }\n\n // Live console capture (#696): when requested, accumulate every\n // `Runtime.consoleAPICalled` event into a local array via a LIVE listener\n // registered just before the run. We deliberately do NOT drain\n // `getBufferedEvents` after the fact — that ring buffer caps at 500 and\n // `shift()`s older entries, so a chatty run would silently lose capture lines.\n // The listener is removed in `finally` so it never bleeds into the next run.\n //\n // Gate the listener on `domainsEnabled`: if enableDomains() soft-failed, the\n // client ws never opened so `Runtime.consoleAPICalled` cannot stream —\n // registering would only add a dead listener that never fires. (The `finally`\n // unsubscribe is an undefined no-op in that case, so this stays safe.)\n const collectCaptures = opts?.collectCaptures === true;\n const liveConsole: ConsoleApiCalledEvent[] = [];\n let unsubscribeConsole: (() => void) | undefined;\n if (collectCaptures && domainsEnabled) {\n unsubscribeConsole = connection.on('Runtime.consoleAPICalled', (event) => {\n liveConsole.push(event);\n });\n }\n\n try {\n for (const file of files) {\n let fileEntry: FileResult;\n try {\n const { code } = await bundleTestFile(file, opts?.bundleOptions);\n\n /**\n * Runs one evaluate attempt and returns a FileResult, or `null` when the\n * result is a genuine timeout and the caller should retry.\n *\n * We need to distinguish:\n * - `rpcResult.ok = false` + timeout error → retry candidate (`return null`)\n * - `rpcResult.ok = false` + other error → final error, no retry\n * - `injectAndRunBundle` throws → CDP exceptionDetails (page\n * engine threw); treated as a final (non-retryable) error.\n *\n * The Promise.race timeout in rpc.ts RETURNS `{ok:false, error: '…'}` (it\n * does NOT throw/reject). Only genuine CDP `exceptionDetails` cause a throw.\n * This distinction is what makes the EVALUATE_TIMEOUT_MARKER gate below\n * reachable — the timeout result surfaces as `rpcResult.ok=false` with the\n * marker string, not as a caught exception.\n */\n const attempt = async (): Promise<FileResult | null> => {\n let rpcResult: Awaited<ReturnType<typeof injectAndRunBundle>>;\n try {\n rpcResult = await injectAndRunBundle(connection, code, opts?.timeoutMs);\n } catch (e) {\n // injectAndRunBundle throws only for CDP exceptionDetails — treat as\n // a final (non-retryable) error.\n return {\n file,\n result: { error: e instanceof Error ? e.message : String(e) },\n };\n }\n\n if (rpcResult.ok) {\n return { file, result: rpcResult.report };\n }\n\n // Timed-out evaluates get one retry; other errors are final.\n if (rpcResult.error.includes(EVALUATE_TIMEOUT_MARKER)) {\n return null; // signal \"retry\"\n }\n return { file, result: { error: rpcResult.error } };\n };\n\n const firstResult = await attempt();\n if (firstResult !== null) {\n fileEntry = firstResult;\n } else {\n // First attempt timed out — retry once. A transient native dialog\n // (camera picker, location permission sheet, GPS cold-fix) may have\n // cleared by now.\n process.stderr.write(`relay-worker: evaluate timed out for ${file} — retrying once\\n`);\n const retryResult = await attempt();\n if (retryResult !== null) {\n fileEntry = retryResult;\n } else {\n // Second timeout: build a final error entry.\n fileEntry = {\n file,\n result: {\n error: `${EVALUATE_TIMEOUT_MARKER} ${opts?.timeoutMs ?? 30_000}ms (after retry)`,\n },\n };\n }\n }\n } catch (e) {\n // Capture bundle errors per-file so subsequent files still run.\n fileEntry = {\n file,\n result: { error: e instanceof Error ? e.message : String(e) },\n };\n }\n fileResults.push(fileEntry);\n }\n } finally {\n // Always remove the live listener — leaking it would accumulate across runs\n // on a reused connection (the Vitest pool keeps one connection for the whole\n // run; the MCP daemon keeps one for the session).\n unsubscribeConsole?.();\n }\n\n // Convert the accumulated console events to `__AIT_CAPTURE__` lines. Each\n // event's args are rendered to a single line text (inlined console rendering —\n // no tools.ts import, to keep this module off the heavy MCP graph), then the\n // allowlist-prefix parser keeps only genuine capture lines.\n const captures = collectCaptures\n ? parseCaptureLines(liveConsole.map((e) => ({ text: renderConsoleLineText(e) })))\n : [];\n\n const totals = fileResults.reduce(\n (acc, { result }) => {\n if ('error' in result) {\n // Treat whole-file errors as a single failure.\n acc.failed += 1;\n acc.total += 1;\n } else {\n acc.passed += result.passed;\n acc.failed += result.failed;\n acc.skipped += result.skipped;\n acc.total += result.passed + result.failed + result.skipped;\n }\n return acc;\n },\n { passed: 0, failed: 0, skipped: 0, total: 0 },\n );\n\n return {\n startedAt,\n duration: Date.now() - wallStart,\n files: fileResults,\n totals,\n captures,\n };\n}\n\n/**\n * Renders one `Runtime.consoleAPICalled` event to a single line of text, the\n * same way `tools.ts#normalizeConsoleMessage` does (args rendered + space-\n * joined). Inlined here (≈8 lines) so this module avoids importing `tools.ts`,\n * which would drag the heavy MCP/Node graph (server-lock, parent-watcher, …)\n * onto the test-runner entry.\n *\n * SECRET-HANDLING: this only stringifies console args; the caller's\n * allowlist-prefix parser then discards everything that is not a genuine\n * `__AIT_CAPTURE__` line.\n */\nfunction renderConsoleLineText(event: ConsoleApiCalledEvent): string {\n return event.args\n .map((arg) => {\n if (arg.value !== undefined) {\n if (typeof arg.value === 'string') return arg.value;\n try {\n return JSON.stringify(arg.value);\n } catch {\n return String(arg.value);\n }\n }\n if (arg.description !== undefined) return arg.description;\n if (arg.className !== undefined) return arg.className;\n return arg.subtype ?? arg.type;\n })\n .join(' ');\n}\n\n/**\n * Flattens all test results from a `RelayRunReport` into a single array.\n * Files that errored during bundle/inject produce a synthetic failed entry.\n */\nexport function flattenResults(report: RelayRunReport): Array<TestResult & { file: string }> {\n const out: Array<TestResult & { file: string }> = [];\n for (const { file, result } of report.files) {\n if ('error' in result) {\n out.push({\n file,\n name: `<bundle/inject error>`,\n status: 'fail',\n duration: 0,\n error: result.error,\n });\n } else {\n for (const t of result.tests) {\n out.push({ ...t, file });\n }\n }\n }\n return out;\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as AitCaptureLine } from "../capture-B1zfGyTo.js";
|
|
2
2
|
import { n as TestResult } from "../runtime-ozyPnRbU.js";
|
|
3
|
-
import {
|
|
3
|
+
import { i as RelayRunReport } from "../relay-worker-TReZtzGl.js";
|
|
4
4
|
|
|
5
5
|
//#region src/test-runner/report.d.ts
|
|
6
6
|
/** The cell axes a report is stamped with — the test-matrix coordinates. */
|
package/dist/test-runner/rpc.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/test-runner/rpc.ts
|
|
2
2
|
/** Maximum milliseconds to wait for a single evaluate round-trip. */
|
|
3
|
-
const DEFAULT_TIMEOUT_MS =
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 6e4;
|
|
4
4
|
/**
|
|
5
5
|
* Wraps bundle code in a self-executing IIFE that:
|
|
6
6
|
* 1. Evaluates the bundle (registering describe/it/test).
|
|
@@ -59,13 +59,22 @@ function parseRunTestsResult(rawValue) {
|
|
|
59
59
|
*/
|
|
60
60
|
async function injectAndRunBundle(connection, bundleCode, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
61
61
|
const expression = buildRunTestsExpression(bundleCode);
|
|
62
|
-
const
|
|
62
|
+
const TIMEOUT_SENTINEL = Symbol("timeout");
|
|
63
|
+
const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve(TIMEOUT_SENTINEL), timeoutMs));
|
|
63
64
|
const evalPromise = connection.send("Runtime.evaluate", {
|
|
64
65
|
expression,
|
|
65
66
|
returnByValue: true,
|
|
66
67
|
awaitPromise: true
|
|
67
68
|
});
|
|
68
|
-
const
|
|
69
|
+
const raceResult = await Promise.race([evalPromise.then((v) => ({
|
|
70
|
+
tag: "eval",
|
|
71
|
+
v
|
|
72
|
+
})), timeoutPromise.then(() => ({ tag: "timeout" }))]);
|
|
73
|
+
if (raceResult.tag === "timeout") return {
|
|
74
|
+
ok: false,
|
|
75
|
+
error: `rpc: evaluate timed out after ${timeoutMs}ms`
|
|
76
|
+
};
|
|
77
|
+
const cdpResult = raceResult.v;
|
|
69
78
|
if (cdpResult.exceptionDetails) {
|
|
70
79
|
const msg = cdpResult.exceptionDetails.exception?.description ?? cdpResult.exceptionDetails.text ?? "Runtime.evaluate threw an exception";
|
|
71
80
|
throw new Error(`rpc.injectAndRunBundle: ${msg}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc.js","names":[],"sources":["../../src/test-runner/rpc.ts"],"sourcesContent":["/**\n * Node-side RPC helpers for injecting and collecting test execution over CDP.\n *\n * Uses the same IIFE + JSON.stringify envelope pattern as `buildCallSdkExpression`\n * in `src/mcp/tools.ts` to reliably shuttle structured results through\n * `Runtime.evaluate`'s `returnByValue: true` boundary.\n *\n * SECRET-HANDLING: bundle code, relay URLs, and result values are NOT logged.\n */\n\nimport type { CdpConnection } from '../mcp/cdp-connection.js';\nimport type { RunReport } from './runtime.js';\n\n/** Maximum milliseconds to wait for a single evaluate round-trip. */\nconst DEFAULT_TIMEOUT_MS =
|
|
1
|
+
{"version":3,"file":"rpc.js","names":[],"sources":["../../src/test-runner/rpc.ts"],"sourcesContent":["/**\n * Node-side RPC helpers for injecting and collecting test execution over CDP.\n *\n * Uses the same IIFE + JSON.stringify envelope pattern as `buildCallSdkExpression`\n * in `src/mcp/tools.ts` to reliably shuttle structured results through\n * `Runtime.evaluate`'s `returnByValue: true` boundary.\n *\n * SECRET-HANDLING: bundle code, relay URLs, and result values are NOT logged.\n */\n\nimport type { CdpConnection } from '../mcp/cdp-connection.js';\nimport type { RunReport } from './runtime.js';\n\n/** Maximum milliseconds to wait for a single evaluate round-trip. */\nconst DEFAULT_TIMEOUT_MS = 60_000;\n\n/**\n * Wraps bundle code in a self-executing IIFE that:\n * 1. Evaluates the bundle (registering describe/it/test).\n * 2. Calls `__testBundle.runTestModule(...)` — the entry the runtime exports.\n * 3. Returns a JSON-serialised `RunReport` string.\n *\n * The double-serialisation (RunReport → JSON string → returnByValue string)\n * is intentional: CDP `returnByValue` reliably transports strings; deeply\n * nested objects can lose fidelity across the Chii relay.\n *\n * SECRET-HANDLING: `bundleCode` MUST NOT be logged by callers.\n */\nexport function buildRunTestsExpression(bundleCode: string): string {\n // We trust bundleCode is already a self-contained IIFE that installs\n // `window.__testBundle` (or `globalThis.__testBundle`).\n // We then call `__testBundle.runTestModule()` and return a JSON string.\n return (\n `(async () => {` +\n // Step 1: evaluate the bundle to register tests\n ` try { ${bundleCode} } catch(e) {` +\n ` return JSON.stringify({ok:false,error:'bundle-eval: ' + String(e && e.message || e)});` +\n ` }` +\n // Step 2: check that the expected exports are present\n ` if (typeof globalThis.__testBundle !== 'object' || typeof globalThis.__testBundle.runTestModule !== 'function' || typeof globalThis.__testBundle.__userFactory !== 'function') {` +\n ` return JSON.stringify({ok:false,error:'bundle-missing-export: __testBundle.runTestModule or __userFactory is not a function'});` +\n ` }` +\n // Step 3: run tests — pass the factory so runTestModule installs globals\n // first, then invokes the factory to register describe/it/test blocks.\n ` try {` +\n ` const report = await globalThis.__testBundle.runTestModule(globalThis.__testBundle.__userFactory);` +\n ` return JSON.stringify({ok:true,value:report});` +\n ` } catch(e) {` +\n ` return JSON.stringify({ok:false,error:'test-run: ' + String(e && e.message || e)});` +\n ` }` +\n `})()`\n );\n}\n\n/**\n * Result of `injectAndRunBundle`.\n */\nexport type RpcRunResult = { ok: true; report: RunReport } | { ok: false; error: string };\n\n/**\n * Parses the raw CDP `returnByValue` result from a `buildRunTestsExpression`\n * evaluate call into a typed `RpcRunResult`.\n *\n * Throws only on parse failure — an `ok:false` envelope is a normal result.\n *\n * SECRET-HANDLING: `rawValue` is not included in error messages.\n */\nexport function parseRunTestsResult(rawValue: unknown): RpcRunResult {\n if (typeof rawValue !== 'string') {\n throw new Error(\n `rpc.parseRunTestsResult: unexpected return type \"${typeof rawValue}\" — expected JSON string`,\n );\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawValue);\n } catch {\n // Do NOT include rawValue — could contain secrets.\n throw new Error('rpc.parseRunTestsResult: bridge returned non-JSON string');\n }\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n throw new Error('rpc.parseRunTestsResult: parsed result is not an object');\n }\n const obj = parsed as Record<string, unknown>;\n if (obj.ok === true) {\n return { ok: true, report: obj.value as RunReport };\n }\n if (obj.ok === false) {\n return {\n ok: false,\n error: typeof obj.error === 'string' ? obj.error : String(obj.error),\n };\n }\n throw new Error('rpc.parseRunTestsResult: result missing \"ok\" field');\n}\n\n/**\n * Injects `bundleCode` into the attached page and awaits test execution.\n *\n * Uses `Runtime.evaluate` with `awaitPromise: true` to wait for the\n * async IIFE to settle. The 30-second CDP command timeout covers even\n * long-running test suites; split into smaller files if you hit it.\n *\n * @param connection - Active CDP connection (relay or local).\n * @param bundleCode - IIFE bundle string from `bundleTestFile`.\n * @param timeoutMs - Override the default 30 s timeout.\n *\n * SECRET-HANDLING: `bundleCode` and the raw CDP result value are never logged.\n */\nexport async function injectAndRunBundle(\n connection: CdpConnection,\n bundleCode: string,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n): Promise<RpcRunResult> {\n const expression = buildRunTestsExpression(bundleCode);\n\n // Use a tagged race so we can distinguish \"timeout won\" from \"evaluate won\"\n // without relying on exception identity. The timeout arm RETURNS a typed\n // RpcRunResult (ok:false + EVALUATE_TIMEOUT_MARKER) so the caller (relay-\n // worker's attempt()) can detect it via `.error.includes(EVALUATE_TIMEOUT_MARKER)`\n // and trigger the one-retry path.\n //\n // Genuine CDP `exceptionDetails` (engine exceptions thrown inside the page)\n // still THROW — those are deterministic failures that a retry cannot fix and\n // relay-worker's catch block finalises them correctly.\n //\n // DO NOT change the literal string below — relay-worker.ts imports\n // EVALUATE_TIMEOUT_MARKER = 'rpc: evaluate timed out after' and uses\n // `.includes()` to recognise this exact prefix.\n const TIMEOUT_SENTINEL = Symbol('timeout');\n const timeoutPromise = new Promise<typeof TIMEOUT_SENTINEL>((resolve) =>\n setTimeout(() => resolve(TIMEOUT_SENTINEL), timeoutMs),\n );\n\n const evalPromise = connection.send('Runtime.evaluate', {\n expression,\n returnByValue: true,\n awaitPromise: true,\n });\n\n const raceResult = await Promise.race([\n evalPromise.then((v) => ({ tag: 'eval' as const, v })),\n timeoutPromise.then(() => ({ tag: 'timeout' as const })),\n ]);\n\n if (raceResult.tag === 'timeout') {\n return { ok: false, error: `rpc: evaluate timed out after ${timeoutMs}ms` };\n }\n\n const cdpResult = raceResult.v;\n\n if (cdpResult.exceptionDetails) {\n // Surface only the engine error string — not the expression or value.\n const msg =\n cdpResult.exceptionDetails.exception?.description ??\n cdpResult.exceptionDetails.text ??\n 'Runtime.evaluate threw an exception';\n throw new Error(`rpc.injectAndRunBundle: ${msg}`);\n }\n\n return parseRunTestsResult(cdpResult.result.value);\n}\n"],"mappings":";;AAcA,MAAM,qBAAqB;;;;;;;;;;;;;AAc3B,SAAgB,wBAAwB,YAA4B;AAIlE,QACE,yBAEW,WAAW;;;;;;;;;;AAgC1B,SAAgB,oBAAoB,UAAiC;AACnE,KAAI,OAAO,aAAa,SACtB,OAAM,IAAI,MACR,oDAAoD,OAAO,SAAS,0BACrE;CAEH,IAAI;AACJ,KAAI;AACF,WAAS,KAAK,MAAM,SAAS;SACvB;AAEN,QAAM,IAAI,MAAM,2DAA2D;;AAE7E,KAAI,OAAO,WAAW,YAAY,WAAW,QAAQ,MAAM,QAAQ,OAAO,CACxE,OAAM,IAAI,MAAM,0DAA0D;CAE5E,MAAM,MAAM;AACZ,KAAI,IAAI,OAAO,KACb,QAAO;EAAE,IAAI;EAAM,QAAQ,IAAI;EAAoB;AAErD,KAAI,IAAI,OAAO,MACb,QAAO;EACL,IAAI;EACJ,OAAO,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ,OAAO,IAAI,MAAM;EACrE;AAEH,OAAM,IAAI,MAAM,uDAAqD;;;;;;;;;;;;;;;AAgBvE,eAAsB,mBACpB,YACA,YACA,YAAY,oBACW;CACvB,MAAM,aAAa,wBAAwB,WAAW;CAetD,MAAM,mBAAmB,OAAO,UAAU;CAC1C,MAAM,iBAAiB,IAAI,SAAkC,YAC3D,iBAAiB,QAAQ,iBAAiB,EAAE,UAAU,CACvD;CAED,MAAM,cAAc,WAAW,KAAK,oBAAoB;EACtD;EACA,eAAe;EACf,cAAc;EACf,CAAC;CAEF,MAAM,aAAa,MAAM,QAAQ,KAAK,CACpC,YAAY,MAAM,OAAO;EAAE,KAAK;EAAiB;EAAG,EAAE,EACtD,eAAe,YAAY,EAAE,KAAK,WAAoB,EAAE,CACzD,CAAC;AAEF,KAAI,WAAW,QAAQ,UACrB,QAAO;EAAE,IAAI;EAAO,OAAO,iCAAiC,UAAU;EAAK;CAG7E,MAAM,YAAY,WAAW;AAE7B,KAAI,UAAU,kBAAkB;EAE9B,MAAM,MACJ,UAAU,iBAAiB,WAAW,eACtC,UAAU,iBAAiB,QAC3B;AACF,QAAM,IAAI,MAAM,2BAA2B,MAAM;;AAGnD,QAAO,oBAAoB,UAAU,OAAO,MAAM"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"relay-worker-7biDlEjo.d.ts","names":[],"sources":["../src/test-runner/relay-worker.ts"],"mappings":";;;;;;;UAwBiB,UAAA;EAcf;EAZA,IAAA;EAcA;EAZA,MAAA,EAAQ,SAAA;IAAc,KAAA;EAAA;AAAA;;UAIP,cAAA;EAwBS;EAtBxB,SAAA;EA0Be;EAxBf,QAAA;;EAEA,KAAA,EAAO,UAAA;EA0BP;EAxBA,MAAA;IACE,MAAA;IACA,MAAA;IACA,OAAA;IACA,KAAA;EAAA;EA6DuC;;;;;;;;;;EAjDzC,QAAA,EAAU,cAAA;AAAA;;UAIK,eAAA;EAiDN;;;EA7CT,aAAA,GAAgB,aAAA;EA8LY;;;;EAzL5B,SAAA;EAyL2D;;;;;;;;;;;EA7K3D,eAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;iBAwBoB,qBAAA,CACpB,UAAA,EAAY,aAAA,EACZ,KAAA,YACA,IAAA,GAAO,eAAA,GACN,OAAA,CAAQ,cAAA;;;;;iBAiJK,cAAA,CAAe,MAAA,EAAQ,cAAA,GAAiB,KAAA,CAAM,UAAA;EAAe,IAAA;AAAA"}
|