@empiricalrun/playwright-utils 0.50.0 → 0.51.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @empiricalrun/playwright-utils
2
2
 
3
+ ## 0.51.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7584f64: fix: incremental blob reporter does not kill process group
8
+
9
+ ## 0.50.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 8b1be9e: fix: html report attachment urls for pw 1.60.0
14
+ - Updated dependencies [8b1be9e]
15
+ - @empiricalrun/reporter@0.29.1
16
+
3
17
  ## 0.50.0
4
18
 
5
19
  ### Minor Changes
@@ -1 +1 @@
1
- {"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../../src/reporter/harness.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;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,CA2BD;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,CAoDpB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,SAAS,EAAE,CAAC,CAUtB"}
1
+ {"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../../src/reporter/harness.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;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,CA2BD;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,CAiDpB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,SAAS,EAAE,CAAC,CAUtB"}
@@ -75,9 +75,6 @@ async function runPlaywrightWithSigint(ctx, opts) {
75
75
  TOTAL_SHARDS: "1",
76
76
  },
77
77
  stdio: ["pipe", "pipe", "pipe"],
78
- // Must match production: detached creates a new process group so the
79
- // reporter's SIGKILL on -process.pid only kills browsers + Playwright,
80
- // not the test runner.
81
78
  detached: true,
82
79
  });
83
80
  let stdout = "";
