@empiricalrun/playwright-utils 0.58.1 → 0.58.3
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/CHANGELOG.md +15 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +12 -2
- package/dist/generated/api-worker-openapi.d.ts +1130 -699
- package/dist/generated/api-worker-openapi.d.ts.map +1 -1
- package/dist/reporter/harness.d.ts +80 -0
- package/dist/reporter/harness.d.ts.map +1 -1
- package/dist/reporter/harness.js +198 -34
- package/dist/reporter/ibr-utils.d.ts +6 -0
- package/dist/reporter/ibr-utils.d.ts.map +1 -1
- package/dist/reporter/ibr-utils.js +15 -1
- package/dist/reporter/incremental-blob-reporter.d.ts +13 -2
- package/dist/reporter/incremental-blob-reporter.d.ts.map +1 -1
- package/dist/reporter/incremental-blob-reporter.js +87 -33
- package/dist/reporter/lifecycle-events.d.ts +5 -3
- package/dist/reporter/lifecycle-events.d.ts.map +1 -1
- package/dist/reporter/lifecycle-events.js +54 -3
- package/dist/reporter/parity-utils.d.ts +63 -0
- package/dist/reporter/parity-utils.d.ts.map +1 -0
- package/dist/reporter/parity-utils.js +109 -0
- package/package.json +5 -5
- package/tsconfig.tsbuildinfo +1 -1
- package/upstream-oracle/README.md +48 -0
- package/upstream-oracle/ibr-adapter.js +72 -0
- package/upstream-oracle/intermediate-mode-ibr.patch +16 -0
- package/upstream-oracle/run.mjs +231 -0
|
@@ -29,6 +29,48 @@ export interface RunResult {
|
|
|
29
29
|
stderr: string;
|
|
30
30
|
}
|
|
31
31
|
export type WaitFor = "first-passed" | "first-failed";
|
|
32
|
+
/** A `@@ NAME @@` line printed by a fixture suite, with its offset from run start. */
|
|
33
|
+
export interface Marker {
|
|
34
|
+
name: string;
|
|
35
|
+
atMs: number;
|
|
36
|
+
}
|
|
37
|
+
export interface SignalRunResult extends RunResult {
|
|
38
|
+
exitCode: number | null;
|
|
39
|
+
exitSignal: NodeJS.Signals | null;
|
|
40
|
+
markers: Marker[];
|
|
41
|
+
/** Offset from run start at which the first signal was delivered. */
|
|
42
|
+
signalSentAtMs: number;
|
|
43
|
+
/** Wall clock at run start, so `atMs` offsets can be compared to file mtimes. */
|
|
44
|
+
startedAtEpochMs: number;
|
|
45
|
+
}
|
|
46
|
+
export interface SignalRunOptions {
|
|
47
|
+
workers: number;
|
|
48
|
+
/**
|
|
49
|
+
* Signal as soon as this `@@ MARKER @@` is printed. Preferred over `waitFor`:
|
|
50
|
+
* it pins the signal to a known point in the run instead of a sleep.
|
|
51
|
+
*/
|
|
52
|
+
waitForMarker?: string;
|
|
53
|
+
/** Legacy trigger: wait for the first pass/fail line in stdout. */
|
|
54
|
+
waitFor?: WaitFor;
|
|
55
|
+
/** Settling delay between the trigger and the signal. */
|
|
56
|
+
delayBeforeSignalMs?: number;
|
|
57
|
+
/** Defaults to SIGINT, which is what production sends. */
|
|
58
|
+
signal?: NodeJS.Signals;
|
|
59
|
+
/** Send the same signal again this long after the first one. */
|
|
60
|
+
secondSignalAfterMs?: number;
|
|
61
|
+
/** SIGKILL the group this long after the first signal, like the cmd.ts grace cap. */
|
|
62
|
+
killAfterMs?: number;
|
|
63
|
+
/** How long to wait for the trigger before giving up and signalling anyway. */
|
|
64
|
+
triggerTimeoutMs?: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Spawns `playwright test` with the IBR reporter in its own process group,
|
|
68
|
+
* signals the group mid-run, and waits for exit.
|
|
69
|
+
*
|
|
70
|
+
* The process group and the signal both match production: `cmd.ts` spawns the
|
|
71
|
+
* runner detached and does `process.kill(-pid, signal)`.
|
|
72
|
+
*/
|
|
73
|
+
export declare function runPlaywrightWithSignal(ctx: IBRTestContext, opts: SignalRunOptions): Promise<SignalRunResult>;
|
|
32
74
|
/**
|
|
33
75
|
* Spawns `playwright test` with the IBR reporter, waits for a test outcome,
|
|
34
76
|
* sends SIGINT, and waits for the process to exit.
|
|
@@ -39,6 +81,8 @@ export declare function runPlaywrightWithSigint(ctx: IBRTestContext, opts: {
|
|
|
39
81
|
workers: number;
|
|
40
82
|
waitFor: WaitFor;
|
|
41
83
|
}): Promise<RunResult>;
|
|
84
|
+
/** Marker names in the order they were printed. */
|
|
85
|
+
export declare function markerNames(result: SignalRunResult): string[];
|
|
42
86
|
export declare function runPlaywrightList(ctx: TestCaseSyncTestContext): Promise<RunResult>;
|
|
43
87
|
export interface BlobEvent {
|
|
44
88
|
method: string;
|
|
@@ -48,4 +92,40 @@ export interface BlobEvent {
|
|
|
48
92
|
* Reads `report.jsonl` from the blob zip and returns parsed events.
|
|
49
93
|
*/
|
|
50
94
|
export declare function readBlobEvents(ctx: IBRTestContext): Promise<BlobEvent[]>;
|
|
95
|
+
/**
|
|
96
|
+
* Reads `report.jsonl` from any blob-format zip (standard or incremental).
|
|
97
|
+
*/
|
|
98
|
+
export declare function readEventsFromZip(zipPath: string): Promise<BlobEvent[]>;
|
|
99
|
+
export interface ParityTestContext {
|
|
100
|
+
tempDir: string;
|
|
101
|
+
/** Playwright's built-in blob reporter output: blob-report/report-1.zip */
|
|
102
|
+
standardZipPath: string;
|
|
103
|
+
standardBlobDir: string;
|
|
104
|
+
/** IBR output: blob-report-incremental/incremental-report-1.zip */
|
|
105
|
+
incrementalZipPath: string;
|
|
106
|
+
incrementalBlobDir: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Sets up a fixture whose config runs BOTH the built-in blob reporter and the
|
|
110
|
+
* IBR on the same invocation, so one event stream feeds both zips.
|
|
111
|
+
*/
|
|
112
|
+
export declare function setupParityFixture(suite: string): Promise<{
|
|
113
|
+
ctx: ParityTestContext;
|
|
114
|
+
cleanup: () => Promise<void>;
|
|
115
|
+
}>;
|
|
116
|
+
export interface CleanRunResult extends RunResult {
|
|
117
|
+
exitCode: number | null;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Spawns `playwright test` and lets it run to completion — the clean-finish
|
|
121
|
+
* half of the matrix (the SIGINT helpers above cover interruption).
|
|
122
|
+
*/
|
|
123
|
+
export declare function runPlaywrightClean(ctx: ParityTestContext, opts: {
|
|
124
|
+
workers: number;
|
|
125
|
+
}): Promise<CleanRunResult>;
|
|
126
|
+
/**
|
|
127
|
+
* Runs `playwright merge-reports <blobDir> --reporter json` and returns the
|
|
128
|
+
* parsed summary. Distinct output names let one temp dir hold both merges.
|
|
129
|
+
*/
|
|
130
|
+
export declare function mergeBlobDirToSummary(cwd: string, blobDir: string, outputName: string): Record<string, unknown>;
|
|
51
131
|
//# sourceMappingURL=harness.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../../src/reporter/harness.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACzD,GAAG,EAAE,cAAc,CAAC;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC,CAaD;AAqCD,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACrE,GAAG,EAAE,uBAAuB,CAAC;IAC7B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC,CAaD;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3E;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,OAAO,GAAG,cAAc,GAAG,cAAc,CAAC;AAOtD;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC1C,OAAO,CAAC,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../../src/reporter/harness.ts"],"names":[],"mappings":"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"}
|
package/dist/reporter/harness.js
CHANGED
|
@@ -7,9 +7,15 @@ exports.sleep = sleep;
|
|
|
7
7
|
exports.setupFixture = setupFixture;
|
|
8
8
|
exports.setupTestCaseSyncFixture = setupTestCaseSyncFixture;
|
|
9
9
|
exports.cleanBlobArtifacts = cleanBlobArtifacts;
|
|
10
|
+
exports.runPlaywrightWithSignal = runPlaywrightWithSignal;
|
|
10
11
|
exports.runPlaywrightWithSigint = runPlaywrightWithSigint;
|
|
12
|
+
exports.markerNames = markerNames;
|
|
11
13
|
exports.runPlaywrightList = runPlaywrightList;
|
|
12
14
|
exports.readBlobEvents = readBlobEvents;
|
|
15
|
+
exports.readEventsFromZip = readEventsFromZip;
|
|
16
|
+
exports.setupParityFixture = setupParityFixture;
|
|
17
|
+
exports.runPlaywrightClean = runPlaywrightClean;
|
|
18
|
+
exports.mergeBlobDirToSummary = mergeBlobDirToSummary;
|
|
13
19
|
const zip_1 = require("@empiricalrun/r2-uploader/zip");
|
|
14
20
|
const child_process_1 = require("child_process");
|
|
15
21
|
const fs_1 = __importDefault(require("fs"));
|
|
@@ -85,15 +91,18 @@ const WAIT_FOR_PATTERNS = {
|
|
|
85
91
|
"first-passed": /passed|✓/,
|
|
86
92
|
"first-failed": /failed|✘|×/,
|
|
87
93
|
};
|
|
94
|
+
const MARKER_RE = /@@ ([A-Z0-9-]+) @@/g;
|
|
88
95
|
/**
|
|
89
|
-
* Spawns `playwright test` with the IBR reporter
|
|
90
|
-
*
|
|
96
|
+
* Spawns `playwright test` with the IBR reporter in its own process group,
|
|
97
|
+
* signals the group mid-run, and waits for exit.
|
|
91
98
|
*
|
|
92
|
-
*
|
|
99
|
+
* The process group and the signal both match production: `cmd.ts` spawns the
|
|
100
|
+
* runner detached and does `process.kill(-pid, signal)`.
|
|
93
101
|
*/
|
|
94
|
-
async function
|
|
95
|
-
const { workers, waitFor } = opts;
|
|
96
|
-
const
|
|
102
|
+
async function runPlaywrightWithSignal(ctx, opts) {
|
|
103
|
+
const { workers, waitForMarker, waitFor, delayBeforeSignalMs = 0, signal = "SIGINT", secondSignalAfterMs, killAfterMs, triggerTimeoutMs = 30_000, } = opts;
|
|
104
|
+
const startedAt = Date.now();
|
|
105
|
+
const since = () => Date.now() - startedAt;
|
|
97
106
|
const child = (0, child_process_1.spawn)(PLAYWRIGHT_BIN, ["test", `--workers=${workers}`], {
|
|
98
107
|
cwd: ctx.tempDir,
|
|
99
108
|
env: {
|
|
@@ -101,40 +110,120 @@ async function runPlaywrightWithSigint(ctx, opts) {
|
|
|
101
110
|
LOCAL_TEST: "false",
|
|
102
111
|
SHARD_INDEX: "1",
|
|
103
112
|
TOTAL_SHARDS: "1",
|
|
113
|
+
FORCE_COLOR: "0",
|
|
104
114
|
},
|
|
105
115
|
stdio: ["pipe", "pipe", "pipe"],
|
|
106
116
|
detached: true,
|
|
107
117
|
});
|
|
108
118
|
let stdout = "";
|
|
109
119
|
let stderr = "";
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
120
|
+
const markers = [];
|
|
121
|
+
const collect = (chunk, isStderr) => {
|
|
122
|
+
const text = chunk.toString();
|
|
123
|
+
if (isStderr) {
|
|
124
|
+
stderr += text;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
stdout += text;
|
|
128
|
+
}
|
|
129
|
+
for (const match of text.matchAll(MARKER_RE)) {
|
|
130
|
+
markers.push({ name: match[1], atMs: since() });
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
child.stdout?.on("data", (data) => collect(data, false));
|
|
134
|
+
child.stderr?.on("data", (data) => collect(data, true));
|
|
135
|
+
let exitCode = null;
|
|
136
|
+
let exitSignal = null;
|
|
137
|
+
let hasExited = false;
|
|
138
|
+
const closed = new Promise((resolve) => {
|
|
139
|
+
child.on("close", (code, sig) => {
|
|
140
|
+
hasExited = true;
|
|
141
|
+
exitCode = code;
|
|
142
|
+
exitSignal = sig;
|
|
143
|
+
resolve();
|
|
144
|
+
});
|
|
128
145
|
});
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
146
|
+
const signalGroup = (sig) => {
|
|
147
|
+
if (hasExited || !child.pid) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
process.kill(-child.pid, sig);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// The group is already gone.
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const pattern = waitFor ? WAIT_FOR_PATTERNS[waitFor] : undefined;
|
|
158
|
+
const isTriggered = () => waitForMarker
|
|
159
|
+
? markers.some((m) => m.name === waitForMarker)
|
|
160
|
+
: pattern
|
|
161
|
+
? pattern.test(stdout)
|
|
162
|
+
: true;
|
|
163
|
+
await Promise.race([
|
|
164
|
+
new Promise((resolve) => {
|
|
165
|
+
const interval = setInterval(() => {
|
|
166
|
+
if (isTriggered()) {
|
|
167
|
+
clearInterval(interval);
|
|
168
|
+
resolve();
|
|
169
|
+
}
|
|
170
|
+
}, 50);
|
|
171
|
+
setTimeout(() => {
|
|
172
|
+
clearInterval(interval);
|
|
173
|
+
resolve();
|
|
174
|
+
}, triggerTimeoutMs);
|
|
175
|
+
}),
|
|
176
|
+
closed,
|
|
177
|
+
]);
|
|
178
|
+
if (delayBeforeSignalMs > 0) {
|
|
179
|
+
await sleep(delayBeforeSignalMs);
|
|
180
|
+
}
|
|
181
|
+
const signalSentAtMs = since();
|
|
182
|
+
signalGroup(signal);
|
|
183
|
+
const timers = [];
|
|
184
|
+
if (secondSignalAfterMs !== undefined) {
|
|
185
|
+
timers.push(setTimeout(() => signalGroup(signal), secondSignalAfterMs));
|
|
186
|
+
}
|
|
187
|
+
if (killAfterMs !== undefined) {
|
|
188
|
+
timers.push(setTimeout(() => signalGroup("SIGKILL"), killAfterMs));
|
|
189
|
+
}
|
|
190
|
+
// Backstop: never leave a runner behind if the suite misbehaves.
|
|
191
|
+
timers.push(setTimeout(() => signalGroup("SIGKILL"), 120_000));
|
|
192
|
+
try {
|
|
193
|
+
await closed;
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
for (const timer of timers) {
|
|
197
|
+
clearTimeout(timer);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
stdout,
|
|
202
|
+
stderr,
|
|
203
|
+
exitCode,
|
|
204
|
+
exitSignal,
|
|
205
|
+
markers,
|
|
206
|
+
signalSentAtMs,
|
|
207
|
+
startedAtEpochMs: startedAt,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Spawns `playwright test` with the IBR reporter, waits for a test outcome,
|
|
212
|
+
* sends SIGINT, and waits for the process to exit.
|
|
213
|
+
*
|
|
214
|
+
* Returns captured stdout/stderr.
|
|
215
|
+
*/
|
|
216
|
+
async function runPlaywrightWithSigint(ctx, opts) {
|
|
217
|
+
return runPlaywrightWithSignal(ctx, {
|
|
218
|
+
workers: opts.workers,
|
|
219
|
+
waitFor: opts.waitFor,
|
|
220
|
+
// Waiting for 1 sec to ensure second test has started
|
|
221
|
+
delayBeforeSignalMs: 1_000,
|
|
136
222
|
});
|
|
137
|
-
|
|
223
|
+
}
|
|
224
|
+
/** Marker names in the order they were printed. */
|
|
225
|
+
function markerNames(result) {
|
|
226
|
+
return result.markers.map((m) => m.name);
|
|
138
227
|
}
|
|
139
228
|
async function runPlaywrightList(ctx) {
|
|
140
229
|
const child = (0, child_process_1.spawn)(PLAYWRIGHT_BIN, ["test", "--list"], {
|
|
@@ -165,9 +254,15 @@ async function runPlaywrightList(ctx) {
|
|
|
165
254
|
* Reads `report.jsonl` from the blob zip and returns parsed events.
|
|
166
255
|
*/
|
|
167
256
|
async function readBlobEvents(ctx) {
|
|
168
|
-
|
|
257
|
+
return readEventsFromZip(ctx.zipPath);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Reads `report.jsonl` from any blob-format zip (standard or incremental).
|
|
261
|
+
*/
|
|
262
|
+
async function readEventsFromZip(zipPath) {
|
|
263
|
+
const reportBuffer = await (0, zip_1.readZipEntry)(zipPath, "report.jsonl");
|
|
169
264
|
if (!reportBuffer) {
|
|
170
|
-
throw new Error(`report.jsonl not found in zip: ${
|
|
265
|
+
throw new Error(`report.jsonl not found in zip: ${zipPath}`);
|
|
171
266
|
}
|
|
172
267
|
return reportBuffer
|
|
173
268
|
.toString("utf8")
|
|
@@ -175,3 +270,72 @@ async function readBlobEvents(ctx) {
|
|
|
175
270
|
.split("\n")
|
|
176
271
|
.map((line) => JSON.parse(line));
|
|
177
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* Sets up a fixture whose config runs BOTH the built-in blob reporter and the
|
|
275
|
+
* IBR on the same invocation, so one event stream feeds both zips.
|
|
276
|
+
*/
|
|
277
|
+
async function setupParityFixture(suite) {
|
|
278
|
+
const { tempDir, cleanup } = await setupReporterFixture({
|
|
279
|
+
suite,
|
|
280
|
+
reporterPath: REPORTER_PATH,
|
|
281
|
+
tempPrefix: "blob-ibr-parity-",
|
|
282
|
+
});
|
|
283
|
+
const standardBlobDir = path_1.default.join(tempDir, "blob-report");
|
|
284
|
+
const incrementalBlobDir = path_1.default.join(tempDir, "blob-report-incremental");
|
|
285
|
+
return {
|
|
286
|
+
ctx: {
|
|
287
|
+
tempDir,
|
|
288
|
+
standardBlobDir,
|
|
289
|
+
standardZipPath: path_1.default.join(standardBlobDir, "report-1.zip"),
|
|
290
|
+
incrementalBlobDir,
|
|
291
|
+
incrementalZipPath: path_1.default.join(incrementalBlobDir, "incremental-report-1.zip"),
|
|
292
|
+
},
|
|
293
|
+
cleanup,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Spawns `playwright test` and lets it run to completion — the clean-finish
|
|
298
|
+
* half of the matrix (the SIGINT helpers above cover interruption).
|
|
299
|
+
*/
|
|
300
|
+
async function runPlaywrightClean(ctx, opts) {
|
|
301
|
+
const child = (0, child_process_1.spawn)(PLAYWRIGHT_BIN, ["test", `--workers=${opts.workers}`], {
|
|
302
|
+
cwd: ctx.tempDir,
|
|
303
|
+
env: {
|
|
304
|
+
...process.env,
|
|
305
|
+
LOCAL_TEST: "false",
|
|
306
|
+
SHARD_INDEX: "1",
|
|
307
|
+
TOTAL_SHARDS: "1",
|
|
308
|
+
FORCE_COLOR: "0",
|
|
309
|
+
},
|
|
310
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
311
|
+
});
|
|
312
|
+
let stdout = "";
|
|
313
|
+
let stderr = "";
|
|
314
|
+
child.stdout?.on("data", (data) => {
|
|
315
|
+
stdout += data.toString();
|
|
316
|
+
});
|
|
317
|
+
child.stderr?.on("data", (data) => {
|
|
318
|
+
stderr += data.toString();
|
|
319
|
+
});
|
|
320
|
+
const exitCode = await new Promise((resolve) => {
|
|
321
|
+
child.on("close", (code) => resolve(code));
|
|
322
|
+
});
|
|
323
|
+
return { stdout, stderr, exitCode };
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Runs `playwright merge-reports <blobDir> --reporter json` and returns the
|
|
327
|
+
* parsed summary. Distinct output names let one temp dir hold both merges.
|
|
328
|
+
*/
|
|
329
|
+
function mergeBlobDirToSummary(cwd, blobDir, outputName) {
|
|
330
|
+
const outputPath = path_1.default.join(cwd, outputName);
|
|
331
|
+
(0, child_process_1.execFileSync)(PLAYWRIGHT_BIN, ["merge-reports", blobDir, "--reporter", "json"], {
|
|
332
|
+
cwd,
|
|
333
|
+
env: {
|
|
334
|
+
...process.env,
|
|
335
|
+
PLAYWRIGHT_JSON_OUTPUT_NAME: outputPath,
|
|
336
|
+
FORCE_COLOR: "0",
|
|
337
|
+
},
|
|
338
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
339
|
+
});
|
|
340
|
+
return JSON.parse(fs_1.default.readFileSync(outputPath, "utf8"));
|
|
341
|
+
}
|
|
@@ -32,6 +32,12 @@ export type JsonSuite = {
|
|
|
32
32
|
location: JsonLocation;
|
|
33
33
|
entries: (JsonTestCase | JsonSuite)[];
|
|
34
34
|
};
|
|
35
|
+
export type TestAnnotation = {
|
|
36
|
+
type: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
location?: JsonLocation;
|
|
39
|
+
};
|
|
40
|
+
export declare function relativeAnnotationLocations(annotations: TestAnnotation[], rootDir: string): TestAnnotation[];
|
|
35
41
|
export declare function serializeTest(test: TestCase, rootDir: string): JsonTestCase;
|
|
36
42
|
export declare function serializeSuite(suite: Suite, rootDir: string): JsonSuite;
|
|
37
43
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ibr-utils.d.ts","sourceRoot":"","sources":["../../src/reporter/ibr-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAO3E,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC,CAAC;AAIF,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAChD,WAAW,EAAE,CAOf;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAO3E;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,EAC1B,IAAI,EAAE,QAAQ,GACb,MAAM,CAOR;AAID,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAIF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACvD,CAAC;AAIF,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,CAAC,YAAY,GAAG,SAAS,CAAC,EAAE,CAAC;CACvC,CAAC;AAIF,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,YAAY,CAc3E;AAID,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAsBvE;AAMD;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,SAAS,EAChB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,GAC5B,SAAS,GAAG,IAAI,CAqBlB;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAK7D;AAED,wBAAgB,aAAa,CAC3B,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMxB;AAED,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAI3D;AAED,wBAAgB,eAAe,CAC7B,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CAoBf"}
|
|
1
|
+
{"version":3,"file":"ibr-utils.d.ts","sourceRoot":"","sources":["../../src/reporter/ibr-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAO3E,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC,CAAC;AAIF,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAChD,WAAW,EAAE,CAOf;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAO3E;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,EAC1B,IAAI,EAAE,QAAQ,GACb,MAAM,CAOR;AAID,KAAK,YAAY,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAIF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACvD,CAAC;AAIF,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,CAAC,YAAY,GAAG,SAAS,CAAC,EAAE,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB,CAAC;AAIF,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,cAAc,EAAE,EAC7B,OAAO,EAAE,MAAM,GACd,cAAc,EAAE,CAUlB;AAID,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,YAAY,CAc3E;AAID,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAsBvE;AAMD;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,SAAS,EAChB,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,GAC5B,SAAS,GAAG,IAAI,CAqBlB;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAK7D;AAED,wBAAgB,aAAa,CAC3B,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMxB;AAED,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAI3D;AAED,wBAAgB,eAAe,CAC7B,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CAoBf"}
|
|
@@ -7,6 +7,7 @@ exports.serializeRegexPatterns = serializeRegexPatterns;
|
|
|
7
7
|
exports.generateId = generateId;
|
|
8
8
|
exports.getOrCreateId = getOrCreateId;
|
|
9
9
|
exports.getOrCreateStepId = getOrCreateStepId;
|
|
10
|
+
exports.relativeAnnotationLocations = relativeAnnotationLocations;
|
|
10
11
|
exports.serializeTest = serializeTest;
|
|
11
12
|
exports.serializeSuite = serializeSuite;
|
|
12
13
|
exports.filterSuiteByCompletedTests = filterSuiteByCompletedTests;
|
|
@@ -45,6 +46,19 @@ function getOrCreateStepId(map, step) {
|
|
|
45
46
|
}
|
|
46
47
|
return id;
|
|
47
48
|
}
|
|
49
|
+
// Mirrors _relativeAnnotationLocations from Playwright's TeleReporterEmitter
|
|
50
|
+
// See: packages/playwright/src/reporters/teleEmitter.ts
|
|
51
|
+
function relativeAnnotationLocations(annotations, rootDir) {
|
|
52
|
+
return annotations.map((annotation) => ({
|
|
53
|
+
...annotation,
|
|
54
|
+
location: annotation.location
|
|
55
|
+
? {
|
|
56
|
+
...annotation.location,
|
|
57
|
+
file: path_1.default.relative(rootDir, annotation.location.file),
|
|
58
|
+
}
|
|
59
|
+
: undefined,
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
48
62
|
// Mirrors _serializeTest from Playwright's TeleReporterEmitter
|
|
49
63
|
// See: packages/playwright/src/reporters/teleEmitter.ts
|
|
50
64
|
function serializeTest(test, rootDir) {
|
|
@@ -59,7 +73,7 @@ function serializeTest(test, rootDir) {
|
|
|
59
73
|
retries: test.retries,
|
|
60
74
|
tags: test.tags,
|
|
61
75
|
repeatEachIndex: test.repeatEachIndex,
|
|
62
|
-
annotations: test.annotations,
|
|
76
|
+
annotations: relativeAnnotationLocations(test.annotations, rootDir),
|
|
63
77
|
};
|
|
64
78
|
}
|
|
65
79
|
// Mirrors _serializeSuite from Playwright's TeleReporterEmitter
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FullConfig, FullResult, Reporter, Suite, TestCase, TestResult, TestStep } from "@playwright/test/reporter";
|
|
1
|
+
import type { FullConfig, FullResult, Reporter, Suite, TestCase, TestError, TestResult, TestStep, WorkerInfo } from "@playwright/test/reporter";
|
|
2
2
|
/**
|
|
3
3
|
* IncrementalBlobReporter
|
|
4
4
|
*
|
|
@@ -25,17 +25,25 @@ declare class IncrementalBlobReporter implements Reporter {
|
|
|
25
25
|
private _testResults;
|
|
26
26
|
private _startTime;
|
|
27
27
|
private _finalizePromise;
|
|
28
|
+
private _rootDir;
|
|
28
29
|
constructor();
|
|
29
30
|
private _sigintHandler;
|
|
30
31
|
private _setupSignalHandler;
|
|
31
32
|
private _removeSignalHandler;
|
|
32
33
|
private _buildSyntheticResult;
|
|
33
34
|
private _finalizeAndMaybeUpload;
|
|
34
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Computes the lines to write, without touching `_reportLines`: recording
|
|
37
|
+
* continues after the SIGINT salvage, and the onEnd pass re-finalizes from
|
|
38
|
+
* the full stream — mutating here would make the second pass work from the
|
|
39
|
+
* first pass's pruned leftovers.
|
|
40
|
+
*/
|
|
41
|
+
private _buildFinalReportLines;
|
|
35
42
|
private _computeCompletedSets;
|
|
36
43
|
private _removeIncompleteTestArtifacts;
|
|
37
44
|
private _patchProjectSuites;
|
|
38
45
|
private get _zipPath();
|
|
46
|
+
private get _markerPath();
|
|
39
47
|
private get _jsonlPath();
|
|
40
48
|
private get _urlsJsonPath();
|
|
41
49
|
private _ensureDirs;
|
|
@@ -45,6 +53,9 @@ declare class IncrementalBlobReporter implements Reporter {
|
|
|
45
53
|
onBegin(config: FullConfig, suite: Suite): void;
|
|
46
54
|
onTestBegin(test: TestCase, result: TestResult): void;
|
|
47
55
|
onTestEnd(test: TestCase, result: TestResult): void;
|
|
56
|
+
onStdOut(chunk: string | Buffer, test?: TestCase, result?: TestResult): void;
|
|
57
|
+
onStdErr(chunk: string | Buffer, test?: TestCase, result?: TestResult): void;
|
|
58
|
+
onError(error: TestError, workerInfo?: WorkerInfo): void;
|
|
48
59
|
onStepBegin(test: TestCase, result: TestResult, step: TestStep): void;
|
|
49
60
|
onStepEnd(test: TestCase, result: TestResult, step: TestStep): void;
|
|
50
61
|
onEnd(result: FullResult): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"incremental-blob-reporter.d.ts","sourceRoot":"","sources":["../../src/reporter/incremental-blob-reporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,UAAU,EACV,QAAQ,
|
|
1
|
+
{"version":3,"file":"incremental-blob-reporter.d.ts","sourceRoot":"","sources":["../../src/reporter/incremental-blob-reporter.ts"],"names":[],"mappings":"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"}
|