@empiricalrun/playwright-utils 0.58.2 → 0.58.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"empirical-reporter.d.ts","sourceRoot":"","sources":["../../src/reporter/empirical-reporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,UAAU,EACX,MAAM,2BAA2B,CAAC;AAuBnC,cAAM,iBAAkB,YAAW,QAAQ;IACzC,OAAO,CAAC,kBAAkB,CAAyB;IACnD,OAAO,CAAC,oBAAoB,CAG1B;IACF,OAAO,CAAC,sBAAsB,CAAuB;IACrD,OAAO,CAAC,YAAY,CAAgD;IACpE,OAAO,CAAC,iBAAiB,CAAyC;IAClE,OAAO,CAAC,gBAAgB,CAAkC;IAC1D,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,kBAAkB,CAA2B;IAGrD,OAAO,CAAC,YAAY,CAAqB;IAEzC,cAEC;IAED,OAAO,CAAC,MAAM,EAAE,UAAU,QAEzB;IAED,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,6BAA6B,CA2CnC;IAEF,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,QAqI3C;IAEK,KAAK,CAAC,MAAM,EAAE,UAAU,iBAiH7B;IAED,OAAO,CAAC,qBAAqB;YAkBf,gBAAgB;YAOhB,iBAAiB;CAqChC;eAEc,iBAAiB"}
1
+ {"version":3,"file":"empirical-reporter.d.ts","sourceRoot":"","sources":["../../src/reporter/empirical-reporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,UAAU,EACX,MAAM,2BAA2B,CAAC;AAuBnC,cAAM,iBAAkB,YAAW,QAAQ;IACzC,OAAO,CAAC,kBAAkB,CAAyB;IACnD,OAAO,CAAC,oBAAoB,CAG1B;IACF,OAAO,CAAC,sBAAsB,CAAuB;IACrD,OAAO,CAAC,YAAY,CAAgD;IACpE,OAAO,CAAC,iBAAiB,CAAyC;IAClE,OAAO,CAAC,gBAAgB,CAAkC;IAC1D,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,kBAAkB,CAA2B;IAGrD,OAAO,CAAC,YAAY,CAAqB;IAEzC,cAEC;IAED,OAAO,CAAC,MAAM,EAAE,UAAU,QAEzB;IAED,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,6BAA6B,CA2CnC;IAEF,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,QA+I3C;IAEK,KAAK,CAAC,MAAM,EAAE,UAAU,iBAiH7B;IAED,OAAO,CAAC,qBAAqB;YAkBf,gBAAgB;YAOhB,iBAAiB;CAqChC;eAEc,iBAAiB"}
@@ -150,6 +150,15 @@ class EmpiricalReporter {
150
150
  stack: e.stack,
151
151
  location: e.location,
152
152
  })),
153
+ // Playwright seeds result.annotations with the full per-attempt
154
+ // set (static + suite + runtime-pushed); test.annotations is the
155
+ // fallback for older Playwright versions without it.
156
+ annotations: (result.annotations?.length
157
+ ? result.annotations
158
+ : test.annotations).map((a) => ({
159
+ type: a.type,
160
+ description: a.description,
161
+ })),
153
162
  },
154
163
  projectName,
155
164
  attachments: successfulAttachments,