@@ -19,18 +19,19 @@ declare class IncrementalBlobReporter implements Reporter {
19
19
  private _resultIdMap;
20
20
  private _stepIdMap;
21
21
  private _uploader;
22
- private _flushPromise;
23
22
  private _completedTestIds;
24
23
  private _completedResultIds;
25
24
  private _testRetries;
26
25
  private _testResults;
27
26
  private _startTime;
27
+ private _finalizePromise;
28
28
  constructor();
29
29
  private _sigintHandler;
30
30
  private _setupSignalHandler;
31
31
  private _removeSignalHandler;
32
- private _flushAndUpload;
33
- private _finalizeReportForInterrupt;
32
+ private _buildSyntheticResult;
33
+ private _finalizeAndMaybeUpload;
34
+ private _finalizeReport;
34
35
  private _computeCompletedSets;
35
36
  private _removeIncompleteTestArtifacts;
36
37
  private _patchProjectSuites;
@@ -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;AAuBnC;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEnD,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,aAAa,CAA8B;IACnD,OAAO,CAAC,iBAAiB,CAA0B;IACnD,OAAO,CAAC,mBAAmB,CAA0B;IACrD,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,YAAY,CAGN;IACd,OAAO,CAAC,UAAU,CAAsB;;IAexC,OAAO,CAAC,cAAc,CAA6B;IAEnD,OAAO,CAAC,mBAAmB;IAkC3B,OAAO,CAAC,oBAAoB;YAOd,eAAe;IAwC7B,OAAO,CAAC,2BAA2B;IAyBnC,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,8BAA8B;IAStC,OAAO,CAAC,mBAAmB;IAkB3B,OAAO,KAAK,QAAQ,GAKnB;IAED,OAAO,KAAK,UAAU,GAErB;IAED,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,aAAa;YAUP,SAAS;IAwBvB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAgB/C,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAIrD,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAyBnD,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI;IAYrE,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI;IAY7D,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB9C;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAI5D,aAAa,IAAI,OAAO;CAGzB;AAID,wBAAgB,0BAA0B,IAAI,uBAAuB,GAAG,IAAI,CAE3E;AAED,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,uBAAuB,GAChC,IAAI,CAEN;AAED,eAAe,uBAAuB,CAAC"}
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;AAuBnC;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEnD,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,CAGN;IACd,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,gBAAgB,CAA8B;;IAetD,OAAO,CAAC,cAAc,CAA6B;IAEnD,OAAO,CAAC,mBAAmB;IA+B3B,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,qBAAqB;YASf,uBAAuB;IAqErC,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,8BAA8B;IAStC,OAAO,CAAC,mBAAmB;IAkB3B,OAAO,KAAK,QAAQ,GAKnB;IAED,OAAO,KAAK,UAAU,GAErB;IAED,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,aAAa;YAUP,SAAS;IAwBvB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAgB/C,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAIrD,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAyBnD,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI;IAYrE,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI;IAY7D,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB9C;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAI5D,aAAa,IAAI,OAAO;CAGzB;AAID,wBAAgB,0BAA0B,IAAI,uBAAuB,GAAG,IAAI,CAE3E;AAED,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,uBAAuB,GAChC,IAAI,CAEN;AAED,eAAe,uBAAuB,CAAC"}
@@ -25,12 +25,12 @@ class IncrementalBlobReporter {
25
25
  _resultIdMap = new Map(); // testId+retry -> resultId
26
26
  _stepIdMap = new Map(); // step -> stepId
27
27
  _uploader = null;
28
- _flushPromise = null;
29
28
  _completedTestIds = new Set();
30
29
  _completedResultIds = new Set();
31
30
  _testRetries = new Map(); // testId → configured retries
32
31
  _testResults = new Map(); // testId → retryIndex → {resultId, status, expectedStatus}
33
32
  _startTime = Date.now();
33
+ _finalizePromise = null;
34
34
  constructor() {
35
35
  if (process.env.SHARD_INDEX && process.env.TOTAL_SHARDS) {
36
36
  this._shardIndex = Number.parseInt(process.env.SHARD_INDEX, 10);
@@ -47,28 +47,25 @@ class IncrementalBlobReporter {
47
47
  _sigintHandler = null;
48
48
  _setupSignalHandler() {
49
49
  this._sigintHandler = () => {
50
- if ((0, reporter_state_1.isFinalized)())
50
+ if (this._finalizePromise || (0, reporter_state_1.isFinalized)()) {
51
51
  return;
52
- console.log("[IncrementalBlobReporter] SIGINT received, flushing and uploading...");
53
- this._flushPromise = this._flushAndUpload()
52
+ }
53
+ console.log("[IncrementalBlobReporter] SIGINT received, finalizing...");
54
+ this._finalizePromise = this._finalizeAndMaybeUpload({
55
+ result: this._buildSyntheticResult("interrupted"),
56
+ source: "SIGINT",
57
+ markGlobalFinalized: true,
58
+ pruneIncompleteTests: true,
59
+ upload: true,
60
+ })
54
61
  .then(() => {
55
- console.log("[IncrementalBlobReporter] Flush and upload complete on SIGINT, exiting");
62
+ console.log("[IncrementalBlobReporter] Finalize and upload complete on SIGINT");
56
63
  })
57
64
  .catch((err) => {
58
- console.error("[IncrementalBlobReporterFailure] Flush/upload failed on SIGINT:", err);
65
+ console.error("[IncrementalBlobReporterFailure] Finalize/upload failed on SIGINT:", err);
59
66
  })
60
67
  .finally(() => {
61
68
  this._removeSignalHandler();
62
- // Kill the entire process group (browsers + self) to avoid
63
- // orphaned browser processes writing to test-results/ after exit.
64
- // Using process.exit(0) alone only exits the Node process, leaving
65
- // browser processes alive which blocks cleanup on worker warm reuse.
66
- try {
67
- process.kill(-process.pid, "SIGKILL");
68
- }
69
- catch {
70
- process.exit(0);
71
- }
72
69
  });
73
70
  };
74
71
  process.on("SIGINT", this._sigintHandler);
@@ -79,8 +76,23 @@ class IncrementalBlobReporter {
79
76
  this._sigintHandler = null;
80
77
  }
81
78
  }
82
- async _flushAndUpload() {
83
- (0, reporter_state_1.setFinalized)();
79
+ _buildSyntheticResult(status) {
80
+ const now = Date.now();
81
+ return {
82
+ status,
83
+ startTime: new Date(this._startTime),
84
+ duration: now - this._startTime,
85
+ };
86
+ }
87
+ async _finalizeAndMaybeUpload({ result, source, markGlobalFinalized, pruneIncompleteTests, upload, }) {
88
+ const finalizeStart = Date.now();
89
+ const logFinalizeComplete = () => {
90
+ const durationMs = Date.now() - finalizeStart;
91
+ console.log(`[IncrementalBlobReporter] Finalize from ${source} completed in ${durationMs}ms (${(durationMs / 1_000).toFixed(1)}s)`);
92
+ };
93
+ if (markGlobalFinalized) {
94
+ (0, reporter_state_1.setFinalized)();
95
+ }
84
96
  if (!(0, ibr_utils_1.hasValidReport)(this._reportLines)) {
85
97
  console.warn("[IncrementalBlobReporterFailure] No onBegin received, skipping upload (nothing to merge)");
86
98
  return;
@@ -89,39 +101,37 @@ class IncrementalBlobReporter {
89
101
  if (this._uploader) {
90
102
  await this._uploader.waitForUploads();
91
103
  }
92
- this._finalizeReportForInterrupt();
104
+ this._finalizeReport(result, pruneIncompleteTests);
93
105
  await this._writeZip();
106
+ if (!upload) {
107
+ logFinalizeComplete();
108
+ return;
109
+ }
94
110
  if (!this._uploader) {
95
111
  console.warn("[IncrementalBlobReporterFailure] No uploader available, skipping upload");
112
+ logFinalizeComplete();
96
113
  return;
97
114
  }
98
115
  await this._uploader.uploadFile(this._zipPath, `blobs/incremental-report-${this._shardIndex}.zip`);
99
116
  await this._uploader.waitForUploads();
100
- console.log("[IncrementalBlobReporter] Flush and upload complete on SIGINT");
117
+ console.log(`[IncrementalBlobReporter] Finalize and upload complete from ${source}`);
101
118
  if ((0, ibr_utils_1.isLocalTesting)()) {
102
119
  await (0, local_test_1.mergeForLocalTest)(this._currentWorkingDir, this._outputDir);
103
120
  }
121
+ logFinalizeComplete();
104
122
  }
105
- _finalizeReportForInterrupt() {
106
- // Determine which tests are fully complete (passed or all retries finished)
107
- this._computeCompletedSets();
108
- // Remove unrun tests from onProject suites
109
- this._patchProjectSuites();
110
- // Remove events (onTestBegin, onStepBegin, etc.) for incomplete tests
111
- this._removeIncompleteTestArtifacts();
112
- // Push onEnd directly (bypass _appendEvent which checks isFinalized)
113
- const now = Date.now();
114
- const onEndEvent = {
115
- method: "onEnd",
116
- params: {
117
- result: {
118
- status: "interrupted",
119
- startTime: this._startTime,
120
- duration: now - this._startTime,
121
- },
122
- },
123
- };
124
- this._reportLines.push(JSON.stringify(onEndEvent));
123
+ _finalizeReport(result, pruneIncompleteTests) {
124
+ if (pruneIncompleteTests) {
125
+ // Determine which tests are fully complete (passed or all retries finished)
126
+ this._computeCompletedSets();
127
+ // Remove unrun tests from onProject suites
128
+ this._patchProjectSuites();
129
+ // Remove events (onTestBegin, onStepBegin, etc.) for incomplete tests
130
+ this._removeIncompleteTestArtifacts();
131
+ }
132
+ // Push onEnd directly. SIGINT marks the reporter finalized before this,
133
+ // so using _appendEvent would drop the synthetic onEnd event.
134
+ this._reportLines.push(JSON.stringify((0, lifecycle_events_1.buildOnEndEvent)(result)));
125
135
  }
126
136
  _computeCompletedSets() {
127
137
  for (const [testId, results] of this._testResults) {
@@ -233,14 +243,22 @@ class IncrementalBlobReporter {
233
243
  }
234
244
  async onEnd(result) {
235
245
  this._removeSignalHandler();
236
- this._appendEvent((0, lifecycle_events_1.buildOnEndEvent)(result));
237
- // Wait for SIGINT flush to complete if it was started
238
- if (this._flushPromise) {
239
- await this._flushPromise;
246
+ // If SIGINT already started the partial-report finalization, let that
247
+ // finish instead of appending a second onEnd or racing another zip write.
248
+ if (this._finalizePromise) {
249
+ await this._finalizePromise;
250
+ return;
240
251
  }
241
- // Final zip write
242
- await this._uploader?.waitForUploads();
243
- await this._writeZip();
252
+ this._finalizePromise = this._finalizeAndMaybeUpload({
253
+ result,
254
+ source: "onEnd",
255
+ markGlobalFinalized: false,
256
+ pruneIncompleteTests: false,
257
+ // Normal completion already has Playwright's blob/html reporters.
258
+ // Only the SIGINT path uploads this incremental fallback blob.
259
+ upload: false,
260
+ });
261
+ await this._finalizePromise;
244
262
  console.log(`[IncrementalBlobReporter] Finished with status: ${result.status}`);
245
263
  }
246
264
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/reporter/util.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAMhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACL,UAAU,IAAI,oBAAoB,EAElC,QAAQ,EACT,MAAM,2BAA2B,CAAC;AA0BnC,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAmB7D;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,UAMhC;AAED,wBAAsB,0BAA0B,CAC9C,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5E,OAAO,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,CAyCD;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,QAAQ;;;EAwBrD;AAED,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAiDf;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,GAAG,EACR,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GACnC,GAAG,CAIL;AAED,wBAAsB,gCAAgC,CACpD,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,iBAuGjB;AAED;;;;;;;;;;GAUG;AACH;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAC/C,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,EAChB,cAAc,GAAE,OAAe,GAC9B,iBAAiB,CAcnB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO7E;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gCAAgC,CACpD,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,6CA+BlB"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/reporter/util.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAQhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EACL,UAAU,IAAI,oBAAoB,EAElC,QAAQ,EACT,MAAM,2BAA2B,CAAC;AA0BnC,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAmB7D;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,UAMhC;AAED,wBAAsB,0BAA0B,CAC9C,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5E,OAAO,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,CAyCD;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,QAAQ;;;EAwBrD;AAED,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAiDf;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,GAAG,EACR,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GACnC,GAAG,CAIL;AAED,wBAAsB,gCAAgC,CACpD,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,iBAoFjB;AAED;;;;;;;;;;GAUG;AACH;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAC/C,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,EAChB,cAAc,GAAE,OAAe,GAC9B,iBAAiB,CAcnB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO7E;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gCAAgC,CACpD,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,6CA+BlB"}
@@ -173,12 +173,10 @@ async function updateHtmlZipFileAttachmentPaths(jsonFilePath, htmlFilePath, repo
173
173
  console.error(`❌ Failed to read HTML file at ${htmlFilePath}:`, err);
174
174
  return;
175
175
  }
176
- // Support both old format (1.53.x) and new format (1.57.0+)
176
+ // Support the global assignment, script tag, and Playwright 1.60 template tag.
177
177
  // Old: window.playwrightReportBase64 = "data:application/zip;base64,..."
178
- // New: <script id="playwrightReportBase64" type="application/zip">data:application/zip;base64,...</script>
179
- const oldFormatMatch = htmlFile.match(/window\.playwrightReportBase64\s*=\s*"(?:data:application\/zip;base64,)?([^"]+)"/);
180
- const newFormatMatch = htmlFile.match(/<script\s+id="playwrightReportBase64"[^>]*>(?:data:application\/zip;base64,)?([^<]+)<\/script>/);
181
- const base64 = oldFormatMatch?.[1] || newFormatMatch?.[1];
178
+ // Newer: <script|template id="playwrightReportBase64">data:application/zip;base64,...</script|template>
179
+ const base64 = (0, reporter_1.findPlaywrightReportBase64)(htmlFile);
182
180
  if (!base64) {
183
181
  console.error("❌ Base64 zip data not found in HTML.");
184
182
  return;
@@ -214,15 +212,7 @@ async function updateHtmlZipFileAttachmentPaths(jsonFilePath, htmlFilePath, repo
214
212
  }
215
213
  const newBuffer = await (0, zip_1.createZipFromDirectory)(tempDir);
216
214
  const newBase64 = newBuffer.toString("base64");
217
- let updatedHtml;
218
- if (oldFormatMatch) {
219
- // Old format (1.53.x): window.playwrightReportBase64 = "..."
220
- updatedHtml = htmlFile.replace(/(window\.playwrightReportBase64\s*=\s*")(?:data:application\/zip;base64,)?[^"]*(")/, `$1data:application/zip;base64,${newBase64}$2`);
221
- }
222
- else {
223
- // New format (1.57.0+): <script id="playwrightReportBase64" ...>...</script>
224
- updatedHtml = htmlFile.replace(/(<script\s+id="playwrightReportBase64"[^>]*>)(?:data:application\/zip;base64,)?[^<]*(<\/script>)/, `$1data:application/zip;base64,${newBase64}$2`);
225
- }
215
+ const updatedHtml = (0, reporter_1.replacePlaywrightReportBase64)(htmlFile, newBase64);
226
216
  await fs_1.default.promises.writeFile(htmlFilePath, updatedHtml, "utf8");
227
217
  logger_1.logger.debug("✅ HTML file updated with new base64 zip attachment.");
228
218
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/playwright-utils",
3
- "version": "0.50.0",
3
+ "version": "0.51.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -50,7 +50,7 @@
50
50
  "@empiricalrun/dashboard-client": "^0.3.0",
51
51
  "@empiricalrun/llm": "^0.27.0",
52
52
  "@empiricalrun/r2-uploader": "^0.9.1",
53
- "@empiricalrun/reporter": "^0.29.0"
53
+ "@empiricalrun/reporter": "^0.29.1"
54
54
  },
55
55
  "scripts": {
56
56
  "dev": "tsc --build --watch",