@aplaytest/runner-playwright 0.1.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/.tsbuildinfo +1 -0
- package/dist/api-fixtures.d.ts +71 -0
- package/dist/api-fixtures.d.ts.map +1 -0
- package/dist/api-fixtures.js +162 -0
- package/dist/api-fixtures.js.map +1 -0
- package/dist/assemble.d.ts +86 -0
- package/dist/assemble.d.ts.map +1 -0
- package/dist/assemble.js +176 -0
- package/dist/assemble.js.map +1 -0
- package/dist/bind.d.ts +43 -0
- package/dist/bind.d.ts.map +1 -0
- package/dist/bind.js +112 -0
- package/dist/bind.js.map +1 -0
- package/dist/fixtures.d.ts +54 -0
- package/dist/fixtures.d.ts.map +1 -0
- package/dist/fixtures.js +210 -0
- package/dist/fixtures.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/reporter.d.ts +79 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +277 -0
- package/dist/reporter.js.map +1 -0
- package/dist/sidecar.d.ts +134 -0
- package/dist/sidecar.d.ts.map +1 -0
- package/dist/sidecar.js +111 -0
- package/dist/sidecar.js.map +1 -0
- package/dist/spawn.d.ts +57 -0
- package/dist/spawn.d.ts.map +1 -0
- package/dist/spawn.js +170 -0
- package/dist/spawn.js.map +1 -0
- package/dist/steps.d.ts +45 -0
- package/dist/steps.d.ts.map +1 -0
- package/dist/steps.js +106 -0
- package/dist/steps.js.map +1 -0
- package/dist-cjs/.tsbuildinfo +1 -0
- package/dist-cjs/api-fixtures.js +166 -0
- package/dist-cjs/api-fixtures.js.map +1 -0
- package/dist-cjs/assemble.js +181 -0
- package/dist-cjs/assemble.js.map +1 -0
- package/dist-cjs/bind.js +117 -0
- package/dist-cjs/bind.js.map +1 -0
- package/dist-cjs/fixtures.js +215 -0
- package/dist-cjs/fixtures.js.map +1 -0
- package/dist-cjs/index.js +64 -0
- package/dist-cjs/index.js.map +1 -0
- package/dist-cjs/package.json +3 -0
- package/dist-cjs/reporter.js +282 -0
- package/dist-cjs/reporter.js.map +1 -0
- package/dist-cjs/sidecar.js +116 -0
- package/dist-cjs/sidecar.js.map +1 -0
- package/dist-cjs/spawn.js +174 -0
- package/dist-cjs/spawn.js.map +1 -0
- package/dist-cjs/steps.js +112 -0
- package/dist-cjs/steps.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The atest Playwright reporter.
|
|
4
|
+
*
|
|
5
|
+
* INVARIANT: this reporter must never change a run's verdict. It reports no
|
|
6
|
+
* status from `onEnd`, swallows its own errors to stderr, and does its I/O
|
|
7
|
+
* after the run rather than inside it. If atest breaks, the suite still tells
|
|
8
|
+
* the truth about the application — that property is what makes adopting it a
|
|
9
|
+
* one-line, revertible change.
|
|
10
|
+
*
|
|
11
|
+
* Work is COLLECTED in `onTestEnd` (synchronous, cheap: a couple of object
|
|
12
|
+
* references) and FLUSHED in `onEnd` (asynchronous: attachment reads, JSON
|
|
13
|
+
* writes). Playwright's `onTestEnd` cannot await, and doing file I/O per test
|
|
14
|
+
* inside a parallel run is exactly the kind of overhead that would make people
|
|
15
|
+
* turn the tool off.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.ATEST_VERSION = void 0;
|
|
19
|
+
exports.runFileName = runFileName;
|
|
20
|
+
const promises_1 = require("node:fs/promises");
|
|
21
|
+
const promises_2 = require("node:fs/promises");
|
|
22
|
+
const node_path_1 = require("node:path");
|
|
23
|
+
const core_1 = require("@aplaytest/core");
|
|
24
|
+
Object.defineProperty(exports, "ATEST_VERSION", { enumerable: true, get: function () { return core_1.ATEST_VERSION; } });
|
|
25
|
+
const assemble_js_1 = require("./assemble.js");
|
|
26
|
+
const sidecar_js_1 = require("./sidecar.js");
|
|
27
|
+
const DEFAULTS = {
|
|
28
|
+
evidenceDir: '.atest/evidence',
|
|
29
|
+
runsDir: '.atest/runs',
|
|
30
|
+
retainRuns: 50,
|
|
31
|
+
redactKeys: ['password', 'token', 'authorization', 'cookie', 'secret', 'api-key'],
|
|
32
|
+
};
|
|
33
|
+
function toOutcome(status) {
|
|
34
|
+
switch (status) {
|
|
35
|
+
case 'passed':
|
|
36
|
+
return 'passed';
|
|
37
|
+
case 'failed':
|
|
38
|
+
return 'failed';
|
|
39
|
+
case 'timedOut':
|
|
40
|
+
return 'timedOut';
|
|
41
|
+
case 'skipped':
|
|
42
|
+
return 'skipped';
|
|
43
|
+
case 'interrupted':
|
|
44
|
+
return 'interrupted';
|
|
45
|
+
default:
|
|
46
|
+
return 'failed';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function warn(message) {
|
|
50
|
+
process.stderr.write(`[atest] ${message}\n`);
|
|
51
|
+
}
|
|
52
|
+
class AtestReporter {
|
|
53
|
+
options;
|
|
54
|
+
collected = [];
|
|
55
|
+
workerTests = new Map();
|
|
56
|
+
config;
|
|
57
|
+
runId = '';
|
|
58
|
+
startedAt = '';
|
|
59
|
+
enabled = true;
|
|
60
|
+
constructor(options = {}) {
|
|
61
|
+
this.options = options;
|
|
62
|
+
}
|
|
63
|
+
/** We add a short footer only; other reporters own the main output. */
|
|
64
|
+
printsToStdio() {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
onBegin(config) {
|
|
68
|
+
this.config = config;
|
|
69
|
+
this.enabled = this.options.enabled ?? process.env['ATEST'] !== '0';
|
|
70
|
+
this.startedAt = new Date().toISOString();
|
|
71
|
+
const fromOptions = typeof this.options.runId === 'function' ? this.options.runId() : this.options.runId;
|
|
72
|
+
// Environment wins over config, deliberately. Every shard of a CI run must
|
|
73
|
+
// share one run id, and only the runtime knows it — a value baked into
|
|
74
|
+
// playwright.config.ts cannot vary per invocation, so config-wins would
|
|
75
|
+
// make sharded runs silently collapse into a single overwritten record.
|
|
76
|
+
this.runId =
|
|
77
|
+
process.env['ATEST_RUN_ID'] ??
|
|
78
|
+
fromOptions ??
|
|
79
|
+
`${this.startedAt.replace(/[:.]/g, '-')}-${process.pid}`;
|
|
80
|
+
}
|
|
81
|
+
onTestEnd(test, result) {
|
|
82
|
+
if (!this.enabled)
|
|
83
|
+
return;
|
|
84
|
+
// Cheap and synchronous by design — two references and a string push.
|
|
85
|
+
this.collected.push({ test, result });
|
|
86
|
+
const onWorker = this.workerTests.get(result.workerIndex) ?? [];
|
|
87
|
+
onWorker.push(test.id);
|
|
88
|
+
this.workerTests.set(result.workerIndex, onWorker);
|
|
89
|
+
}
|
|
90
|
+
async onEnd(_result) {
|
|
91
|
+
if (!this.enabled)
|
|
92
|
+
return;
|
|
93
|
+
try {
|
|
94
|
+
await this.flush();
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
// A reporting failure must never become a test failure.
|
|
98
|
+
warn(`failed to write evidence: ${error instanceof Error ? error.message : String(error)}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async flush() {
|
|
102
|
+
const evidenceStore = new core_1.EvidenceStore({
|
|
103
|
+
dir: this.options.evidenceDir ?? DEFAULTS.evidenceDir,
|
|
104
|
+
redactKeys: this.options.redactKeys ?? DEFAULTS.redactKeys,
|
|
105
|
+
retainRuns: this.options.retainRuns ?? DEFAULTS.retainRuns,
|
|
106
|
+
});
|
|
107
|
+
const attempts = [];
|
|
108
|
+
let bundlesWritten = 0;
|
|
109
|
+
for (const { test, result } of this.collected) {
|
|
110
|
+
const outcome = toOutcome(result.status);
|
|
111
|
+
// Playwright names the implicit project '' when a config declares no
|
|
112
|
+
// projects. Empty string is a poor grouping key: it is part of the
|
|
113
|
+
// scoring key and the evidence id, and it reads as missing data in
|
|
114
|
+
// every report.
|
|
115
|
+
const projectName = test.parent.project()?.name;
|
|
116
|
+
const project = projectName === undefined || projectName === '' ? 'default' : projectName;
|
|
117
|
+
const traceId = this.options.traceId?.({ id: test.id }, result.retry) ?? null;
|
|
118
|
+
let failureKind = null;
|
|
119
|
+
let evidenceIdValue = null;
|
|
120
|
+
// Coverage is read for EVERY attempt, not only failures: what a passing
|
|
121
|
+
// test visited is precisely what future selection needs.
|
|
122
|
+
const coverage = await this.readCoverage(result);
|
|
123
|
+
if ((0, core_1.isFailure)(outcome)) {
|
|
124
|
+
try {
|
|
125
|
+
const sidecars = await this.readSidecars(result);
|
|
126
|
+
const bundle = (0, assemble_js_1.assembleBundle)({
|
|
127
|
+
test: {
|
|
128
|
+
id: test.id,
|
|
129
|
+
title: test.title,
|
|
130
|
+
titlePath: () => test.titlePath(),
|
|
131
|
+
location: { file: test.location.file, line: test.location.line },
|
|
132
|
+
tags: test.tags,
|
|
133
|
+
},
|
|
134
|
+
result: result,
|
|
135
|
+
sidecars,
|
|
136
|
+
context: {
|
|
137
|
+
runId: this.runId,
|
|
138
|
+
traceId,
|
|
139
|
+
project,
|
|
140
|
+
shard: this.config?.shard ?? null,
|
|
141
|
+
workers: this.config?.workers ?? 1,
|
|
142
|
+
appEnv: process.env['APP_ENV'] ?? 'unknown',
|
|
143
|
+
baseUrl: process.env['BASE_URL'] ?? '',
|
|
144
|
+
browser: project,
|
|
145
|
+
platform: process.platform,
|
|
146
|
+
commit: process.env['GITHUB_SHA'] ?? '',
|
|
147
|
+
changedPaths: [],
|
|
148
|
+
timeoutMs: test.timeout,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
await evidenceStore.write(bundle);
|
|
152
|
+
bundlesWritten += 1;
|
|
153
|
+
failureKind = bundle.failure.kind;
|
|
154
|
+
evidenceIdValue = bundle.id;
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
if (error instanceof sidecar_js_1.SidecarParseError) {
|
|
158
|
+
// Loud, named, and actionable — a drifted contract is a bug in the
|
|
159
|
+
// fixtures, not something to paper over with an empty bundle.
|
|
160
|
+
warn(error.message);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
warn(`could not build evidence for "${test.title}": ` +
|
|
164
|
+
`${error instanceof Error ? error.message : String(error)}`);
|
|
165
|
+
}
|
|
166
|
+
failureKind = (0, assemble_js_1.classifyResult)(result, EMPTY, test.timeout).kind;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
attempts.push({
|
|
170
|
+
testId: test.id,
|
|
171
|
+
title: test.title,
|
|
172
|
+
titlePath: test.titlePath(),
|
|
173
|
+
file: test.location.file,
|
|
174
|
+
line: test.location.line,
|
|
175
|
+
project,
|
|
176
|
+
tags: test.tags,
|
|
177
|
+
retry: result.retry,
|
|
178
|
+
outcome,
|
|
179
|
+
failureKind,
|
|
180
|
+
durationMs: result.duration,
|
|
181
|
+
workerIndex: result.workerIndex,
|
|
182
|
+
shard: this.config?.shard ?? null,
|
|
183
|
+
traceId,
|
|
184
|
+
evidenceId: evidenceIdValue,
|
|
185
|
+
coScheduled: (this.workerTests.get(result.workerIndex) ?? []).filter(id => id !== test.id),
|
|
186
|
+
routes: coverage,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
const run = {
|
|
190
|
+
schemaVersion: core_1.RUN_SCHEMA_VERSION,
|
|
191
|
+
runId: this.runId,
|
|
192
|
+
startedAt: this.startedAt,
|
|
193
|
+
finishedAt: new Date().toISOString(),
|
|
194
|
+
commit: process.env['GITHUB_SHA'] ?? null,
|
|
195
|
+
branch: process.env['GITHUB_REF_NAME'] ?? null,
|
|
196
|
+
appEnv: process.env['APP_ENV'] ?? null,
|
|
197
|
+
ci: process.env['CI'] === 'true' || process.env['CI'] === '1',
|
|
198
|
+
workers: this.config?.workers ?? 1,
|
|
199
|
+
shard: this.config?.shard ?? null,
|
|
200
|
+
atestVersion: core_1.ATEST_VERSION,
|
|
201
|
+
playwrightVersion: this.config?.version ?? null,
|
|
202
|
+
attempts,
|
|
203
|
+
};
|
|
204
|
+
const runPath = (0, node_path_1.join)(this.options.runsDir ?? DEFAULTS.runsDir, runFileName(this.runId, run.shard, attempts.map(a => a.project)));
|
|
205
|
+
await (0, promises_2.mkdir)((0, node_path_1.dirname)(runPath), { recursive: true });
|
|
206
|
+
await (0, promises_2.writeFile)(runPath, `${JSON.stringify(run, null, 2)}\n`, 'utf8');
|
|
207
|
+
await evidenceStore.prune();
|
|
208
|
+
const failures = attempts.filter(a => (0, core_1.isFailure)(a.outcome)).length;
|
|
209
|
+
if (failures > 0) {
|
|
210
|
+
warn(`${bundlesWritten}/${failures} failures captured → ${runPath}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async readAttachment(result, name) {
|
|
214
|
+
const attachment = result.attachments.find(a => a.name === name);
|
|
215
|
+
if (attachment === undefined)
|
|
216
|
+
return undefined;
|
|
217
|
+
if (attachment.body !== undefined)
|
|
218
|
+
return attachment.body.toString('utf8');
|
|
219
|
+
if (attachment.path !== undefined)
|
|
220
|
+
return (0, promises_1.readFile)(attachment.path, 'utf8').catch(() => undefined);
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
async readCoverage(result) {
|
|
224
|
+
try {
|
|
225
|
+
const parsed = (0, sidecar_js_1.parseSidecar)(sidecar_js_1.SIDECAR.coverage, await this.readAttachment(result, sidecar_js_1.SIDECAR.coverage));
|
|
226
|
+
return parsed?.routes ?? [];
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
// A drifted coverage sidecar must not cost us the attempt record.
|
|
230
|
+
warn(error instanceof Error ? error.message : String(error));
|
|
231
|
+
return [];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
async readSidecars(result) {
|
|
235
|
+
const read = (name) => this.readAttachment(result, name);
|
|
236
|
+
return {
|
|
237
|
+
page: (0, sidecar_js_1.parseSidecar)(sidecar_js_1.SIDECAR.page, await read(sidecar_js_1.SIDECAR.page)),
|
|
238
|
+
network: (0, sidecar_js_1.parseSidecar)(sidecar_js_1.SIDECAR.network, await read(sidecar_js_1.SIDECAR.network)),
|
|
239
|
+
console: (0, sidecar_js_1.parseSidecar)(sidecar_js_1.SIDECAR.console, await read(sidecar_js_1.SIDECAR.console)),
|
|
240
|
+
intent: (0, sidecar_js_1.parseSidecar)(sidecar_js_1.SIDECAR.intent, await read(sidecar_js_1.SIDECAR.intent)),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
exports.default = AtestReporter;
|
|
245
|
+
const EMPTY = { page: null, network: null, console: null, intent: null };
|
|
246
|
+
/**
|
|
247
|
+
* One file per INVOCATION, not per run.
|
|
248
|
+
*
|
|
249
|
+
* Naming the file `<runId>.json` looks right until the suite is sharded, and
|
|
250
|
+
* then it silently destroys almost all of the data. Every shard shares one run
|
|
251
|
+
* id on purpose — that is how they get merged — so every shard wrote the same
|
|
252
|
+
* filename. Measured on a three-shard run: shards 1 and 2 recorded their
|
|
253
|
+
* attempts, shard 3 had no tests to run, and its empty record overwrote both.
|
|
254
|
+
* The surviving file reported `attempts: 0` for a run that passed four tests.
|
|
255
|
+
*
|
|
256
|
+
* It survives the upload too. CI downloads shard artifacts with
|
|
257
|
+
* `merge-multiple: true`, which flattens them into one directory — identical
|
|
258
|
+
* names collide there as well, so a 6-shard × 9-project matrix would keep one
|
|
259
|
+
* file in fifty-four.
|
|
260
|
+
*
|
|
261
|
+
* Shard and project both go in the name because their matrix varies both, and
|
|
262
|
+
* two jobs differing only by project would otherwise still collide.
|
|
263
|
+
*/
|
|
264
|
+
function runFileName(runId, shard, projects) {
|
|
265
|
+
const parts = [runId];
|
|
266
|
+
if (shard !== null)
|
|
267
|
+
parts.push(`shard-${shard.current}of${shard.total}`);
|
|
268
|
+
const distinct = [...new Set(projects)].sort();
|
|
269
|
+
if (distinct.length === 1 && distinct[0] !== undefined)
|
|
270
|
+
parts.push(distinct[0]);
|
|
271
|
+
else if (distinct.length > 1)
|
|
272
|
+
parts.push(shortHash(distinct.join(',')));
|
|
273
|
+
return `${parts.join('-').replace(/[^A-Za-z0-9._-]/g, '_')}.json`;
|
|
274
|
+
}
|
|
275
|
+
/** djb2, base36. Deterministic — re-ingesting the same file must be idempotent. */
|
|
276
|
+
function shortHash(input) {
|
|
277
|
+
let hash = 5381;
|
|
278
|
+
for (let i = 0; i < input.length; i += 1)
|
|
279
|
+
hash = ((hash * 33) ^ input.charCodeAt(i)) >>> 0;
|
|
280
|
+
return hash.toString(36).padStart(7, '0').slice(0, 7);
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAoTH,kCAaC;AA/TD,+CAA4C;AAC5C,+CAAoD;AACpD,yCAA0C;AAU1C,0CAUyB;AAKhB,8FAdP,oBAAa,OAcO;AAHtB,+CAAmG;AACnG,6CAAwE;AAsBxE,MAAM,QAAQ,GAAG;IACf,WAAW,EAAE,iBAAiB;IAC9B,OAAO,EAAE,aAAa;IACtB,UAAU,EAAE,EAAE;IACd,UAAU,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAU;CAC3F,CAAC;AAEF,SAAS,SAAS,CAAC,MAA4B;IAC7C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,UAAU;YACb,OAAO,UAAU,CAAC;QACpB,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;QACnB,KAAK,aAAa;YAChB,OAAO,aAAa,CAAC;QACvB;YACE,OAAO,QAAQ,CAAC;IACpB,CAAC;AACH,CAAC;AAED,SAAS,IAAI,CAAC,OAAe;IAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,OAAO,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED,MAAqB,aAAa;IACf,OAAO,CAAuB;IAC9B,SAAS,GAA6C,EAAE,CAAC;IACzD,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEnD,MAAM,CAAyB;IAC/B,KAAK,GAAG,EAAE,CAAC;IACX,SAAS,GAAG,EAAE,CAAC;IACf,OAAO,GAAG,IAAI,CAAC;IAEvB,YAAY,UAAgC,EAAE;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,uEAAuE;IACvE,aAAa;QACX,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CAAC,MAAkB;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC;QACpE,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC1C,MAAM,WAAW,GACf,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QACvF,2EAA2E;QAC3E,uEAAuE;QACvE,wEAAwE;QACxE,wEAAwE;QACxE,IAAI,CAAC,KAAK;YACR,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;gBAC3B,WAAW;gBACX,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC7D,CAAC;IAED,SAAS,CAAC,IAAc,EAAE,MAAkB;QAC1C,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,sEAAsE;QACtE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QAChE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAmB;QAC7B,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,wDAAwD;YACxD,IAAI,CAAC,6BAA6B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,KAAK;QACjB,MAAM,aAAa,GAAG,IAAI,oBAAa,CAAC;YACtC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,QAAQ,CAAC,WAAW;YACrD,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,QAAQ,CAAC,UAAU;YAC1D,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,QAAQ,CAAC,UAAU;SAC3D,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAoB,EAAE,CAAC;QACrC,IAAI,cAAc,GAAG,CAAC,CAAC;QAEvB,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC9C,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACzC,qEAAqE;YACrE,mEAAmE;YACnE,mEAAmE;YACnE,gBAAgB;YAChB,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC;YAChD,MAAM,OAAO,GAAG,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;YAC1F,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;YAE9E,IAAI,WAAW,GAAuB,IAAI,CAAC;YAC3C,IAAI,eAAe,GAAsB,IAAI,CAAC;YAE9C,wEAAwE;YACxE,yDAAyD;YACzD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAEjD,IAAI,IAAA,gBAAS,EAAC,OAAO,CAAC,EAAE,CAAC;gBACvB,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;oBACjD,MAAM,MAAM,GAAG,IAAA,4BAAc,EAAC;wBAC5B,IAAI,EAAE;4BACJ,EAAE,EAAE,IAAI,CAAC,EAAE;4BACX,KAAK,EAAE,IAAI,CAAC,KAAK;4BACjB,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE;4BACjC,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;4BAChE,IAAI,EAAE,IAAI,CAAC,IAAI;yBAChB;wBACD,MAAM,EAAE,MAAmC;wBAC3C,QAAQ;wBACR,OAAO,EAAE;4BACP,KAAK,EAAE,IAAI,CAAC,KAAK;4BACjB,OAAO;4BACP,OAAO;4BACP,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,IAAI;4BACjC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC;4BAClC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,SAAS;4BAC3C,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE;4BACtC,OAAO,EAAE,OAAO;4BAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;4BAC1B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE;4BACvC,YAAY,EAAE,EAAE;4BAChB,SAAS,EAAE,IAAI,CAAC,OAAO;yBACxB;qBACF,CAAC,CAAC;oBAEH,MAAM,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;oBAClC,cAAc,IAAI,CAAC,CAAC;oBACpB,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;oBAClC,eAAe,GAAG,MAAM,CAAC,EAAE,CAAC;gBAC9B,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,KAAK,YAAY,8BAAiB,EAAE,CAAC;wBACvC,mEAAmE;wBACnE,8DAA8D;wBAC9D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBACtB,CAAC;yBAAM,CAAC;wBACN,IAAI,CACF,iCAAiC,IAAI,CAAC,KAAK,KAAK;4BAC9C,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC9D,CAAC;oBACJ,CAAC;oBACD,WAAW,GAAG,IAAA,4BAAc,EAAC,MAAmC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;gBAC9F,CAAC;YACH,CAAC;YAED,QAAQ,CAAC,IAAI,CAAC;gBACZ,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;gBAC3B,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;gBACxB,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;gBACxB,OAAO;gBACP,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,OAAO;gBACP,WAAW;gBACX,UAAU,EAAE,MAAM,CAAC,QAAQ;gBAC3B,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,IAAI;gBACjC,OAAO;gBACP,UAAU,EAAE,eAAe;gBAC3B,WAAW,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;gBAC1F,MAAM,EAAE,QAAQ;aACjB,CAAC,CAAC;QACL,CAAC;QAED,MAAM,GAAG,GAAc;YACrB,aAAa,EAAE,yBAAkB;YACjC,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACpC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI;YACzC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,IAAI;YAC9C,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI;YACtC,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG;YAC7D,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC;YAClC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,IAAI;YACjC,YAAY,EAAE,oBAAa;YAC3B,iBAAiB,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,IAAI,IAAI;YAC/C,QAAQ;SACT,CAAC;QAEF,MAAM,OAAO,GAAG,IAAA,gBAAI,EAClB,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,EACxC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CACjE,CAAC;QACF,MAAM,IAAA,gBAAK,EAAC,IAAA,mBAAO,EAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,MAAM,IAAA,oBAAS,EAAC,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACtE,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC;QAE5B,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAA,gBAAS,EAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QACnE,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,IAAI,CAAC,GAAG,cAAc,IAAI,QAAQ,wBAAwB,OAAO,EAAE,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,MAAkB,EAAE,IAAY;QAC3D,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACjE,IAAI,UAAU,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAC/C,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3E,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,IAAA,mBAAQ,EAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACnG,OAAO,SAAS,CAAC;IACnB,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,MAAkB;QAC3C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAA,yBAAY,EAAC,oBAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,oBAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YACnG,OAAO,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC;QAC9B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kEAAkE;YAClE,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7D,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,MAAkB;QAC3C,MAAM,IAAI,GAAG,CAAC,IAAY,EAA+B,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAE9F,OAAO;YACL,IAAI,EAAE,IAAA,yBAAY,EAAC,oBAAO,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,oBAAO,CAAC,IAAI,CAAC,CAAC;YAC1D,OAAO,EAAE,IAAA,yBAAY,EAAC,oBAAO,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,oBAAO,CAAC,OAAO,CAAC,CAAC;YACnE,OAAO,EAAE,IAAA,yBAAY,EAAC,oBAAO,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,oBAAO,CAAC,OAAO,CAAC,CAAC;YACnE,MAAM,EAAE,IAAA,yBAAY,EAAC,oBAAO,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,oBAAO,CAAC,MAAM,CAAC,CAAC;SACjE,CAAC;IACJ,CAAC;CACF;AAjND,gCAiNC;AAED,MAAM,KAAK,GAAa,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAEnF;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,WAAW,CACzB,KAAa,EACb,KAAkE,EAClE,QAA2B;IAE3B,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC;IACtB,IAAI,KAAK,KAAK,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IAEzE,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;SAC3E,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAExE,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,OAAO,CAAC;AACpE,CAAC;AAED,mFAAmF;AACnF,SAAS,SAAS,CAAC,KAAa;IAC9B,IAAI,IAAI,GAAG,IAAI,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC;QAAE,IAAI,GAAG,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC3F,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The fixture → reporter channel.
|
|
4
|
+
*
|
|
5
|
+
* A Playwright reporter runs in the main process and cannot reach into the
|
|
6
|
+
* browser. Anything only the worker knows — the ARIA snapshot, the request
|
|
7
|
+
* ledger, console output — has to travel as a test ATTACHMENT, which is the
|
|
8
|
+
* runner's own supported channel and needs no side files or IPC.
|
|
9
|
+
*
|
|
10
|
+
* Both ends import these schemas, and the reporter PARSES rather than casts.
|
|
11
|
+
* A fixture that drifts from the contract fails loudly with a named error
|
|
12
|
+
* instead of silently producing a bundle with an empty ARIA snapshot — the
|
|
13
|
+
* same reasoning behind validating mocked response bodies against wire
|
|
14
|
+
* schemas rather than trusting them.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.SidecarParseError = exports.CoverageSidecarSchema = exports.IntentSidecarSchema = exports.ConsoleSidecarSchema = exports.NetworkSidecarSchema = exports.PageSidecarSchema = exports.SIDECAR = void 0;
|
|
18
|
+
exports.parseSidecar = parseSidecar;
|
|
19
|
+
const zod_1 = require("zod");
|
|
20
|
+
exports.SIDECAR = {
|
|
21
|
+
page: 'atest:page',
|
|
22
|
+
network: 'atest:network',
|
|
23
|
+
console: 'atest:console',
|
|
24
|
+
intent: 'atest:intent',
|
|
25
|
+
coverage: 'atest:coverage',
|
|
26
|
+
};
|
|
27
|
+
exports.PageSidecarSchema = zod_1.z.object({
|
|
28
|
+
url: zod_1.z.string(),
|
|
29
|
+
title: zod_1.z.string(),
|
|
30
|
+
ariaSnapshot: zod_1.z.string(),
|
|
31
|
+
testIdsPresent: zod_1.z.array(zod_1.z.string()),
|
|
32
|
+
htmlDigest: zod_1.z.string().nullable().default(null),
|
|
33
|
+
});
|
|
34
|
+
const RequestRecordSchema = zod_1.z.object({
|
|
35
|
+
url: zod_1.z.string(),
|
|
36
|
+
method: zod_1.z.string(),
|
|
37
|
+
status: zod_1.z.number().nullable(),
|
|
38
|
+
durationMs: zod_1.z.number(),
|
|
39
|
+
failureText: zod_1.z.string().nullable().default(null),
|
|
40
|
+
schemaError: zod_1.z.string().nullable().default(null),
|
|
41
|
+
});
|
|
42
|
+
exports.NetworkSidecarSchema = zod_1.z.object({
|
|
43
|
+
failed: zod_1.z.array(RequestRecordSchema),
|
|
44
|
+
slow: zod_1.z.array(RequestRecordSchema),
|
|
45
|
+
statusCounts: zod_1.z.record(zod_1.z.string(), zod_1.z.number()),
|
|
46
|
+
});
|
|
47
|
+
exports.ConsoleSidecarSchema = zod_1.z.object({
|
|
48
|
+
errors: zod_1.z.array(zod_1.z.string()),
|
|
49
|
+
warnings: zod_1.z.array(zod_1.z.string()),
|
|
50
|
+
});
|
|
51
|
+
exports.IntentSidecarSchema = zod_1.z.object({
|
|
52
|
+
selector: zod_1.z.string().nullable().default(null),
|
|
53
|
+
selectorSource: zod_1.z
|
|
54
|
+
.object({
|
|
55
|
+
file: zod_1.z.string(),
|
|
56
|
+
line: zod_1.z.number(),
|
|
57
|
+
constantPath: zod_1.z.string(),
|
|
58
|
+
aliases: zod_1.z.array(zod_1.z.string()).default([]),
|
|
59
|
+
})
|
|
60
|
+
.nullable()
|
|
61
|
+
.default(null),
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Routes a test actually visited.
|
|
65
|
+
*
|
|
66
|
+
* The one signal that survives a fixture barrel. Static imports say every spec
|
|
67
|
+
* depends on every feature (they compose one `test` object); what a test
|
|
68
|
+
* VISITED is independent of that, and is the only thing that can narrow
|
|
69
|
+
* selection in a suite built that way.
|
|
70
|
+
*/
|
|
71
|
+
exports.CoverageSidecarSchema = zod_1.z.object({
|
|
72
|
+
routes: zod_1.z.array(zod_1.z.string()),
|
|
73
|
+
});
|
|
74
|
+
const SCHEMAS = {
|
|
75
|
+
[exports.SIDECAR.page]: exports.PageSidecarSchema,
|
|
76
|
+
[exports.SIDECAR.network]: exports.NetworkSidecarSchema,
|
|
77
|
+
[exports.SIDECAR.console]: exports.ConsoleSidecarSchema,
|
|
78
|
+
[exports.SIDECAR.intent]: exports.IntentSidecarSchema,
|
|
79
|
+
[exports.SIDECAR.coverage]: exports.CoverageSidecarSchema,
|
|
80
|
+
};
|
|
81
|
+
class SidecarParseError extends Error {
|
|
82
|
+
sidecar;
|
|
83
|
+
issues;
|
|
84
|
+
constructor(sidecar, issues) {
|
|
85
|
+
super(`Attachment "${sidecar}" does not match its schema — the atest fixtures and ` +
|
|
86
|
+
`reporter are out of sync.\n${issues}`);
|
|
87
|
+
this.sidecar = sidecar;
|
|
88
|
+
this.issues = issues;
|
|
89
|
+
this.name = 'SidecarParseError';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.SidecarParseError = SidecarParseError;
|
|
93
|
+
/**
|
|
94
|
+
* Parse a sidecar payload. Absent is fine (the fixtures are optional);
|
|
95
|
+
* PRESENT-BUT-WRONG is not, and throws.
|
|
96
|
+
*/
|
|
97
|
+
function parseSidecar(name, raw) {
|
|
98
|
+
if (raw === undefined)
|
|
99
|
+
return null;
|
|
100
|
+
let json;
|
|
101
|
+
try {
|
|
102
|
+
json = JSON.parse(raw);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
throw new SidecarParseError(name, error instanceof Error ? error.message : String(error));
|
|
106
|
+
}
|
|
107
|
+
const result = SCHEMAS[name].safeParse(json);
|
|
108
|
+
if (!result.success) {
|
|
109
|
+
const issues = result.error.issues
|
|
110
|
+
.map(i => ` • ${i.path.join('.') || '(root)'}: ${i.message}`)
|
|
111
|
+
.join('\n');
|
|
112
|
+
throw new SidecarParseError(name, issues);
|
|
113
|
+
}
|
|
114
|
+
return result.data;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=sidecar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidecar.js","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Drive `playwright test` as a child process and read structured results.
|
|
4
|
+
*
|
|
5
|
+
* Used by bisect (re-run under controlled perturbations) and by heal
|
|
6
|
+
* validation (re-run with a candidate patch applied). Both need counts, not
|
|
7
|
+
* evidence, so this uses Playwright's own JSON reporter rather than ours —
|
|
8
|
+
* fewer moving parts, and it works against a consumer repo whether or not the
|
|
9
|
+
* atest reporter is configured.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.escapeForGrep = escapeForGrep;
|
|
13
|
+
exports.runPlaywright = runPlaywright;
|
|
14
|
+
const node_child_process_1 = require("node:child_process");
|
|
15
|
+
const promises_1 = require("node:fs/promises");
|
|
16
|
+
const node_os_1 = require("node:os");
|
|
17
|
+
const node_path_1 = require("node:path");
|
|
18
|
+
/** Playwright's `-g` takes a regular expression; titles are literal text. */
|
|
19
|
+
function escapeForGrep(title) {
|
|
20
|
+
return title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
21
|
+
}
|
|
22
|
+
const RESULT_PASSED = 'passed';
|
|
23
|
+
const RESULT_FAILED = 'failed';
|
|
24
|
+
const RESULT_TIMED_OUT = 'timedOut';
|
|
25
|
+
const PLAYWRIGHT_JSON_OUTPUT = 'PLAYWRIGHT_JSON_OUTPUT_NAME';
|
|
26
|
+
function countResults(spec) {
|
|
27
|
+
let passed = 0;
|
|
28
|
+
let failed = 0;
|
|
29
|
+
let error = null;
|
|
30
|
+
for (const test of spec.tests ?? []) {
|
|
31
|
+
for (const result of test.results ?? []) {
|
|
32
|
+
if (result.status === RESULT_PASSED)
|
|
33
|
+
passed += 1;
|
|
34
|
+
else if (result.status === RESULT_FAILED || result.status === RESULT_TIMED_OUT) {
|
|
35
|
+
failed += 1;
|
|
36
|
+
error = result.error?.message ?? error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { passed, failed, error };
|
|
41
|
+
}
|
|
42
|
+
function collectSpecs(suites, file = '') {
|
|
43
|
+
const out = [];
|
|
44
|
+
for (const suite of suites ?? []) {
|
|
45
|
+
const suiteFile = suite.file ?? file;
|
|
46
|
+
for (const spec of suite.specs ?? []) {
|
|
47
|
+
out.push({ title: spec.title ?? '', file: suiteFile, ...countResults(spec) });
|
|
48
|
+
}
|
|
49
|
+
out.push(...collectSpecs(suite.suites, suiteFile));
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
function buildArgs(options) {
|
|
54
|
+
const args = ['playwright', 'test'];
|
|
55
|
+
if (options.config !== undefined)
|
|
56
|
+
args.push('--config', options.config);
|
|
57
|
+
if (options.file !== undefined)
|
|
58
|
+
args.push(options.file);
|
|
59
|
+
if (options.grepTitle !== undefined)
|
|
60
|
+
args.push('-g', escapeForGrep(options.grepTitle));
|
|
61
|
+
if (options.project !== undefined)
|
|
62
|
+
args.push('--project', options.project);
|
|
63
|
+
if (options.workers !== undefined)
|
|
64
|
+
args.push(`--workers=${options.workers}`);
|
|
65
|
+
if (options.repeatEach !== undefined)
|
|
66
|
+
args.push(`--repeat-each=${options.repeatEach}`);
|
|
67
|
+
if (options.maxFailures !== undefined)
|
|
68
|
+
args.push(`--max-failures=${options.maxFailures}`);
|
|
69
|
+
// Replaces the project's reporters for this invocation. Deliberate: bisect
|
|
70
|
+
// and validation want counts, and inheriting a consumer's HTML or blob
|
|
71
|
+
// reporter would write artifacts nobody asked for on every probe.
|
|
72
|
+
args.push('--reporter=json');
|
|
73
|
+
return args;
|
|
74
|
+
}
|
|
75
|
+
function isJsonReport(value) {
|
|
76
|
+
return typeof value === 'object' && value !== null;
|
|
77
|
+
}
|
|
78
|
+
function parseJsonReport(raw) {
|
|
79
|
+
try {
|
|
80
|
+
const parsed = JSON.parse(raw);
|
|
81
|
+
return isJsonReport(parsed) ? parsed : null;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function inconclusiveResult(exitCode, stderr) {
|
|
88
|
+
return {
|
|
89
|
+
ok: false,
|
|
90
|
+
passed: 0,
|
|
91
|
+
failed: 0,
|
|
92
|
+
flaky: 0,
|
|
93
|
+
skipped: 0,
|
|
94
|
+
durationMs: 0,
|
|
95
|
+
exitCode,
|
|
96
|
+
inconclusive: true,
|
|
97
|
+
stderr,
|
|
98
|
+
specs: [],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
async function runPlaywright(options) {
|
|
102
|
+
const dir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'atest-run-'));
|
|
103
|
+
const jsonPath = (0, node_path_1.join)(dir, 'report.json');
|
|
104
|
+
try {
|
|
105
|
+
const args = buildArgs(options);
|
|
106
|
+
const result = await new Promise(resolve => {
|
|
107
|
+
const child = (0, node_child_process_1.spawn)('npx', args, {
|
|
108
|
+
cwd: options.cwd,
|
|
109
|
+
env: {
|
|
110
|
+
...process.env,
|
|
111
|
+
...options.env,
|
|
112
|
+
[PLAYWRIGHT_JSON_OUTPUT]: jsonPath,
|
|
113
|
+
// The reporter is not wanted during a probe: bisect runs the same
|
|
114
|
+
// test dozens of times, and each run would otherwise write evidence
|
|
115
|
+
// bundles that pollute the history the analysis is reading.
|
|
116
|
+
ATEST: '0',
|
|
117
|
+
FORCE_COLOR: '0',
|
|
118
|
+
},
|
|
119
|
+
stdio: ['ignore', 'ignore', 'pipe'],
|
|
120
|
+
});
|
|
121
|
+
let stderr = '';
|
|
122
|
+
child.stderr.on('data', (chunk) => {
|
|
123
|
+
stderr += chunk.toString('utf8');
|
|
124
|
+
});
|
|
125
|
+
const timeout = options.timeoutMs === undefined
|
|
126
|
+
? null
|
|
127
|
+
: setTimeout(() => child.kill('SIGTERM'), options.timeoutMs);
|
|
128
|
+
child.on('close', code => {
|
|
129
|
+
if (timeout !== null)
|
|
130
|
+
clearTimeout(timeout);
|
|
131
|
+
resolve({ code: code ?? 1, stderr });
|
|
132
|
+
});
|
|
133
|
+
child.on('error', error => {
|
|
134
|
+
if (timeout !== null)
|
|
135
|
+
clearTimeout(timeout);
|
|
136
|
+
resolve({ code: 1, stderr: error.message });
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
const raw = await (0, promises_1.readFile)(jsonPath, 'utf8').catch(() => null);
|
|
140
|
+
if (raw === null) {
|
|
141
|
+
// No report means the run never got as far as executing tests — a config
|
|
142
|
+
// error, a missing browser. That is INCONCLUSIVE, not a failing test;
|
|
143
|
+
// counting it as a failure would make bisect blame the code under test
|
|
144
|
+
// for a broken environment.
|
|
145
|
+
return inconclusiveResult(result.code, result.stderr);
|
|
146
|
+
}
|
|
147
|
+
const report = parseJsonReport(raw);
|
|
148
|
+
if (report === null) {
|
|
149
|
+
return inconclusiveResult(result.code, `unparseable JSON report\n${result.stderr}`);
|
|
150
|
+
}
|
|
151
|
+
const stats = report.stats ?? {};
|
|
152
|
+
const passed = stats.expected ?? 0;
|
|
153
|
+
const failed = stats.unexpected ?? 0;
|
|
154
|
+
const flaky = stats.flaky ?? 0;
|
|
155
|
+
return {
|
|
156
|
+
ok: failed === 0 && passed + flaky > 0,
|
|
157
|
+
passed,
|
|
158
|
+
failed,
|
|
159
|
+
flaky,
|
|
160
|
+
skipped: stats.skipped ?? 0,
|
|
161
|
+
durationMs: stats.duration ?? 0,
|
|
162
|
+
exitCode: result.code,
|
|
163
|
+
// A run that executed nothing tells us nothing — usually a grep that
|
|
164
|
+
// matched no test, which is a caller mistake worth surfacing.
|
|
165
|
+
inconclusive: passed + failed + flaky === 0,
|
|
166
|
+
stderr: result.stderr,
|
|
167
|
+
specs: collectSpecs(report.suites),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
await (0, promises_1.rm)(dir, { recursive: true, force: true });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=spawn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn.js","sourceRoot":"","sources":["../src/spawn.ts"],"names":[],"mappings":"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"}
|