vdelta 0.4.0 → 0.6.0
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/adapter.d.ts +7 -5
- package/dist/adapter.js +22 -3
- package/dist/adapter.js.map +1 -1
- package/dist/adapters/playwright/adapter.d.ts +27 -0
- package/dist/adapters/playwright/adapter.js +175 -0
- package/dist/adapters/playwright/adapter.js.map +1 -0
- package/dist/adapters/playwright/capture.d.ts +119 -0
- package/dist/adapters/playwright/capture.js +12 -0
- package/dist/adapters/playwright/capture.js.map +1 -0
- package/dist/adapters/playwright/recorder.d.ts +65 -0
- package/dist/adapters/playwright/recorder.js +511 -0
- package/dist/adapters/playwright/recorder.js.map +1 -0
- package/dist/adapters/playwright/reporter.cjs +322 -0
- package/dist/adapters/playwright/reporter.cjs.map +1 -0
- package/dist/adapters/playwright/reporter.d.cts +63 -0
- package/dist/adapters/registry.js +2 -1
- package/dist/adapters/registry.js.map +1 -1
- package/dist/adapters/vitest/adapter.d.ts +9 -10
- package/dist/adapters/vitest/adapter.js +8 -17
- package/dist/adapters/vitest/adapter.js.map +1 -1
- package/dist/adapters/vitest/recorder.d.ts +10 -1
- package/dist/adapters/vitest/recorder.js +18 -1
- package/dist/adapters/vitest/recorder.js.map +1 -1
- package/dist/compare.d.ts +5 -0
- package/dist/compare.js +28 -27
- package/dist/compare.js.map +1 -1
- package/dist/gate.js +9 -8
- package/dist/gate.js.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +55 -1
- package/dist/schema.js +26 -8
- package/dist/schema.js.map +1 -1
- package/package.json +4 -2
- package/spec/veridelta-1.md +32 -3
package/dist/adapter.d.ts
CHANGED
|
@@ -14,13 +14,15 @@
|
|
|
14
14
|
* `splitCommandSelector` know only the runner's *argv surface*, `record` knows
|
|
15
15
|
* only its *structured channel*.
|
|
16
16
|
*/
|
|
17
|
-
import type
|
|
17
|
+
import { CAPABILITY_VALUES, type CapabilityValue, type RunRecord } from './schema.js';
|
|
18
|
+
export type { CapabilityValue };
|
|
18
19
|
/**
|
|
19
|
-
* The three-valued capability convention (§3.4).
|
|
20
|
-
*
|
|
20
|
+
* The three-valued capability convention (§3.4). Defined in `schema.ts`
|
|
21
|
+
* because `parseRunRecord` needs it for `instrument.capabilities` value
|
|
22
|
+
* validation; re-exported here so adapter code keeps importing it from the
|
|
23
|
+
* adapter seam.
|
|
21
24
|
*/
|
|
22
|
-
export
|
|
23
|
-
export type CapabilityValue = (typeof CAPABILITY_VALUES)[number];
|
|
25
|
+
export { CAPABILITY_VALUES };
|
|
24
26
|
export type CapabilityDeclaration = Readonly<Record<string, CapabilityValue>>;
|
|
25
27
|
/**
|
|
26
28
|
* Where the adapter's structured channel lands. A single capture file is the
|
package/dist/adapter.js
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
3
|
-
*
|
|
2
|
+
* The adapter seam. The core (`run` / `compare` / `gate`) never reaches into a
|
|
3
|
+
* concrete runner: it resolves an {@link Adapter} descriptor from the registry
|
|
4
|
+
* (`src/adapters/registry.ts`) and talks to it through this interface only.
|
|
5
|
+
*
|
|
6
|
+
* Every type here is a promotion of a shape that already existed on the vitest
|
|
7
|
+
* side, so the seam is a rearrangement of what already ran rather than a new
|
|
8
|
+
* mechanism: {@link RecordContext} is the recorder's context object verbatim,
|
|
9
|
+
* {@link DetectResult} is the runner-token scan's return value,
|
|
10
|
+
* {@link InstrumentedChild} is the argv/env injection `vdelta run` already
|
|
11
|
+
* performed, and {@link CommandSelector} is the §6.4 inclusion-intent split.
|
|
12
|
+
*
|
|
13
|
+
* Dependency direction inside an adapter is one-way: `detect` / `instrument` /
|
|
14
|
+
* `splitCommandSelector` know only the runner's *argv surface*, `record` knows
|
|
15
|
+
* only its *structured channel*.
|
|
4
16
|
*/
|
|
5
|
-
|
|
17
|
+
import { CAPABILITY_VALUES, } from './schema.js';
|
|
18
|
+
/**
|
|
19
|
+
* The three-valued capability convention (§3.4). Defined in `schema.ts`
|
|
20
|
+
* because `parseRunRecord` needs it for `instrument.capabilities` value
|
|
21
|
+
* validation; re-exported here so adapter code keeps importing it from the
|
|
22
|
+
* adapter seam.
|
|
23
|
+
*/
|
|
24
|
+
export { CAPABILITY_VALUES };
|
|
6
25
|
/**
|
|
7
26
|
* The capability names a declaration says the composition cannot meet, sorted
|
|
8
27
|
* (§4.2 disclosure rule). `unsupported` is the only degraded value: `fail`
|
package/dist/adapter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EACL,iBAAiB,GAGlB,MAAM,aAAa,CAAA;AAGpB;;;;;GAKG;AACH,OAAO,EAAE,iBAAiB,EAAE,CAAA;AAwD5B;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAA2B;IAC9D,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;SACxB,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,aAAa,CAAC;SAC9C,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC;SACrB,IAAI,EAAE,CAAA;AACX,CAAC;AAWD;;;;GAIG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;IACnC,CAAC;CACF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type Adapter, type CommandSelector } from '../../adapter.js';
|
|
2
|
+
import { PLAYWRIGHT_CAPABILITIES } from './recorder.js';
|
|
3
|
+
/**
|
|
4
|
+
* Re-exported from the recorder (§3.4): the declaration lives in
|
|
5
|
+
* `recorder.ts` so `buildRunRecord` can write it into
|
|
6
|
+
* `instrument.capabilities` without an import cycle. Kept here too so
|
|
7
|
+
* existing consumers of this descriptor module keep importing it from
|
|
8
|
+
* `adapter.js` (same convention as `../vitest/adapter.ts`).
|
|
9
|
+
*/
|
|
10
|
+
export { PLAYWRIGHT_CAPABILITIES };
|
|
11
|
+
/**
|
|
12
|
+
* Locate the playwright `test` invocation inside the child argv; `null` when
|
|
13
|
+
* absent. Unlike vitest, a matching binary token alone is not enough: only
|
|
14
|
+
* a binary token *immediately followed (modulo flags) by the `test`
|
|
15
|
+
* subcommand* counts. Injecting `--reporter` into e.g. `playwright install`
|
|
16
|
+
* would kill that child outright (INV-5 — veridelta is never worse than its
|
|
17
|
+
* absence).
|
|
18
|
+
*/
|
|
19
|
+
export declare function findPlaywrightToken(argv: readonly string[]): number | null;
|
|
20
|
+
/**
|
|
21
|
+
* The invocation's selector is its inclusion intent (§6.4): the playwright
|
|
22
|
+
* CLI positional filters. The canonical command excludes them (§5.1), and
|
|
23
|
+
* keeps the `test` subcommand token (mirrors `../vitest/adapter.ts`'s
|
|
24
|
+
* treatment of the `run` subcommand token).
|
|
25
|
+
*/
|
|
26
|
+
export declare function splitCommandSelector(cmd: readonly string[]): CommandSelector;
|
|
27
|
+
export declare const playwrightAdapter: Adapter;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* playwright adapter, descriptor side: the runner-facing half of the seam
|
|
3
|
+
* (`src/adapter.ts`). Everything playwright-specific about *invoking* a run
|
|
4
|
+
* lives here — locating the playwright binary in the child argv, injecting
|
|
5
|
+
* the capture reporter, and splitting inclusion intent out of the command
|
|
6
|
+
* (§6.4) using playwright's own CLI surface. The recorder half (capture →
|
|
7
|
+
* RunRecord) stays in `./recorder.ts`; this module only owns reading and
|
|
8
|
+
* parsing the channel. Structured 1:1 on `../vitest/adapter.ts`.
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { dirname, join } from 'node:path';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import { AdapterCaptureError, } from '../../adapter.js';
|
|
14
|
+
import { ADAPTER_NAME, buildRunRecord, COMPOSITION_ID, DECLARED_ENV_VARS, PLAYWRIGHT_CAPABILITIES, } from './recorder.js';
|
|
15
|
+
/**
|
|
16
|
+
* Re-exported from the recorder (§3.4): the declaration lives in
|
|
17
|
+
* `recorder.ts` so `buildRunRecord` can write it into
|
|
18
|
+
* `instrument.capabilities` without an import cycle. Kept here too so
|
|
19
|
+
* existing consumers of this descriptor module keep importing it from
|
|
20
|
+
* `adapter.js` (same convention as `../vitest/adapter.ts`).
|
|
21
|
+
*/
|
|
22
|
+
export { PLAYWRIGHT_CAPABILITIES };
|
|
23
|
+
/**
|
|
24
|
+
* Absolute path of the in-process playwright reporter that writes the
|
|
25
|
+
* capture. Resolved relative to this module so it points at the built
|
|
26
|
+
* sibling (`dist/adapters/playwright/reporter.cjs`) rather than a source
|
|
27
|
+
* path. `.cjs`, not `.js`: an ESM reporter file makes playwright 1.49.1's
|
|
28
|
+
* loader (`node_modules/playwright/lib/util.js` `fileIsModule()` →
|
|
29
|
+
* `transform.js` `requireOrImport()`'s `eval("import(...)")` branch) hang
|
|
30
|
+
* indefinitely in this environment. `.cjs` is unconditionally treated as
|
|
31
|
+
* CommonJS and loads via `require()` instead (`reporter.cts`'s doc comment
|
|
32
|
+
* has the full account).
|
|
33
|
+
*/
|
|
34
|
+
function reporterModulePath() {
|
|
35
|
+
return join(dirname(fileURLToPath(import.meta.url)), 'reporter.cjs');
|
|
36
|
+
}
|
|
37
|
+
/** The one env var the capture reporter reads (`reporter.ts` — active/inert gate). */
|
|
38
|
+
const CAPTURE_FILE_ENV = 'VDELTA_CAPTURE_FILE';
|
|
39
|
+
function channelEnv(channel) {
|
|
40
|
+
return { [CAPTURE_FILE_ENV]: channel.path };
|
|
41
|
+
}
|
|
42
|
+
/** Parse the channel, or `undefined` when there is nothing readable in it. */
|
|
43
|
+
function readCapture(channel) {
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(readFileSync(channel.path, 'utf8'));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function isPlaywrightBinaryToken(token) {
|
|
52
|
+
return (token === 'playwright' ||
|
|
53
|
+
/(^|[\\/])playwright(\.m?js)?$/.test(token) ||
|
|
54
|
+
/[\\/]@playwright[\\/]test[\\/]cli\.(m?)js$/.test(token));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Locate the playwright `test` invocation inside the child argv; `null` when
|
|
58
|
+
* absent. Unlike vitest, a matching binary token alone is not enough: only
|
|
59
|
+
* a binary token *immediately followed (modulo flags) by the `test`
|
|
60
|
+
* subcommand* counts. Injecting `--reporter` into e.g. `playwright install`
|
|
61
|
+
* would kill that child outright (INV-5 — veridelta is never worse than its
|
|
62
|
+
* absence).
|
|
63
|
+
*/
|
|
64
|
+
export function findPlaywrightToken(argv) {
|
|
65
|
+
for (let i = 0; i < argv.length; i++) {
|
|
66
|
+
const token = argv[i];
|
|
67
|
+
if (!isPlaywrightBinaryToken(token))
|
|
68
|
+
continue;
|
|
69
|
+
let j = i + 1;
|
|
70
|
+
while (j < argv.length && argv[j].startsWith('-'))
|
|
71
|
+
j++;
|
|
72
|
+
if (j < argv.length && argv[j] === 'test')
|
|
73
|
+
return i;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* playwright 1.49.x CLI flags that always take their value as a *separate*
|
|
79
|
+
* argv token (`--flag value`), never combined into the flag token itself.
|
|
80
|
+
* Same role/limitation as `../vitest/adapter.ts`'s `VITEST_VALUE_FLAGS`:
|
|
81
|
+
* flags with an optional value are deliberately excluded, so a
|
|
82
|
+
* space-separated token after them stays a selector token rather than being
|
|
83
|
+
* silently swallowed.
|
|
84
|
+
*/
|
|
85
|
+
const PLAYWRIGHT_VALUE_FLAGS = new Set([
|
|
86
|
+
'--project',
|
|
87
|
+
'--config',
|
|
88
|
+
'-c',
|
|
89
|
+
'--grep',
|
|
90
|
+
'-g',
|
|
91
|
+
'--grep-invert',
|
|
92
|
+
'--workers',
|
|
93
|
+
'-j',
|
|
94
|
+
'--retries',
|
|
95
|
+
'--repeat-each',
|
|
96
|
+
'--timeout',
|
|
97
|
+
'--global-timeout',
|
|
98
|
+
'--max-failures',
|
|
99
|
+
'--shard',
|
|
100
|
+
'--reporter',
|
|
101
|
+
'--output',
|
|
102
|
+
'--tsconfig',
|
|
103
|
+
]);
|
|
104
|
+
/**
|
|
105
|
+
* The invocation's selector is its inclusion intent (§6.4): the playwright
|
|
106
|
+
* CLI positional filters. The canonical command excludes them (§5.1), and
|
|
107
|
+
* keeps the `test` subcommand token (mirrors `../vitest/adapter.ts`'s
|
|
108
|
+
* treatment of the `run` subcommand token).
|
|
109
|
+
*/
|
|
110
|
+
export function splitCommandSelector(cmd) {
|
|
111
|
+
const idx = findPlaywrightToken(cmd);
|
|
112
|
+
if (idx === null)
|
|
113
|
+
return { command: [...cmd], selector: [] };
|
|
114
|
+
const command = cmd.slice(0, idx + 1);
|
|
115
|
+
const selector = [];
|
|
116
|
+
for (let i = idx + 1; i < cmd.length; i++) {
|
|
117
|
+
const token = cmd[i];
|
|
118
|
+
if (token === 'test' && i === idx + 1) {
|
|
119
|
+
command.push(token);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (!token.startsWith('-')) {
|
|
123
|
+
selector.push(token);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (token.includes('=')) {
|
|
127
|
+
command.push(token);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const next = cmd[i + 1];
|
|
131
|
+
if (PLAYWRIGHT_VALUE_FLAGS.has(token) &&
|
|
132
|
+
next !== undefined &&
|
|
133
|
+
!next.startsWith('-')) {
|
|
134
|
+
command.push(`${token}=${next}`);
|
|
135
|
+
i++;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
command.push(token);
|
|
139
|
+
}
|
|
140
|
+
return { command, selector };
|
|
141
|
+
}
|
|
142
|
+
export const playwrightAdapter = {
|
|
143
|
+
name: ADAPTER_NAME,
|
|
144
|
+
compositionId: COMPOSITION_ID,
|
|
145
|
+
declaredCapabilities: PLAYWRIGHT_CAPABILITIES,
|
|
146
|
+
declaredEnvVars: DECLARED_ENV_VARS,
|
|
147
|
+
detect(argv) {
|
|
148
|
+
const i = findPlaywrightToken(argv);
|
|
149
|
+
return i === null ? null : { tokenIndex: i };
|
|
150
|
+
},
|
|
151
|
+
channelEnv,
|
|
152
|
+
instrument(argv, channel) {
|
|
153
|
+
return {
|
|
154
|
+
argv: [...argv, `--reporter=list,${reporterModulePath()}`],
|
|
155
|
+
env: channelEnv(channel),
|
|
156
|
+
};
|
|
157
|
+
},
|
|
158
|
+
splitCommandSelector,
|
|
159
|
+
claimsCapture(channel) {
|
|
160
|
+
// Authorship only, from the payload's own self-identification
|
|
161
|
+
// (`capture.ts` — a literal `'playwright'`). Not a version/shape check:
|
|
162
|
+
// a capture this adapter wrote but cannot read must reach `record` so
|
|
163
|
+
// the run degrades with *that* diagnostic instead of the generic
|
|
164
|
+
// "is the child a playwright invocation?" (same division as vitest's).
|
|
165
|
+
return readCapture(channel)?.runner === 'playwright';
|
|
166
|
+
},
|
|
167
|
+
record(channel, ctx) {
|
|
168
|
+
const capture = readCapture(channel);
|
|
169
|
+
if (capture === undefined) {
|
|
170
|
+
throw new AdapterCaptureError('no capture from the playwright reporter — is the child a playwright invocation?');
|
|
171
|
+
}
|
|
172
|
+
return buildRunRecord(capture, ctx);
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/adapters/playwright/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture interchange format between the in-process playwright reporter and
|
|
3
|
+
* the out-of-process recorder (`vdelta run`). Raw structured-channel data
|
|
4
|
+
* only; canonicalization/redaction/digesting happen in the recorder (mirrors
|
|
5
|
+
* `../vitest/capture.ts`). Field names diverge where playwright's structured
|
|
6
|
+
* channel differs from vitest's: test IDs are project-scoped
|
|
7
|
+
* (`TestCase.id`), results are per-attempt (retries produce multiple
|
|
8
|
+
* `onTestEnd` calls for the same test), and dependency-skip cascades can
|
|
9
|
+
* leave whole projects unreported (`unreported_tests`).
|
|
10
|
+
*/
|
|
11
|
+
export declare const CAPTURE_VERSION = 1;
|
|
12
|
+
export interface CapturedPwFrame {
|
|
13
|
+
file: string;
|
|
14
|
+
line: number;
|
|
15
|
+
column: number;
|
|
16
|
+
}
|
|
17
|
+
export interface CapturedPwError {
|
|
18
|
+
message: string;
|
|
19
|
+
stack?: string;
|
|
20
|
+
location?: {
|
|
21
|
+
file: string;
|
|
22
|
+
line: number;
|
|
23
|
+
column: number;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Deterministically parsed from `stack` (named `at symbol (file:line:col)`
|
|
27
|
+
* frames only — see `parseStackFrames` in `reporter.ts`). Used by the
|
|
28
|
+
* recorder to reconstruct a line-shift-stable failing source region
|
|
29
|
+
* without relying on the runner's rendered `snippet` (CE-4).
|
|
30
|
+
*/
|
|
31
|
+
frames: CapturedPwFrame[];
|
|
32
|
+
}
|
|
33
|
+
export interface CapturedPwAttachment {
|
|
34
|
+
name: string;
|
|
35
|
+
content_type: string;
|
|
36
|
+
/**
|
|
37
|
+
* sha256 hex digest of the attachment body (from `body` if present,
|
|
38
|
+
* otherwise read from `path`). `null` when neither is readable. The
|
|
39
|
+
* absolute path string itself is never carried into the capture.
|
|
40
|
+
*/
|
|
41
|
+
body_digest: string | null;
|
|
42
|
+
}
|
|
43
|
+
export interface CapturedPwAttempt {
|
|
44
|
+
status: 'passed' | 'failed' | 'timedOut' | 'skipped' | 'interrupted';
|
|
45
|
+
retry: number;
|
|
46
|
+
errors: CapturedPwError[];
|
|
47
|
+
stdio: {
|
|
48
|
+
type: 'stdout' | 'stderr';
|
|
49
|
+
text: string;
|
|
50
|
+
}[];
|
|
51
|
+
attachments: CapturedPwAttachment[];
|
|
52
|
+
duration_ms: number;
|
|
53
|
+
}
|
|
54
|
+
interface CapturedPwTestMeta {
|
|
55
|
+
test_case_id: string;
|
|
56
|
+
file_abs: string;
|
|
57
|
+
project: string;
|
|
58
|
+
/** `titlePath()` with the leading `''` / project / file entries removed. */
|
|
59
|
+
titles: string[];
|
|
60
|
+
location_line: number | null;
|
|
61
|
+
expected_status: 'passed' | 'failed' | 'timedOut' | 'skipped' | 'interrupted';
|
|
62
|
+
annotations: {
|
|
63
|
+
type: string;
|
|
64
|
+
description?: string;
|
|
65
|
+
}[];
|
|
66
|
+
}
|
|
67
|
+
export interface CapturedPwTest extends CapturedPwTestMeta {
|
|
68
|
+
attempts: CapturedPwAttempt[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A `TestCase` that `allTests()` enumerates but that never reached
|
|
72
|
+
* `onTestEnd` (e.g. blocked by a failed `dependencies` project). No attempts
|
|
73
|
+
* exist for it, so it carries the same identifying fields as
|
|
74
|
+
* `CapturedPwTest` minus `attempts`.
|
|
75
|
+
*/
|
|
76
|
+
export type CapturedPwUnreportedTest = CapturedPwTestMeta;
|
|
77
|
+
export interface CapturedPwProjectConfig {
|
|
78
|
+
name: string;
|
|
79
|
+
/** `RegExp`/array entries safe-serialized (`.toString()`), see `safeSerialize`. */
|
|
80
|
+
testMatch: unknown;
|
|
81
|
+
testIgnore: unknown;
|
|
82
|
+
dependencies: string[];
|
|
83
|
+
retries: number;
|
|
84
|
+
timeout: number;
|
|
85
|
+
/** `use` safe-serialized; may contain absolute paths (e.g. `launchOptions.executablePath`). */
|
|
86
|
+
use: unknown;
|
|
87
|
+
}
|
|
88
|
+
export interface Capture {
|
|
89
|
+
capture_version: number;
|
|
90
|
+
runner: 'playwright';
|
|
91
|
+
runner_version: string;
|
|
92
|
+
status: 'passed' | 'failed' | 'timedout' | 'interrupted';
|
|
93
|
+
unhandled_errors: number;
|
|
94
|
+
/**
|
|
95
|
+
* Only the fields `docs/compositions/playwright-native-1.md` §4 judges
|
|
96
|
+
* `yes` (evidence-affecting / test-selection-affecting). `reporter` is
|
|
97
|
+
* omitted (§4 `no`); `testDir`/`rootDir`/`configFile` are omitted (§4 `no`
|
|
98
|
+
* — absolute-path administrative values, see `config_files` instead).
|
|
99
|
+
*/
|
|
100
|
+
config: {
|
|
101
|
+
fullyParallel: boolean;
|
|
102
|
+
workers: number;
|
|
103
|
+
shard: {
|
|
104
|
+
total: number;
|
|
105
|
+
current: number;
|
|
106
|
+
} | null;
|
|
107
|
+
forbidOnly: boolean;
|
|
108
|
+
maxFailures: number;
|
|
109
|
+
grep: unknown;
|
|
110
|
+
grepInvert: unknown;
|
|
111
|
+
globalTimeout: number;
|
|
112
|
+
projects: CapturedPwProjectConfig[];
|
|
113
|
+
};
|
|
114
|
+
tests: CapturedPwTest[];
|
|
115
|
+
unreported_tests: CapturedPwUnreportedTest[];
|
|
116
|
+
/** `[config.configFile]` when playwright resolved one, else `[]`. */
|
|
117
|
+
config_files: string[];
|
|
118
|
+
}
|
|
119
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture interchange format between the in-process playwright reporter and
|
|
3
|
+
* the out-of-process recorder (`vdelta run`). Raw structured-channel data
|
|
4
|
+
* only; canonicalization/redaction/digesting happen in the recorder (mirrors
|
|
5
|
+
* `../vitest/capture.ts`). Field names diverge where playwright's structured
|
|
6
|
+
* channel differs from vitest's: test IDs are project-scoped
|
|
7
|
+
* (`TestCase.id`), results are per-attempt (retries produce multiple
|
|
8
|
+
* `onTestEnd` calls for the same test), and dependency-skip cascades can
|
|
9
|
+
* leave whole projects unreported (`unreported_tests`).
|
|
10
|
+
*/
|
|
11
|
+
export const CAPTURE_VERSION = 1;
|
|
12
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../../src/adapters/playwright/capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { AdapterCaptureError, type CapabilityDeclaration, type RecordContext } from '../../adapter.js';
|
|
2
|
+
import { type RunRecord } from '../../schema.js';
|
|
3
|
+
import { type Capture } from './capture.js';
|
|
4
|
+
export declare const ADAPTER_NAME = "playwright";
|
|
5
|
+
export declare const COMPOSITION_ID = "playwright-native/1";
|
|
6
|
+
/** Env vars whose values (fingerprinted, never stored) are comparison-relevant. */
|
|
7
|
+
export declare const DECLARED_ENV_VARS: readonly ["CI", "NODE_ENV", "TZ", "LANG"];
|
|
8
|
+
/**
|
|
9
|
+
* A capture the recorder cannot turn into a record: unsupported capture
|
|
10
|
+
* version, or an ambiguity it refuses to guess through (§12 fail-closed).
|
|
11
|
+
* A subtype of `AdapterCaptureError` so the core degrades to raw passthrough
|
|
12
|
+
* (INV-5) without knowing which adapter raised it.
|
|
13
|
+
*/
|
|
14
|
+
export declare class RecorderError extends AdapterCaptureError {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
/** Re-exported from the seam: the context shape is runner-neutral (§4.1). */
|
|
18
|
+
export type { RecordContext };
|
|
19
|
+
/**
|
|
20
|
+
* Capability declaration for `playwright-native/1`
|
|
21
|
+
* (docs/compositions/playwright-native-1.md §8, decision 6). Unlike vitest,
|
|
22
|
+
* `source-region-text` is `pass` (tree-reconstructed — provenance below), and
|
|
23
|
+
* `retry-evidence` is `pass` (per-attempt evidence lands in
|
|
24
|
+
* `FailureFinding.annex.attempts`). `resolved-config-coverage` is
|
|
25
|
+
* `unsupported`: playwright's resolved `FullConfig`/`FullProject` never
|
|
26
|
+
* expose `expect.timeout` to the reporter (doc §4 `expect.timeout` row),
|
|
27
|
+
* so `instrumentConfigDigest` below cannot cover it. This capability is
|
|
28
|
+
* intentionally not one of `schema.ts`'s `EVIDENCE_CAPABILITY_NAMES` — it is
|
|
29
|
+
* an instrument-config capability, not an evidence capability, so a report's
|
|
30
|
+
* `failure_evidence.degraded_capabilities` never lists it (decision 6).
|
|
31
|
+
*/
|
|
32
|
+
export declare const PLAYWRIGHT_CAPABILITIES: CapabilityDeclaration;
|
|
33
|
+
export declare function buildRunRecord(capture: Capture, ctx: RecordContext): RunRecord;
|
|
34
|
+
/**
|
|
35
|
+
* The §4-judged-`yes` covering set (docs/compositions/playwright-native-1.md
|
|
36
|
+
* §4): every field the resolved `FullConfig`/`FullProject` exposes that can
|
|
37
|
+
* change evidence bytes or test-selection verdicts. `testDir`/`rootDir`/
|
|
38
|
+
* `configFile`/`reporter` are `no` in the judgement table and are absent from
|
|
39
|
+
* `Capture['config']`/`CapturedPwProjectConfig` by construction (never
|
|
40
|
+
* captured at all — see `./capture.ts`), so no extra filtering is needed
|
|
41
|
+
* here. `expect.timeout` is `channel-unavailable` (§4) and is likewise absent
|
|
42
|
+
* from the capture; it is disclosed instead via
|
|
43
|
+
* `PLAYWRIGHT_CAPABILITIES['resolved-config-coverage'] === 'unsupported'`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function instrumentConfigDigest(capture: Capture): string;
|
|
46
|
+
/**
|
|
47
|
+
* Project-scoped test id: `${rel}::${project}::${titles.join(' > ')}`.
|
|
48
|
+
* `rel` is computed here (not carried in the capture) because the reporter
|
|
49
|
+
* runs in-process without the worktree root; only the recorder — which has
|
|
50
|
+
* `RecordContext.worktree` — can normalize `file_abs` into a worktree-relative
|
|
51
|
+
* path.
|
|
52
|
+
*/
|
|
53
|
+
export declare function testId(t: {
|
|
54
|
+
file_abs: string;
|
|
55
|
+
project: string;
|
|
56
|
+
titles: readonly string[];
|
|
57
|
+
}, worktree: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Normalizes an absolute path into a `surface.config_sources`/test-file key:
|
|
60
|
+
* a worktree-relative POSIX-style path when the file lives inside the
|
|
61
|
+
* worktree, or `external:<abs path>` when it doesn't. Private duplicate of
|
|
62
|
+
* `../vitest/recorder.ts`'s `configSourceKey` (same convention) — the vitest
|
|
63
|
+
* module is not imported from here, and is not modified by this file.
|
|
64
|
+
*/
|
|
65
|
+
export declare function configSourceKey(absPath: string, worktree: string): string;
|