@@ -92,4 +92,40 @@ export interface BlobEvent {
92
92
  * Reads `report.jsonl` from the blob zip and returns parsed events.
93
93
  */
94
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>;
95
131
  //# sourceMappingURL=harness.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../../src/reporter/harness.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../../src/reporter/harness.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,10 @@ exports.runPlaywrightWithSigint = runPlaywrightWithSigint;
12
12
  exports.markerNames = markerNames;
13
13
  exports.runPlaywrightList = runPlaywrightList;
14
14
  exports.readBlobEvents = readBlobEvents;
15
+ exports.readEventsFromZip = readEventsFromZip;
16
+ exports.setupParityFixture = setupParityFixture;
17
+ exports.runPlaywrightClean = runPlaywrightClean;
18
+ exports.mergeBlobDirToSummary = mergeBlobDirToSummary;
15
19
  const zip_1 = require("@empiricalrun/r2-uploader/zip");
16
20
  const child_process_1 = require("child_process");
17
21
  const fs_1 = __importDefault(require("fs"));
@@ -250,9 +254,15 @@ async function runPlaywrightList(ctx) {
250
254
  * Reads `report.jsonl` from the blob zip and returns parsed events.
251
255
  */
252
256
  async function readBlobEvents(ctx) {
253
- const reportBuffer = await (0, zip_1.readZipEntry)(ctx.zipPath, "report.jsonl");
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");
254
264
  if (!reportBuffer) {
255
- throw new Error(`report.jsonl not found in zip: ${ctx.zipPath}`);
265
+ throw new Error(`report.jsonl not found in zip: ${zipPath}`);
256
266
  }
257
267
  return reportBuffer
258
268
  .toString("utf8")
@@ -260,3 +270,72 @@ async function readBlobEvents(ctx) {
260
270
  .split("\n")
261
271
  .map((line) => JSON.parse(line));
262
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,6 +25,7 @@ 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;
@@ -42,6 +43,7 @@ declare class IncrementalBlobReporter implements Reporter {
42
43
  private _removeIncompleteTestArtifacts;
43
44
  private _patchProjectSuites;
44
45
  private get _zipPath();
46
+ private get _markerPath();
45
47
  private get _jsonlPath();
46
48
  private get _urlsJsonPath();
47
49
  private _ensureDirs;
@@ -51,6 +53,9 @@ declare class IncrementalBlobReporter implements Reporter {
51
53
  onBegin(config: FullConfig, suite: Suite): void;
52
54
  onTestBegin(test: TestCase, result: TestResult): void;
53
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;
54
59
  onStepBegin(test: TestCase, result: TestResult, step: TestStep): void;
55
60
  onStepEnd(test: TestCase, result: TestResult, step: TestStep): void;
56
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,EACT,MAAM,2BAA2B,CAAC;AAwBnC;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AASnD,cAAM,uBAAwB,YAAW,QAAQ;IAC/C,OAAO,CAAC,kBAAkB,CAAyB;IACnD,OAAO,CAAC,WAAW,CAIjB;IACF,OAAO,CAAC,UAAU,CAGhB;IACF,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,iBAAiB,CAA0B;IACnD,OAAO,CAAC,mBAAmB,CAA0B;IACrD,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,YAAY,CAAsD;IAC1E,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,gBAAgB,CAA8B;IAEtD,cAWC;IAED,OAAO,CAAC,cAAc,CAA6B;IAEnD,OAAO,CAAC,mBAAmB;IA+B3B,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,qBAAqB;YASf,uBAAuB;IAqErC;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAuB9B,OAAO,CAAC,qBAAqB;IA0B7B,OAAO,CAAC,8BAA8B;IAWtC,OAAO,CAAC,mBAAmB;IAmB3B,OAAO,KAAK,QAAQ,GAKnB;IAED,OAAO,KAAK,UAAU,GAErB;IAED,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,aAAa;YAUP,SAAS;IAwBvB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAc9C;IAED,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAEpD;IAED,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA0BlD;IAED,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAUpE;IAED,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAUlE;IAEK,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAiC7C;IAED;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAE3D;IAED,aAAa,IAAI,OAAO,CAEvB;CACF;AAID,wBAAgB,0BAA0B,IAAI,uBAAuB,GAAG,IAAI,CAE3E;AAED,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,uBAAuB,GAChC,IAAI,CAEN;eAEc,uBAAuB"}
1
+ {"version":3,"file":"incremental-blob-reporter.d.ts","sourceRoot":"","sources":["../../src/reporter/incremental-blob-reporter.ts"],"names":[],"mappings":"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"}
@@ -31,6 +31,7 @@ class IncrementalBlobReporter {
31
31
  _testResults = new Map(); // testId → retryIndex → RecordedRetry
32
32
  _startTime = Date.now();
33
33
  _finalizePromise = null;
34
+ _rootDir = process.cwd();
34
35
  constructor() {
35
36
  if (process.env.SHARD_INDEX && process.env.TOTAL_SHARDS) {
36
37
  this._shardIndex = Number.parseInt(process.env.SHARD_INDEX, 10);
@@ -108,12 +109,17 @@ class IncrementalBlobReporter {
108
109
  return;
109
110
  }
110
111
  if (!this._uploader) {
111
- console.warn("[IncrementalBlobReporterFailure] No uploader available, skipping upload");
112
+ console.warn("[IncrementalBlobReporter] No uploader available, skipping upload");
112
113
  logFinalizeComplete();
113
114
  return;
114
115
  }
115
116
  await this._uploader.uploadFile(this._zipPath, `blobs/incremental-report-${this._shardIndex}.zip`);
116
117
  await this._uploader.waitForUploads();
118
+ if (source === "onEnd") {
119
+ fs_1.default.writeFileSync(this._markerPath, JSON.stringify({ status: result.status, events: lines.length }), "utf8");
120
+ await this._uploader.uploadFile(this._markerPath, `blobs/incremental-report-${this._shardIndex}.zip.complete`);
121
+ await this._uploader.waitForUploads();
122
+ }
117
123
  console.log(`[IncrementalBlobReporter] Finalize and upload complete from ${source}`);
118
124
  if ((0, ibr_utils_1.isLocalTesting)()) {
119
125
  await (0, local_test_1.mergeForLocalTest)(this._currentWorkingDir, this._outputDir);
@@ -188,6 +194,9 @@ class IncrementalBlobReporter {
188
194
  get _zipPath() {
189
195
  return path_1.default.join(this._outputDir, `incremental-report-${this._shardIndex}.zip`);
190
196
  }
197
+ get _markerPath() {
198
+ return `${this._zipPath}.complete`;
199
+ }
191
200
  get _jsonlPath() {
192
201
  return path_1.default.join(this._stagingDir, "report.jsonl");
193
202
  }
@@ -230,6 +239,14 @@ class IncrementalBlobReporter {
230
239
  }
231
240
  onBegin(config, suite) {
232
241
  this._ensureDirs();
242
+ this._rootDir = config.rootDir;
243
+ // The env vars win (production sets them), but a sharded run without
244
+ // them should still stamp the right shard into the blob metadata and
245
+ // the zip name instead of defaulting every shard to 1/1.
246
+ if (!process.env.SHARD_INDEX && config.shard) {
247
+ this._shardIndex = config.shard.current;
248
+ this._totalShards = config.shard.total;
249
+ }
233
250
  this._appendEvents((0, lifecycle_events_1.buildOnBeginEvents)(config, suite, this._currentWorkingDir, this._shardIndex, this._totalShards));
234
251
  console.log(`[IncrementalBlobReporter] Started with ${suite.allTests().length} tests`);
235
252
  }
@@ -237,7 +254,7 @@ class IncrementalBlobReporter {
237
254
  this._appendEvent((0, lifecycle_events_1.buildOnTestBeginEvent)(test, result, this._resultIdMap));
238
255
  }
239
256
  onTestEnd(test, result) {
240
- const events = (0, lifecycle_events_1.buildOnTestEndEvents)(test, result, this._resultIdMap, this._stagingDir);
257
+ const events = (0, lifecycle_events_1.buildOnTestEndEvents)(test, result, this._resultIdMap, this._stagingDir, this._rootDir);
241
258
  if (this._appendEvents(events)) {
242
259
  if (!this._testRetries.has(test.id)) {
243
260
  this._testRetries.set(test.id, test.retries);
@@ -258,11 +275,20 @@ class IncrementalBlobReporter {
258
275
  }
259
276
  }
260
277
  }
278
+ onStdOut(chunk, test, result) {
279
+ this._appendEvent((0, lifecycle_events_1.buildOnStdIOEvent)("stdout", chunk, test, result, this._resultIdMap));
280
+ }
281
+ onStdErr(chunk, test, result) {
282
+ this._appendEvent((0, lifecycle_events_1.buildOnStdIOEvent)("stderr", chunk, test, result, this._resultIdMap));
283
+ }
284
+ onError(error, workerInfo) {
285
+ this._appendEvent((0, lifecycle_events_1.buildOnErrorEvent)(error, workerInfo));
286
+ }
261
287
  onStepBegin(test, result, step) {
262
288
  this._appendEvent((0, lifecycle_events_1.buildOnStepBeginEvent)(test, result, step, this._resultIdMap, this._stepIdMap));
263
289
  }
264
290
  onStepEnd(test, result, step) {
265
- this._appendEvent((0, lifecycle_events_1.buildOnStepEndEvent)(test, result, step, this._resultIdMap, this._stepIdMap));
291
+ this._appendEvent((0, lifecycle_events_1.buildOnStepEndEvent)(test, result, step, this._resultIdMap, this._stepIdMap, this._rootDir));
266
292
  }
267
293
  async onEnd(result) {
268
294
  this._removeSignalHandler();
@@ -287,9 +313,7 @@ class IncrementalBlobReporter {
287
313
  source: "onEnd",
288
314
  markGlobalFinalized: false,
289
315
  pruneIncompleteTests: false,
290
- // Normal completion already has Playwright's blob/html reporters.
291
- // Only the SIGINT path uploads this incremental fallback blob.
292
- upload: false,
316
+ upload: true,
293
317
  });
294
318
  await this._finalizePromise;
295
319
  console.log(`[IncrementalBlobReporter] Finished with status: ${result.status}`);
@@ -1,4 +1,4 @@
1
- import type { FullConfig, FullProject, FullResult, Suite, TestCase, TestResult, TestStep } from "@playwright/test/reporter";
1
+ import type { FullConfig, FullProject, FullResult, Suite, TestCase, TestError, TestResult, TestStep, WorkerInfo } from "@playwright/test/reporter";
2
2
  export type JsonEvent = {
3
3
  method: string;
4
4
  params?: object;
@@ -6,8 +6,10 @@ export type JsonEvent = {
6
6
  export declare function buildOnBeginEvents(config: FullConfig, suite: Suite, currentWorkingDir: string, shardIndex: number, totalShards: number): JsonEvent[];
7
7
  export declare function buildOnProjectEvent(config: FullConfig, project: FullProject, projectSuite: Suite, currentWorkingDir: string): JsonEvent;
8
8
  export declare function buildOnTestBeginEvent(test: TestCase, result: TestResult, resultIdMap: Map<string, string>): JsonEvent;
9
- export declare function buildOnTestEndEvents(test: TestCase, result: TestResult, resultIdMap: Map<string, string>, stagingDir: string): JsonEvent[];
9
+ export declare function buildOnTestEndEvents(test: TestCase, result: TestResult, resultIdMap: Map<string, string>, stagingDir: string, rootDir: string): JsonEvent[];
10
+ export declare function buildOnStdIOEvent(type: "stdout" | "stderr", chunk: string | Buffer, test: TestCase | undefined, result: TestResult | undefined, resultIdMap: Map<string, string>): JsonEvent;
11
+ export declare function buildOnErrorEvent(error: TestError, workerInfo?: WorkerInfo): JsonEvent;
10
12
  export declare function buildOnStepBeginEvent(test: TestCase, result: TestResult, step: TestStep, resultIdMap: Map<string, string>, stepIdMap: Map<TestStep, string>): JsonEvent;
11
- export declare function buildOnStepEndEvent(test: TestCase, result: TestResult, step: TestStep, resultIdMap: Map<string, string>, stepIdMap: Map<TestStep, string>): JsonEvent;
13
+ export declare function buildOnStepEndEvent(test: TestCase, result: TestResult, step: TestStep, resultIdMap: Map<string, string>, stepIdMap: Map<TestStep, string>, rootDir: string): JsonEvent;
12
14
  export declare function buildOnEndEvent(result: FullResult): JsonEvent;
13
15
  //# sourceMappingURL=lifecycle-events.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle-events.d.ts","sourceRoot":"","sources":["../../src/reporter/lifecycle-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,UAAU,EACV,KAAK,EACL,QAAQ,EACR,UAAU,EACV,QAAQ,EACT,MAAM,2BAA2B,CAAC;AAgBnC,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,KAAK,EACZ,iBAAiB,EAAE,MAAM,EACzB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,SAAS,EAAE,CAqDb;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,YAAY,EAAE,KAAK,EACnB,iBAAiB,EAAE,MAAM,GACxB,SAAS,CA+BX;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,SAAS,CAeX;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,UAAU,EAAE,MAAM,GACjB,SAAS,EAAE,CAqDb;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,QAAQ,EACd,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,SAAS,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,GAC/B,SAAS,CAsBX;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,QAAQ,EACd,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,SAAS,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,GAC/B,SAAS,CAuBX;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAW7D"}
1
+ {"version":3,"file":"lifecycle-events.d.ts","sourceRoot":"","sources":["../../src/reporter/lifecycle-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,UAAU,EACV,KAAK,EACL,QAAQ,EACR,SAAS,EACT,UAAU,EACV,QAAQ,EACR,UAAU,EACX,MAAM,2BAA2B,CAAC;AAiBnC,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,KAAK,EACZ,iBAAiB,EAAE,MAAM,EACzB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,SAAS,EAAE,CAqDb;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,YAAY,EAAE,KAAK,EACnB,iBAAiB,EAAE,MAAM,GACxB,SAAS,CA+BX;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,SAAS,CAeX;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,SAAS,EAAE,CA+Db;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,QAAQ,GAAG,QAAQ,EACzB,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,IAAI,EAAE,QAAQ,GAAG,SAAS,EAC1B,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,SAAS,CAgBX;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,EAChB,UAAU,CAAC,EAAE,UAAU,GACtB,SAAS,CAcX;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,QAAQ,EACd,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,SAAS,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,GAC/B,SAAS,CAsBX;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,QAAQ,EACd,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,SAAS,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,EAChC,OAAO,EAAE,MAAM,GACd,SAAS,CA+BX;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAW7D"}
@@ -7,6 +7,8 @@ exports.buildOnBeginEvents = buildOnBeginEvents;
7
7
  exports.buildOnProjectEvent = buildOnProjectEvent;
8
8
  exports.buildOnTestBeginEvent = buildOnTestBeginEvent;
9
9
  exports.buildOnTestEndEvents = buildOnTestEndEvents;
10
+ exports.buildOnStdIOEvent = buildOnStdIOEvent;
11
+ exports.buildOnErrorEvent = buildOnErrorEvent;
10
12
  exports.buildOnStepBeginEvent = buildOnStepBeginEvent;
11
13
  exports.buildOnStepEndEvent = buildOnStepEndEvent;
12
14
  exports.buildOnEndEvent = buildOnEndEvent;
@@ -108,7 +110,7 @@ function buildOnTestBeginEvent(test, result, resultIdMap) {
108
110
  },
109
111
  };
110
112
  }
111
- function buildOnTestEndEvents(test, result, resultIdMap, stagingDir) {
113
+ function buildOnTestEndEvents(test, result, resultIdMap, stagingDir, rootDir) {
112
114
  const resultId = (0, ibr_utils_1.getOrCreateId)(resultIdMap, `${test.id}-${result.retry}`);
113
115
  const events = [];
114
116
  // onAttach for each attachment (matching Playwright's blob format)
@@ -131,6 +133,11 @@ function buildOnTestEndEvents(test, result, resultIdMap, stagingDir) {
131
133
  name: attachment.name,
132
134
  contentType: attachment.contentType,
133
135
  path: attachmentPath,
136
+ // Body-based attachments travel inline, mirroring
137
+ // TeleReporterEmitter._serializeAttachments.
138
+ base64: attachment.body
139
+ ? attachment.body.toString("base64")
140
+ : undefined,
134
141
  },
135
142
  ],
136
143
  },
@@ -143,7 +150,7 @@ function buildOnTestEndEvents(test, result, resultIdMap, stagingDir) {
143
150
  testId: test.id,
144
151
  expectedStatus: test.expectedStatus,
145
152
  timeout: test.timeout,
146
- annotations: test.annotations,
153
+ annotations: (0, ibr_utils_1.relativeAnnotationLocations)(test.annotations, rootDir),
147
154
  },
148
155
  result: {
149
156
  id: resultId,
@@ -155,11 +162,47 @@ function buildOnTestEndEvents(test, result, resultIdMap, stagingDir) {
155
162
  location: e.location,
156
163
  snippet: e.snippet,
157
164
  })),
165
+ // Blob v2 carries annotations on the result; the merge reads them
166
+ // from here (result-level), not from the test payload above.
167
+ annotations: result.annotations?.length
168
+ ? (0, ibr_utils_1.relativeAnnotationLocations)(result.annotations, rootDir)
169
+ : undefined,
158
170
  },
159
171
  },
160
172
  });
161
173
  return events;
162
174
  }
175
+ function buildOnStdIOEvent(type, chunk, test, result, resultIdMap) {
176
+ const isBase64 = typeof chunk !== "string";
177
+ const data = isBase64 ? chunk.toString("base64") : chunk;
178
+ return {
179
+ method: "onStdIO",
180
+ params: {
181
+ testId: test?.id,
182
+ resultId: test && result
183
+ ? (0, ibr_utils_1.getOrCreateId)(resultIdMap, `${test.id}-${result.retry}`)
184
+ : undefined,
185
+ type,
186
+ data,
187
+ isBase64,
188
+ },
189
+ };
190
+ }
191
+ function buildOnErrorEvent(error, workerInfo) {
192
+ return {
193
+ method: "onError",
194
+ params: {
195
+ error,
196
+ workerInfo: workerInfo
197
+ ? {
198
+ workerIndex: workerInfo.workerIndex,
199
+ parallelIndex: workerInfo.parallelIndex,
200
+ projectName: workerInfo.project.name,
201
+ }
202
+ : undefined,
203
+ },
204
+ };
205
+ }
163
206
  function buildOnStepBeginEvent(test, result, step, resultIdMap, stepIdMap) {
164
207
  const resultId = (0, ibr_utils_1.getOrCreateId)(resultIdMap, `${test.id}-${result.retry}`);
165
208
  const stepId = (0, ibr_utils_1.getOrCreateStepId)(stepIdMap, step);
@@ -182,7 +225,7 @@ function buildOnStepBeginEvent(test, result, step, resultIdMap, stepIdMap) {
182
225
  },
183
226
  };
184
227
  }
185
- function buildOnStepEndEvent(test, result, step, resultIdMap, stepIdMap) {
228
+ function buildOnStepEndEvent(test, result, step, resultIdMap, stepIdMap, rootDir) {
186
229
  const resultId = (0, ibr_utils_1.getOrCreateId)(resultIdMap, `${test.id}-${result.retry}`);
187
230
  const stepId = (0, ibr_utils_1.getOrCreateStepId)(stepIdMap, step);
188
231
  return {
@@ -201,6 +244,14 @@ function buildOnStepEndEvent(test, result, step, resultIdMap, stepIdMap) {
201
244
  snippet: step.error.snippet,
202
245
  }
203
246
  : undefined,
247
+ // Indices into the result's attachments, matching
248
+ // TeleReporterEmitter._serializeStepEnd.
249
+ attachments: step.attachments.length
250
+ ? step.attachments.map((a) => result.attachments.indexOf(a))
251
+ : undefined,
252
+ annotations: step.annotations.length
253
+ ? (0, ibr_utils_1.relativeAnnotationLocations)(step.annotations, rootDir)
254
+ : undefined,
204
255
  },
205
256
  },
206
257
  };
@@ -0,0 +1,63 @@
1
+ import type { BlobEvent } from "./harness";
2
+ export interface NormalizedAttachment {
3
+ name: string;
4
+ contentType: string;
5
+ /**
6
+ * Whether the merged report still points at real content (path or inline
7
+ * body). Compared only where a scenario opts in: the empirical pipeline
8
+ * resolves attachment bytes through _empirical_urls.json, so name+type is
9
+ * the baseline parity contract.
10
+ */
11
+ hasContent: boolean;
12
+ }
13
+ export interface NormalizedResult {
14
+ retry: number;
15
+ status: string;
16
+ errorMessages: string[];
17
+ stdout: string[];
18
+ stderr: string[];
19
+ attachments: NormalizedAttachment[];
20
+ }
21
+ export interface NormalizedTest {
22
+ projectName: string;
23
+ expectedStatus: string;
24
+ status: string;
25
+ annotations: {
26
+ type: string;
27
+ description?: string;
28
+ }[];
29
+ results: NormalizedResult[];
30
+ }
31
+ export interface NormalizedSpec {
32
+ title: string;
33
+ file: string;
34
+ ok: boolean;
35
+ tests: NormalizedTest[];
36
+ }
37
+ export interface NormalizedSuite {
38
+ title: string;
39
+ file: string;
40
+ specs: NormalizedSpec[];
41
+ suites: NormalizedSuite[];
42
+ }
43
+ export interface NormalizedReport {
44
+ suites: NormalizedSuite[];
45
+ errorMessages: string[];
46
+ stats: Record<string, unknown>;
47
+ }
48
+ export interface NormalizeOptions {
49
+ /** Absolute fixture dir, replaced with a stable token in messages. */
50
+ cwd: string;
51
+ /** Include attachment `hasContent` in the comparison (see above). */
52
+ compareAttachmentContent?: boolean;
53
+ }
54
+ export declare function normalizeJsonReport(report: Record<string, unknown>, opts: NormalizeOptions): NormalizedReport;
55
+ /**
56
+ * Per-result step signatures from a raw blob event stream, keyed by
57
+ * `testId:retry` (stable across both reporters — they see the same run).
58
+ * The merged JSON report drops steps, so step parity is checked here.
59
+ */
60
+ export declare function stepSignatures(events: BlobEvent[]): Map<string, string[]>;
61
+ /** Event method names present in `reference` but absent from `candidate`. */
62
+ export declare function missingEventMethods(reference: BlobEvent[], candidate: BlobEvent[]): string[];
63
+ //# sourceMappingURL=parity-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parity-utils.d.ts","sourceRoot":"","sources":["../../src/reporter/parity-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAiD3C,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,EAAE,oBAAoB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACtD,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAwED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,EAAE,gBAAgB,GACrB,gBAAgB,CAclB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CA+BzE;AAED,6EAA6E;AAC7E,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,SAAS,EAAE,EACtB,SAAS,EAAE,SAAS,EAAE,GACrB,MAAM,EAAE,CASV"}