@empiricalrun/playwright-utils 0.50.1 → 0.52.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 +12 -0
- package/dist/reporter/attachment-cleanup.js +2 -2
- package/dist/reporter/harness.d.ts.map +1 -1
- package/dist/reporter/harness.js +0 -3
- package/dist/reporter/ibr-utils.d.ts +1 -0
- package/dist/reporter/ibr-utils.d.ts.map +1 -1
- package/dist/reporter/ibr-utils.js +6 -0
- package/dist/reporter/incremental-blob-reporter.d.ts +4 -3
- package/dist/reporter/incremental-blob-reporter.d.ts.map +1 -1
- package/dist/reporter/incremental-blob-reporter.js +66 -48
- package/dist/reporter/lifecycle-events.d.ts.map +1 -1
- package/dist/reporter/lifecycle-events.js +8 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @empiricalrun/playwright-utils
|
|
2
2
|
|
|
3
|
+
## 0.52.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 73b88a2: fix: relative attachment for pw-utils
|
|
8
|
+
|
|
9
|
+
## 0.51.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 7584f64: fix: incremental blob reporter does not kill process group
|
|
14
|
+
|
|
3
15
|
## 0.50.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -89,7 +89,7 @@ class AttachmentCleanup {
|
|
|
89
89
|
_onEvict = null;
|
|
90
90
|
constructor(limitBytes = getDefaultDiskLimitBytes()) {
|
|
91
91
|
this._limitBytes = limitBytes;
|
|
92
|
-
logger_1.logger.
|
|
92
|
+
logger_1.logger.debug(`[AttachmentCleanup] Initialized with limit: ${formatBytes(limitBytes)}`);
|
|
93
93
|
this._diskLogTimer = setInterval(() => {
|
|
94
94
|
this._logDiskStatus();
|
|
95
95
|
}, DISK_LOG_INTERVAL_MS);
|
|
@@ -139,7 +139,7 @@ class AttachmentCleanup {
|
|
|
139
139
|
this._evictedCount++;
|
|
140
140
|
this._evictedBytes += oldest.size;
|
|
141
141
|
this._totalSize -= oldest.size;
|
|
142
|
-
logger_1.logger.
|
|
142
|
+
logger_1.logger.debug(`[AttachmentCleanup] Evicted ${oldest.path} (${formatBytes(oldest.size)}), totalSize=${formatBytes(this._totalSize)}, pending=${this._pending.size}, uploaded=${this._uploaded.length}`);
|
|
143
143
|
this._onEvict?.(oldest.path);
|
|
144
144
|
}
|
|
145
145
|
catch (err) {
|
|
@@ -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,
|
|
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"}
|
package/dist/reporter/harness.js
CHANGED
|
@@ -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 = "";
|
|
@@ -43,6 +43,7 @@ export declare function filterSuiteByCompletedTests(suite: JsonSuite, completedT
|
|
|
43
43
|
export declare function hasValidReport(reportLines: string[]): boolean;
|
|
44
44
|
export declare function buildUrlsJson(attachmentUrlMap: Map<string, string>): Record<string, string>;
|
|
45
45
|
export declare function isLocalTesting(): boolean;
|
|
46
|
+
export declare function toResourcePath(absolutePath: string): string;
|
|
46
47
|
export declare function embedAttachment(attachmentPath: string | undefined, resultId: string, stagingDir: string): string | null;
|
|
47
48
|
export {};
|
|
48
49
|
//# sourceMappingURL=ibr-utils.d.ts.map
|
|
@@ -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,CAmBlB;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,eAAe,CAC7B,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CAkBf"}
|
|
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,CAmBlB;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,CAkBf"}
|
|
@@ -13,6 +13,7 @@ exports.filterSuiteByCompletedTests = filterSuiteByCompletedTests;
|
|
|
13
13
|
exports.hasValidReport = hasValidReport;
|
|
14
14
|
exports.buildUrlsJson = buildUrlsJson;
|
|
15
15
|
exports.isLocalTesting = isLocalTesting;
|
|
16
|
+
exports.toResourcePath = toResourcePath;
|
|
16
17
|
exports.embedAttachment = embedAttachment;
|
|
17
18
|
const crypto_1 = __importDefault(require("crypto"));
|
|
18
19
|
const fs_1 = __importDefault(require("fs"));
|
|
@@ -126,6 +127,11 @@ function buildUrlsJson(attachmentUrlMap) {
|
|
|
126
127
|
function isLocalTesting() {
|
|
127
128
|
return process.env.LOCAL_TEST === "true";
|
|
128
129
|
}
|
|
130
|
+
function toResourcePath(absolutePath) {
|
|
131
|
+
const ext = path_1.default.extname(absolutePath);
|
|
132
|
+
const hash = crypto_1.default.createHash("sha1").update(absolutePath).digest("hex");
|
|
133
|
+
return `resources/${hash}${ext}`;
|
|
134
|
+
}
|
|
129
135
|
function embedAttachment(attachmentPath, resultId, stagingDir) {
|
|
130
136
|
if (!attachmentPath || !fs_1.default.existsSync(attachmentPath))
|
|
131
137
|
return null;
|
|
@@ -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
|
|
33
|
-
private
|
|
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;
|
|
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;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
|
-
|
|
53
|
-
|
|
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]
|
|
62
|
+
console.log("[IncrementalBlobReporter] Finalize and upload complete on SIGINT");
|
|
56
63
|
})
|
|
57
64
|
.catch((err) => {
|
|
58
|
-
console.error("[IncrementalBlobReporterFailure]
|
|
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
|
-
|
|
83
|
-
|
|
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.
|
|
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(
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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,21 +243,29 @@ class IncrementalBlobReporter {
|
|
|
233
243
|
}
|
|
234
244
|
async onEnd(result) {
|
|
235
245
|
this._removeSignalHandler();
|
|
236
|
-
|
|
237
|
-
//
|
|
238
|
-
if (this.
|
|
239
|
-
await this.
|
|
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
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
/**
|
|
247
265
|
* Add a single attachment URL mapping
|
|
248
266
|
*/
|
|
249
267
|
addAttachmentUrl(localPath, remoteUrl) {
|
|
250
|
-
this._attachmentUrlMap.set(localPath, remoteUrl);
|
|
268
|
+
this._attachmentUrlMap.set((0, ibr_utils_1.toResourcePath)(localPath), remoteUrl);
|
|
251
269
|
}
|
|
252
270
|
printsToStdio() {
|
|
253
271
|
return false;
|
|
@@ -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;
|
|
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,CAmDb;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"}
|
|
@@ -113,6 +113,13 @@ function buildOnTestEndEvents(test, result, resultIdMap, stagingDir) {
|
|
|
113
113
|
// onAttach for each attachment (matching Playwright's blob format)
|
|
114
114
|
for (const attachment of result.attachments) {
|
|
115
115
|
const embeddedPath = (0, ibr_utils_1.embedAttachment)(attachment.path, resultId, stagingDir);
|
|
116
|
+
let attachmentPath;
|
|
117
|
+
if (embeddedPath) {
|
|
118
|
+
attachmentPath = embeddedPath;
|
|
119
|
+
}
|
|
120
|
+
else if (attachment.path) {
|
|
121
|
+
attachmentPath = (0, ibr_utils_1.toResourcePath)(attachment.path);
|
|
122
|
+
}
|
|
116
123
|
events.push({
|
|
117
124
|
method: "onAttach",
|
|
118
125
|
params: {
|
|
@@ -122,7 +129,7 @@ function buildOnTestEndEvents(test, result, resultIdMap, stagingDir) {
|
|
|
122
129
|
{
|
|
123
130
|
name: attachment.name,
|
|
124
131
|
contentType: attachment.contentType,
|
|
125
|
-
path:
|
|
132
|
+
path: attachmentPath,
|
|
126
133
|
},
|
|
127
134
|
],
|
|
128
135
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@empiricalrun/playwright-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"rimraf": "^6.0.1",
|
|
48
48
|
"ts-morph": "^23.0.0",
|
|
49
49
|
"@empiricalrun/cua": "^0.4.1",
|
|
50
|
-
"@empiricalrun/dashboard-client": "^0.3.0",
|
|
51
50
|
"@empiricalrun/llm": "^0.27.0",
|
|
51
|
+
"@empiricalrun/dashboard-client": "^0.3.0",
|
|
52
52
|
"@empiricalrun/r2-uploader": "^0.9.1",
|
|
53
53
|
"@empiricalrun/reporter": "^0.29.1"
|
|
54
54
|
},
|