@empiricalrun/playwright-utils 0.65.0 → 0.66.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 +18 -0
- package/dist/api-worker-client.d.ts +25 -6
- package/dist/api-worker-client.d.ts.map +1 -1
- package/dist/api-worker-client.js +73 -9
- package/dist/generated/api-worker-openapi.d.ts +2568 -1384
- package/dist/generated/api-worker-openapi.d.ts.map +1 -1
- package/dist/kv.d.ts +31 -1
- package/dist/kv.d.ts.map +1 -1
- package/dist/kv.js +79 -5
- package/dist/overlay-tests/typesafe.spec.js +5 -3
- package/dist/overlay-tests/visual.spec.js +1 -1
- package/dist/reporter/attachment-cleanup-test-reporter.d.ts +3 -1
- package/dist/reporter/attachment-cleanup-test-reporter.d.ts.map +1 -1
- package/dist/reporter/attachment-cleanup-test-reporter.js +5 -1
- package/dist/reporter/attachment-cleanup.d.ts +1 -1
- package/dist/reporter/attachment-cleanup.d.ts.map +1 -1
- package/dist/reporter/attachment-cleanup.js +14 -7
- package/dist/reporter/attachment-key.d.ts +3 -0
- package/dist/reporter/attachment-key.d.ts.map +1 -0
- package/dist/reporter/attachment-key.js +31 -0
- package/dist/reporter/empirical-reporter.d.ts +1 -1
- package/dist/reporter/empirical-reporter.d.ts.map +1 -1
- package/dist/reporter/empirical-reporter.js +7 -6
- package/dist/reporter/harness.d.ts +6 -1
- package/dist/reporter/harness.d.ts.map +1 -1
- package/dist/reporter/harness.js +22 -13
- package/dist/reporter/incremental-blob-reporter.d.ts +1 -0
- package/dist/reporter/incremental-blob-reporter.d.ts.map +1 -1
- package/dist/reporter/incremental-blob-reporter.js +8 -4
- package/dist/reporter/util.d.ts +3 -3
- package/dist/reporter/util.d.ts.map +1 -1
- package/dist/reporter/util.js +10 -8
- package/dist/test/cross-shard-locks.d.ts +22 -0
- package/dist/test/cross-shard-locks.d.ts.map +1 -0
- package/dist/test/cross-shard-locks.js +110 -0
- package/dist/test/expect/visual.d.ts.map +1 -1
- package/dist/test/expect/visual.js +6 -2
- package/dist/test/index.d.ts +1 -0
- package/dist/test/index.d.ts.map +1 -1
- package/dist/test/index.js +13 -0
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/index.d.ts.map +1 -1
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/index.js +0 -2
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/utils.d.ts +0 -1
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/utils.d.ts.map +1 -1
- package/dist/test/scripts/pw-locator-patch/dismiss-overlays/utils.js +0 -20
- package/dist/test/scripts/pw-locator-patch/vision/query.d.ts.map +1 -1
- package/dist/test/scripts/pw-locator-patch/vision/query.js +57 -5
- package/docs/kv.md +66 -2
- package/package.json +4 -5
- package/tsconfig.tsbuildinfo +1 -1
package/dist/kv.d.ts
CHANGED
|
@@ -1,7 +1,37 @@
|
|
|
1
|
+
import { type KvEntryRecord } from "./api-worker-client";
|
|
2
|
+
export type KvEntry<T = unknown> = Omit<KvEntryRecord, "value"> & {
|
|
3
|
+
value: T;
|
|
4
|
+
};
|
|
5
|
+
export type KvEntryMetadata = Omit<KvEntryRecord, "value">;
|
|
6
|
+
export type KvSetOptions = {
|
|
7
|
+
ifAbsent?: boolean;
|
|
8
|
+
ifVersion?: number;
|
|
9
|
+
};
|
|
10
|
+
export type KvListOptions = {
|
|
11
|
+
prefix?: string;
|
|
12
|
+
cursor?: string;
|
|
13
|
+
limit?: number;
|
|
14
|
+
};
|
|
15
|
+
export declare class KvPreconditionFailedError extends Error {
|
|
16
|
+
readonly current: KvEntry | null;
|
|
17
|
+
constructor(key: string, current: KvEntryRecord | null);
|
|
18
|
+
}
|
|
1
19
|
export declare class KVClient {
|
|
2
20
|
private client;
|
|
3
21
|
constructor();
|
|
4
22
|
get<T = unknown>(key: string): Promise<T | null>;
|
|
5
|
-
|
|
23
|
+
getEntry<T = unknown>(key: string): Promise<KvEntry<T> | null>;
|
|
24
|
+
set<T>(key: string, value: T, ttl: number, options?: KvSetOptions): Promise<KvEntry<T>>;
|
|
25
|
+
refresh<T = unknown>(key: string, ttl: number, options?: {
|
|
26
|
+
ifVersion?: number;
|
|
27
|
+
}): Promise<KvEntry<T> | null>;
|
|
28
|
+
delete(key: string, options?: {
|
|
29
|
+
ifVersion?: number;
|
|
30
|
+
}): Promise<boolean>;
|
|
31
|
+
list(options?: KvListOptions): Promise<{
|
|
32
|
+
entries: KvEntryMetadata[];
|
|
33
|
+
nextCursor: string | null;
|
|
34
|
+
}>;
|
|
35
|
+
entries<T = unknown>(prefix?: string): AsyncGenerator<KvEntry<T>>;
|
|
6
36
|
}
|
|
7
37
|
//# sourceMappingURL=kv.d.ts.map
|
package/dist/kv.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kv.d.ts","sourceRoot":"","sources":["../src/kv.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"kv.d.ts","sourceRoot":"","sources":["../src/kv.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAGnB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,OAAO,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,GAAG;IAAE,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AAE/E,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;AAE3D,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtE,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAEjC,YAAY,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,EAQrD;CACF;AAoBD,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAkB;IAEhC,cAEC;IAEK,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAGrD;IAEK,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAGnE;IAEK,GAAG,CAAC,CAAC,EACT,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,CAAC,EACR,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAUrB;IAEK,OAAO,CAAC,CAAC,GAAG,OAAO,EACvB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/B,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAa5B;IAEK,MAAM,CACV,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/B,OAAO,CAAC,OAAO,CAAC,CAMlB;IAEK,IAAI,CACR,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC;QAAE,OAAO,EAAE,eAAe,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CASpE;IAEM,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,SAAK,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAanE;CACF"}
|
package/dist/kv.js
CHANGED
|
@@ -1,18 +1,92 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.KVClient = void 0;
|
|
3
|
+
exports.KVClient = exports.KvPreconditionFailedError = void 0;
|
|
4
4
|
const api_worker_client_1 = require("./api-worker-client");
|
|
5
|
+
class KvPreconditionFailedError extends Error {
|
|
6
|
+
current;
|
|
7
|
+
constructor(key, current) {
|
|
8
|
+
super(current
|
|
9
|
+
? `KV condition failed for "${key}": it is at version ${current.version}`
|
|
10
|
+
: `KV condition failed for "${key}": it does not exist`);
|
|
11
|
+
this.name = "KvPreconditionFailedError";
|
|
12
|
+
this.current = current ? asEntry(current) : null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.KvPreconditionFailedError = KvPreconditionFailedError;
|
|
16
|
+
function asEntry(record) {
|
|
17
|
+
return { ...record, value: record.value };
|
|
18
|
+
}
|
|
19
|
+
function writeCondition(options) {
|
|
20
|
+
if (options?.ifAbsent && options.ifVersion !== undefined) {
|
|
21
|
+
throw new Error("Pass either ifAbsent or ifVersion, not both");
|
|
22
|
+
}
|
|
23
|
+
if (options?.ifAbsent) {
|
|
24
|
+
return { ifAbsent: true };
|
|
25
|
+
}
|
|
26
|
+
return options?.ifVersion === undefined
|
|
27
|
+
? undefined
|
|
28
|
+
: { ifVersion: options.ifVersion };
|
|
29
|
+
}
|
|
5
30
|
class KVClient {
|
|
6
31
|
client;
|
|
7
32
|
constructor() {
|
|
8
33
|
this.client = new api_worker_client_1.ApiWorkerClient();
|
|
9
34
|
}
|
|
10
35
|
async get(key) {
|
|
11
|
-
const
|
|
12
|
-
return
|
|
36
|
+
const entry = await this.getEntry(key);
|
|
37
|
+
return entry ? entry.value : null;
|
|
38
|
+
}
|
|
39
|
+
async getEntry(key) {
|
|
40
|
+
const record = await this.client.getKvEntry(key);
|
|
41
|
+
return record ? asEntry(record) : null;
|
|
42
|
+
}
|
|
43
|
+
async set(key, value, ttl, options) {
|
|
44
|
+
const result = await this.client.putKvEntry(key, { value: value, ttl }, writeCondition(options));
|
|
45
|
+
if (!result.ok) {
|
|
46
|
+
throw new KvPreconditionFailedError(key, result.current);
|
|
47
|
+
}
|
|
48
|
+
return asEntry(result.value);
|
|
49
|
+
}
|
|
50
|
+
async refresh(key, ttl, options) {
|
|
51
|
+
const result = await this.client.refreshKvEntry(key, ttl, options?.ifVersion);
|
|
52
|
+
if (result === null) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
if (!result.ok) {
|
|
56
|
+
throw new KvPreconditionFailedError(key, result.current);
|
|
57
|
+
}
|
|
58
|
+
return asEntry(result.value);
|
|
59
|
+
}
|
|
60
|
+
async delete(key, options) {
|
|
61
|
+
const result = await this.client.deleteKvEntry(key, options?.ifVersion);
|
|
62
|
+
if (!result.ok) {
|
|
63
|
+
throw new KvPreconditionFailedError(key, result.current);
|
|
64
|
+
}
|
|
65
|
+
return result.value;
|
|
66
|
+
}
|
|
67
|
+
async list(options = {}) {
|
|
68
|
+
const page = await this.client.listKvEntries({
|
|
69
|
+
...options,
|
|
70
|
+
include_values: "false",
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
entries: page.entries.map(({ value: _value, ...metadata }) => metadata),
|
|
74
|
+
nextCursor: page.next_cursor,
|
|
75
|
+
};
|
|
13
76
|
}
|
|
14
|
-
async
|
|
15
|
-
|
|
77
|
+
async *entries(prefix = "") {
|
|
78
|
+
let cursor;
|
|
79
|
+
do {
|
|
80
|
+
const page = await this.client.listKvEntries({
|
|
81
|
+
prefix,
|
|
82
|
+
cursor,
|
|
83
|
+
include_values: "true",
|
|
84
|
+
});
|
|
85
|
+
for (const record of page.entries) {
|
|
86
|
+
yield asEntry(record);
|
|
87
|
+
}
|
|
88
|
+
cursor = page.next_cursor ?? undefined;
|
|
89
|
+
} while (cursor);
|
|
16
90
|
}
|
|
17
91
|
}
|
|
18
92
|
exports.KVClient = KVClient;
|
|
@@ -10,7 +10,9 @@ const typesafe_1 = require("../test/scripts/pw-locator-patch/dismiss-overlays/ty
|
|
|
10
10
|
const utils_1 = require("../test/scripts/pw-locator-patch/dismiss-overlays/utils");
|
|
11
11
|
const fixtures_1 = require("./fixtures");
|
|
12
12
|
fixtures_1.test.skip(!process.env.TYPESAFE_API_KEY, "TYPESAFE_API_KEY is not set");
|
|
13
|
-
|
|
13
|
+
function resultsFile() {
|
|
14
|
+
return node_path_1.default.join(fixtures_1.test.info().project.outputDir, "typesafe-overlay-results.jsonl");
|
|
15
|
+
}
|
|
14
16
|
const DISMISS_ATTEMPTS = 3;
|
|
15
17
|
async function actWithTypeSafeDismissal(page, target, action) {
|
|
16
18
|
const results = [];
|
|
@@ -30,8 +32,8 @@ async function actWithTypeSafeDismissal(page, target, action) {
|
|
|
30
32
|
target: await target.elementHandle(),
|
|
31
33
|
});
|
|
32
34
|
results.push(result);
|
|
33
|
-
node_fs_1.default.mkdirSync(node_path_1.default.dirname(
|
|
34
|
-
node_fs_1.default.appendFileSync(
|
|
35
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(resultsFile()), { recursive: true });
|
|
36
|
+
node_fs_1.default.appendFileSync(resultsFile(), JSON.stringify({
|
|
35
37
|
test: fixtures_1.test.info().title,
|
|
36
38
|
attempt,
|
|
37
39
|
overlayText: text,
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const test_1 = require("../test");
|
|
4
4
|
const fixtures_1 = require("./fixtures");
|
|
5
5
|
const expect = (0, test_1.extendExpect)(fixtures_1.expect);
|
|
6
|
-
|
|
6
|
+
fixtures_1.test.skip("toLookRight on page attaches screenshot", async ({ page, server, }, testInfo) => {
|
|
7
7
|
await page.goto(`${server.baseURL}/visual-test.html`);
|
|
8
8
|
await expect(page).toLookRight("A welcome page with a heading and a paragraph of text");
|
|
9
9
|
const pageAttachment = testInfo.attachments.find((a) => a.name.startsWith("toLookRight-"));
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import type { FullResult, Reporter, TestCase, TestResult } from "@playwright/test/reporter";
|
|
1
|
+
import type { FullConfig, FullResult, Reporter, TestCase, TestResult } from "@playwright/test/reporter";
|
|
2
2
|
declare class AttachmentCleanupTestReporter implements Reporter {
|
|
3
3
|
private _timeline;
|
|
4
4
|
private _cleanup;
|
|
5
5
|
private _allAttachmentPaths;
|
|
6
6
|
private _pendingUploads;
|
|
7
7
|
private _queue;
|
|
8
|
+
private _outputDirs;
|
|
8
9
|
constructor();
|
|
9
10
|
onTestEnd(_test: TestCase, result: TestResult): void;
|
|
11
|
+
onBegin(config: FullConfig): void;
|
|
10
12
|
onEnd(_result: FullResult): Promise<void>;
|
|
11
13
|
}
|
|
12
14
|
export default AttachmentCleanupTestReporter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachment-cleanup-test-reporter.d.ts","sourceRoot":"","sources":["../../src/reporter/attachment-cleanup-test-reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,UAAU,EACX,MAAM,2BAA2B,CAAC;AA0CnC,cAAM,6BAA8B,YAAW,QAAQ;IACrD,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,mBAAmB,CAAgB;IAC3C,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,MAAM,CAAkC;
|
|
1
|
+
{"version":3,"file":"attachment-cleanup-test-reporter.d.ts","sourceRoot":"","sources":["../../src/reporter/attachment-cleanup-test-reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,UAAU,EACX,MAAM,2BAA2B,CAAC;AA0CnC,cAAM,6BAA8B,YAAW,QAAQ;IACrD,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,mBAAmB,CAAgB;IAC3C,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,WAAW,CAAgB;IAEnC,cAQC;IAED,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,QAyB5C;IAED,OAAO,CAAC,MAAM,EAAE,UAAU,QAEzB;IAEK,KAAK,CAAC,OAAO,EAAE,UAAU,iBAyB9B;CACF;eAEc,6BAA6B"}
|
|
@@ -39,6 +39,7 @@ class AttachmentCleanupTestReporter {
|
|
|
39
39
|
_allAttachmentPaths = [];
|
|
40
40
|
_pendingUploads = [];
|
|
41
41
|
_queue = new AsyncQueue(MAX_CONCURRENT);
|
|
42
|
+
_outputDirs = [];
|
|
42
43
|
constructor() {
|
|
43
44
|
this._cleanup.onEvict = (evictedPath) => {
|
|
44
45
|
this._timeline.push({
|
|
@@ -72,9 +73,12 @@ class AttachmentCleanupTestReporter {
|
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
}
|
|
76
|
+
onBegin(config) {
|
|
77
|
+
this._outputDirs = config.projects.map((project) => project.outputDir);
|
|
78
|
+
}
|
|
75
79
|
async onEnd(_result) {
|
|
76
80
|
await Promise.allSettled(this._pendingUploads);
|
|
77
|
-
this._cleanup.logSummary();
|
|
81
|
+
this._cleanup.logSummary(this._outputDirs);
|
|
78
82
|
const stats = this._cleanup.stats;
|
|
79
83
|
const existingPaths = this._allAttachmentPaths.filter((p) => fs_1.default.existsSync(p));
|
|
80
84
|
const deletedPaths = this._allAttachmentPaths.filter((p) => !fs_1.default.existsSync(p));
|
|
@@ -17,7 +17,7 @@ export declare class AttachmentCleanup {
|
|
|
17
17
|
markUploaded(attachmentPath: string): void;
|
|
18
18
|
private _evict;
|
|
19
19
|
private _logDiskStatus;
|
|
20
|
-
logSummary(): void;
|
|
20
|
+
logSummary(outputDirs: string[]): void;
|
|
21
21
|
set onEvict(callback: (path: string) => void);
|
|
22
22
|
get stats(): {
|
|
23
23
|
registeredCount: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachment-cleanup.d.ts","sourceRoot":"","sources":["../../src/reporter/attachment-cleanup.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"attachment-cleanup.d.ts","sourceRoot":"","sources":["../../src/reporter/attachment-cleanup.ts"],"names":[],"mappings":"AAqEA,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,SAAS,CAAwC;IACzD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,aAAa,CAA+C;IACpE,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAyC;IAEzD,YAAY,UAAU,GAAE,MAAmC,EAM1D;IAED,QAAQ,CAAC,UAAU,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,QAejD;IAED,YAAY,CAAC,cAAc,EAAE,MAAM,QASlC;IAED,OAAO,CAAC,MAAM;IA4Bd,OAAO,CAAC,cAAc;IAItB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,QAW9B;IAED,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAE3C;IAED,IAAI,KAAK;QAEL,eAAe;QACf,aAAa;QACb,YAAY;QACZ,YAAY;QACZ,YAAY;QACZ,WAAW;QACX,SAAS;QACT,UAAU;MAEb;CACF"}
|
|
@@ -40,16 +40,23 @@ function getDiskUsage() {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
const WORKER_REPO_DIR = "/app/source-repo";
|
|
43
|
-
function
|
|
43
|
+
function shellQuote(value) {
|
|
44
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
45
|
+
}
|
|
46
|
+
function getDiskBreakdown(outputDirs) {
|
|
47
|
+
const outputDirTargets = outputDirs.flatMap((dir) => [
|
|
48
|
+
`${shellQuote(dir)}/.playwright-artifacts-*`,
|
|
49
|
+
shellQuote(dir),
|
|
50
|
+
]);
|
|
44
51
|
try {
|
|
45
|
-
const output = (0, child_process_1.execSync)(
|
|
52
|
+
const output = (0, child_process_1.execSync)(`du -sh ${outputDirTargets.join(" ")} blob-report/ blob-report-incremental/ playwright-report/ /tmp/playwright-artifacts-* /tmp 2>/dev/null | sort -rh`, { encoding: "utf8", timeout: 8000, cwd: WORKER_REPO_DIR }).trim();
|
|
46
53
|
if (!output) {
|
|
47
54
|
return "none";
|
|
48
55
|
}
|
|
49
|
-
|
|
56
|
+
return output
|
|
50
57
|
.split("\n")
|
|
51
|
-
.map((l) => l.replace(
|
|
52
|
-
|
|
58
|
+
.map((l) => l.replace(/\t/g, " "))
|
|
59
|
+
.join(", ");
|
|
53
60
|
}
|
|
54
61
|
catch {
|
|
55
62
|
return "none";
|
|
@@ -129,7 +136,7 @@ class AttachmentCleanup {
|
|
|
129
136
|
_logDiskStatus() {
|
|
130
137
|
this._diskLogTick++;
|
|
131
138
|
}
|
|
132
|
-
logSummary() {
|
|
139
|
+
logSummary(outputDirs) {
|
|
133
140
|
if (this._diskLogTimer) {
|
|
134
141
|
clearInterval(this._diskLogTimer);
|
|
135
142
|
this._diskLogTimer = null;
|
|
@@ -137,7 +144,7 @@ class AttachmentCleanup {
|
|
|
137
144
|
if (!fs_1.default.existsSync(WORKER_REPO_DIR)) {
|
|
138
145
|
return;
|
|
139
146
|
}
|
|
140
|
-
logger_1.logger.info(`[AttachmentCleanup] Summary: registered=${this._registeredCount}, pending=${this._pending.size}, uploaded=${this._uploadedCount}, evicted=${this._evictedCount} (${formatBytes(this._evictedBytes)}), totalSize=${formatBytes(this._totalSize)}, disk=${getDiskUsage()}, breakdown=${getDiskBreakdown()}`);
|
|
147
|
+
logger_1.logger.info(`[AttachmentCleanup] Summary: registered=${this._registeredCount}, pending=${this._pending.size}, uploaded=${this._uploadedCount}, evicted=${this._evictedCount} (${formatBytes(this._evictedBytes)}), totalSize=${formatBytes(this._totalSize)}, disk=${getDiskUsage()}, breakdown=${getDiskBreakdown(outputDirs)}`);
|
|
141
148
|
}
|
|
142
149
|
set onEvict(callback) {
|
|
143
150
|
this._onEvict = callback;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment-key.d.ts","sourceRoot":"","sources":["../../src/reporter/attachment-key.ts"],"names":[],"mappings":"AAWA,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAE7D;AAED,wBAAgB,aAAa,CAC3B,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,CAaR"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.sortOutputDirs = sortOutputDirs;
|
|
7
|
+
exports.attachmentKey = attachmentKey;
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
function isInside(relative) {
|
|
11
|
+
return (relative !== ".." &&
|
|
12
|
+
!relative.startsWith(`..${path_1.default.sep}`) &&
|
|
13
|
+
!path_1.default.isAbsolute(relative));
|
|
14
|
+
}
|
|
15
|
+
function sortOutputDirs(outputDirs) {
|
|
16
|
+
return [...new Set(outputDirs)].sort((a, b) => b.length - a.length);
|
|
17
|
+
}
|
|
18
|
+
function attachmentKey(attachmentPath, outputDirs) {
|
|
19
|
+
for (const dir of outputDirs) {
|
|
20
|
+
const relative = path_1.default.relative(dir, attachmentPath);
|
|
21
|
+
if (isInside(relative)) {
|
|
22
|
+
return relative;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const hash = crypto_1.default
|
|
26
|
+
.createHash("sha1")
|
|
27
|
+
.update(attachmentPath)
|
|
28
|
+
.digest("hex")
|
|
29
|
+
.slice(0, 12);
|
|
30
|
+
return path_1.default.join("external", hash, path_1.default.basename(attachmentPath));
|
|
31
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { FullConfig, FullResult, Reporter, TestCase, TestResult } from "@playwright/test/reporter";
|
|
2
2
|
declare class EmpiricalReporter implements Reporter {
|
|
3
3
|
private _currentWorkingDir;
|
|
4
|
-
private
|
|
4
|
+
private _outputDirs;
|
|
5
5
|
private _pendingTestCaseEvents;
|
|
6
6
|
private _hasSharding;
|
|
7
7
|
private _attachmentUrlMap;
|
|
@@ -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;
|
|
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;AAyBnC,cAAM,iBAAkB,YAAW,QAAQ;IACzC,OAAO,CAAC,kBAAkB,CAAyB;IACnD,OAAO,CAAC,WAAW,CAAgB;IACnC,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;IACrD,OAAO,CAAC,YAAY,CAAqB;IAEzC,cAEC;IAED,OAAO,CAAC,MAAM,EAAE,UAAU,QAKzB;IAED,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,6BAA6B,CAuCnC;IAEF,OAAO,CAAC,WAAW;IAMnB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,QAyB7C;IAED,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,QA4I3C;IAEK,KAAK,CAAC,MAAM,EAAE,UAAU,iBAkH7B;IAED,OAAO,CAAC,qBAAqB;YAkBf,gBAAgB;YAOhB,iBAAiB;CAqChC;eAEc,iBAAiB"}
|
|
@@ -8,6 +8,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
8
8
|
const logger_1 = require("../logger");
|
|
9
9
|
const telemetry_1 = require("../telemetry");
|
|
10
10
|
const attachment_cleanup_1 = require("./attachment-cleanup");
|
|
11
|
+
const attachment_key_1 = require("./attachment-key");
|
|
11
12
|
const blob_utils_1 = require("./blob-utils");
|
|
12
13
|
const failing_line_1 = require("./failing-line");
|
|
13
14
|
const incremental_blob_reporter_1 = require("./incremental-blob-reporter");
|
|
@@ -16,7 +17,7 @@ const uploader_1 = require("./uploader");
|
|
|
16
17
|
const util_1 = require("./util");
|
|
17
18
|
class EmpiricalReporter {
|
|
18
19
|
_currentWorkingDir = process.cwd();
|
|
19
|
-
|
|
20
|
+
_outputDirs = [];
|
|
20
21
|
_pendingTestCaseEvents = [];
|
|
21
22
|
_hasSharding = process.env.HAS_SHARDING === "true";
|
|
22
23
|
_attachmentUrlMap = new Map();
|
|
@@ -29,6 +30,7 @@ class EmpiricalReporter {
|
|
|
29
30
|
}
|
|
30
31
|
onBegin(config) {
|
|
31
32
|
this._maxFailures = config.maxFailures;
|
|
33
|
+
this._outputDirs = (0, attachment_key_1.sortOutputDirs)(config.projects.map((project) => project.outputDir));
|
|
32
34
|
}
|
|
33
35
|
_piSandboxLog(message) {
|
|
34
36
|
const runningInsidePiSandbox = process.env.RUNNING_INSIDE_PI_SANDBOX === "true";
|
|
@@ -51,8 +53,7 @@ class EmpiricalReporter {
|
|
|
51
53
|
return;
|
|
52
54
|
}
|
|
53
55
|
this._attachmentCleanup.register(attachment);
|
|
54
|
-
const
|
|
55
|
-
const destinationPath = `data/${relativePath}`;
|
|
56
|
+
const destinationPath = `data/${(0, attachment_key_1.attachmentKey)(attachment.path, this._outputDirs)}`;
|
|
56
57
|
const publicUrl = await this._uploader.uploadFile(attachment.path, destinationPath, keepHot ? "STANDARD" : undefined);
|
|
57
58
|
if (publicUrl) {
|
|
58
59
|
this._attachmentCleanup.markUploaded(attachment.path);
|
|
@@ -225,7 +226,7 @@ class EmpiricalReporter {
|
|
|
225
226
|
}
|
|
226
227
|
if (htmlExists && jsonExists) {
|
|
227
228
|
logger_1.logger.debug("[Empirical Reporter] Patching HTML with attachment URLs");
|
|
228
|
-
await (0, util_1.updateHtmlZipFileAttachmentPaths)(jsonFilePath, htmlFilePath, this.
|
|
229
|
+
await (0, util_1.updateHtmlZipFileAttachmentPaths)(jsonFilePath, htmlFilePath, this._outputDirs);
|
|
229
230
|
const htmlReportUrl = await this._uploader.uploadFile(htmlFilePath, "index.html");
|
|
230
231
|
this._piSandboxLog(`[Empirical Reporter] HTML report URL: ${htmlReportUrl}`);
|
|
231
232
|
}
|
|
@@ -234,7 +235,7 @@ class EmpiricalReporter {
|
|
|
234
235
|
}
|
|
235
236
|
if (jsonExists) {
|
|
236
237
|
logger_1.logger.debug("[Empirical Reporter] Patching summary.json with attachment URLs");
|
|
237
|
-
await (0, util_1.updateSummaryJsonAttachmentPaths)(jsonFilePath, this.
|
|
238
|
+
await (0, util_1.updateSummaryJsonAttachmentPaths)(jsonFilePath, this._outputDirs, `${this._uploader.urlPrefix}/data`);
|
|
238
239
|
const summaryJsonUrl = await this._uploader.uploadFile(jsonFilePath, "summary.json");
|
|
239
240
|
this._piSandboxLog(`[Empirical Reporter] summary.json URL: ${summaryJsonUrl}`);
|
|
240
241
|
}
|
|
@@ -266,7 +267,7 @@ class EmpiricalReporter {
|
|
|
266
267
|
else {
|
|
267
268
|
logger_1.logger.info(`[Empirical Reporter] Sharding not enabled (HAS_SHARDING=${process.env.HAS_SHARDING})`);
|
|
268
269
|
}
|
|
269
|
-
this._attachmentCleanup.logSummary();
|
|
270
|
+
this._attachmentCleanup.logSummary(this._outputDirs);
|
|
270
271
|
logger_1.logger.debug("[Empirical Reporter] All uploads finished");
|
|
271
272
|
const timeDiff = Date.now() - startTime;
|
|
272
273
|
logger_1.logger.debug("[Empirical Reporter] Time taken to upload after tests ended: ", timeDiff, "ms");
|
|
@@ -37,6 +37,7 @@ export interface SignalRunOptions {
|
|
|
37
37
|
workers: number;
|
|
38
38
|
waitForMarker?: string;
|
|
39
39
|
waitFor?: WaitFor;
|
|
40
|
+
waitForPattern?: RegExp;
|
|
40
41
|
delayBeforeSignalMs?: number;
|
|
41
42
|
signal?: NodeJS.Signals;
|
|
42
43
|
secondSignalAfterMs?: number;
|
|
@@ -81,8 +82,12 @@ export declare function runPlaywrightClean(ctx: ParityTestContext, opts: {
|
|
|
81
82
|
export declare function mergeBlobDirToSummary(cwd: string, blobDir: string, outputName: string): Record<string, unknown>;
|
|
82
83
|
export interface DashboardStub {
|
|
83
84
|
testCaseEvents: () => Array<Record<string, any>>;
|
|
85
|
+
completedUploadPaths: () => string[];
|
|
84
86
|
env: NodeJS.ProcessEnv;
|
|
85
87
|
close: () => Promise<void>;
|
|
86
88
|
}
|
|
87
|
-
export declare function startDashboardStub(
|
|
89
|
+
export declare function startDashboardStub({ slowUploadPathSuffix, slowUploadMs, }?: {
|
|
90
|
+
slowUploadPathSuffix?: string;
|
|
91
|
+
slowUploadMs?: number;
|
|
92
|
+
}): Promise<DashboardStub>;
|
|
88
93
|
//# sourceMappingURL=harness.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../../src/reporter/harness.ts"],"names":[],"mappings":"AA0BA,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,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;AA2CD,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,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,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAID,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,eAAe,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
|
@@ -96,7 +96,7 @@ const WAIT_FOR_PATTERNS = {
|
|
|
96
96
|
};
|
|
97
97
|
const MARKER_RE = /@@ ([A-Z0-9-]+) @@/g;
|
|
98
98
|
async function runPlaywrightWithSignal(ctx, opts) {
|
|
99
|
-
const { workers, waitForMarker, waitFor, delayBeforeSignalMs = 0, signal = "SIGINT", secondSignalAfterMs, killAfterMs, triggerTimeoutMs = 30_000, env, } = opts;
|
|
99
|
+
const { workers, waitForMarker, waitFor, waitForPattern, delayBeforeSignalMs = 0, signal = "SIGINT", secondSignalAfterMs, killAfterMs, triggerTimeoutMs = 30_000, env, } = opts;
|
|
100
100
|
const startedAt = Date.now();
|
|
101
101
|
const since = () => Date.now() - startedAt;
|
|
102
102
|
const child = (0, child_process_1.spawn)(PLAYWRIGHT_BIN, ["test", `--workers=${workers}`], {
|
|
@@ -149,7 +149,7 @@ async function runPlaywrightWithSignal(ctx, opts) {
|
|
|
149
149
|
}
|
|
150
150
|
catch { }
|
|
151
151
|
};
|
|
152
|
-
const pattern = waitFor ? WAIT_FOR_PATTERNS[waitFor] : undefined;
|
|
152
|
+
const pattern = waitForPattern ?? (waitFor ? WAIT_FOR_PATTERNS[waitFor] : undefined);
|
|
153
153
|
const isTriggered = () => waitForMarker
|
|
154
154
|
? markers.some((m) => m.name === waitForMarker)
|
|
155
155
|
: pattern
|
|
@@ -311,8 +311,22 @@ function mergeBlobDirToSummary(cwd, blobDir, outputName) {
|
|
|
311
311
|
});
|
|
312
312
|
return JSON.parse(fs_1.default.readFileSync(outputPath, "utf8"));
|
|
313
313
|
}
|
|
314
|
-
async function startDashboardStub() {
|
|
314
|
+
async function startDashboardStub({ slowUploadPathSuffix, slowUploadMs = 0, } = {}) {
|
|
315
315
|
const events = [];
|
|
316
|
+
const completedUploadPaths = [];
|
|
317
|
+
const respondToUpload = (req, res, uploadPath) => {
|
|
318
|
+
completedUploadPaths.push(uploadPath);
|
|
319
|
+
res.writeHead(200, { "content-type": "application/xml", etag: '"etag"' });
|
|
320
|
+
if (req.method === "POST" && req.url?.includes("?uploads")) {
|
|
321
|
+
res.end("<InitiateMultipartUploadResult><UploadId>upload</UploadId></InitiateMultipartUploadResult>");
|
|
322
|
+
}
|
|
323
|
+
else if (req.method === "POST") {
|
|
324
|
+
res.end('<CompleteMultipartUploadResult><ETag>"etag"</ETag></CompleteMultipartUploadResult>');
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
res.end();
|
|
328
|
+
}
|
|
329
|
+
};
|
|
316
330
|
const server = http_1.default.createServer((req, res) => {
|
|
317
331
|
const chunks = [];
|
|
318
332
|
req.on("data", (c) => chunks.push(c));
|
|
@@ -328,22 +342,17 @@ async function startDashboardStub() {
|
|
|
328
342
|
res.end("{}");
|
|
329
343
|
return;
|
|
330
344
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
else if (req.method === "POST") {
|
|
336
|
-
res.end('<CompleteMultipartUploadResult><ETag>"etag"</ETag></CompleteMultipartUploadResult>');
|
|
337
|
-
}
|
|
338
|
-
else {
|
|
339
|
-
res.end();
|
|
340
|
-
}
|
|
345
|
+
const uploadPath = (req.url ?? "").split("?")[0];
|
|
346
|
+
const isSlow = slowUploadPathSuffix !== undefined &&
|
|
347
|
+
uploadPath.endsWith(slowUploadPathSuffix);
|
|
348
|
+
setTimeout(() => respondToUpload(req, res, uploadPath), isSlow ? slowUploadMs : 0);
|
|
341
349
|
});
|
|
342
350
|
});
|
|
343
351
|
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
344
352
|
const url = `http://127.0.0.1:${server.address().port}`;
|
|
345
353
|
return {
|
|
346
354
|
testCaseEvents: () => [...events],
|
|
355
|
+
completedUploadPaths: () => [...completedUploadPaths],
|
|
347
356
|
env: {
|
|
348
357
|
PROJECT_NAME: "reporter-test",
|
|
349
358
|
TEST_RUN_GITHUB_ACTION_ID: "1",
|
|
@@ -46,6 +46,7 @@ declare class IncrementalBlobReporter implements Reporter {
|
|
|
46
46
|
onStepBegin(test: TestCase, result: TestResult, step: TestStep): void;
|
|
47
47
|
onStepEnd(test: TestCase, result: TestResult, step: TestStep): void;
|
|
48
48
|
onEnd(result: FullResult): Promise<void>;
|
|
49
|
+
private _finalizeOnEnd;
|
|
49
50
|
addAttachmentUrl(localPath: string, remoteUrl: string): void;
|
|
50
51
|
printsToStdio(): boolean;
|
|
51
52
|
}
|
|
@@ -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,SAAS,EACT,UAAU,EACV,QAAQ,EACR,UAAU,EACX,MAAM,2BAA2B,CAAC;AA8BnC,MAAM,MAAM,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAOnD,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,sBAAsB,CAAkC;IAChE,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;IACtD,OAAO,CAAC,QAAQ,CAAyB;IAEzC,cAWC;IAED,OAAO,CAAC,cAAc,CAA6B;IAEnD,OAAO,CAAC,mBAAmB;
|
|
1
|
+
{"version":3,"file":"incremental-blob-reporter.d.ts","sourceRoot":"","sources":["../../src/reporter/incremental-blob-reporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -65,9 +65,6 @@ class IncrementalBlobReporter {
|
|
|
65
65
|
})
|
|
66
66
|
.catch((err) => {
|
|
67
67
|
console.error("[IncrementalBlobReporterFailure] Finalize/upload failed on SIGINT:", err);
|
|
68
|
-
})
|
|
69
|
-
.finally(() => {
|
|
70
|
-
this._removeSignalHandler();
|
|
71
68
|
});
|
|
72
69
|
};
|
|
73
70
|
process.on("SIGINT", this._sigintHandler);
|
|
@@ -264,7 +261,14 @@ class IncrementalBlobReporter {
|
|
|
264
261
|
this._appendEvents((0, lifecycle_events_1.buildOnStepEndEvents)(test, result, step, this._resultIdMap, this._stepIdMap, this._rootDir, this._stagingDir, this._knownAttachmentCounts));
|
|
265
262
|
}
|
|
266
263
|
async onEnd(result) {
|
|
267
|
-
|
|
264
|
+
try {
|
|
265
|
+
await this._finalizeOnEnd(result);
|
|
266
|
+
}
|
|
267
|
+
finally {
|
|
268
|
+
this._removeSignalHandler();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
async _finalizeOnEnd(result) {
|
|
268
272
|
if (this._finalizePromise) {
|
|
269
273
|
await this._finalizePromise;
|
|
270
274
|
this._finalizePromise = this._finalizeAndMaybeUpload({
|
package/dist/reporter/util.d.ts
CHANGED
|
@@ -20,8 +20,8 @@ export declare function suitesAndProjectForTest(test: TestCase): {
|
|
|
20
20
|
export declare function sendTestCaseUpdateToDashboard(params: TestCaseRunEndEventV2): Promise<void>;
|
|
21
21
|
export declare function sendTestCaseBeginToDashboard(params: TestCaseRunBeginEvent): Promise<void>;
|
|
22
22
|
export declare function safelySerialiseJSON(obj: any, keyFilter?: (key: string) => boolean): any;
|
|
23
|
-
export declare function updateHtmlZipFileAttachmentPaths(jsonFilePath: string, htmlFilePath: string,
|
|
24
|
-
export declare function buildTestAttachmentMapFromSummary(summaryJsonFilePath: string,
|
|
23
|
+
export declare function updateHtmlZipFileAttachmentPaths(jsonFilePath: string, htmlFilePath: string, outputDirs: string[]): Promise<void>;
|
|
24
|
+
export declare function buildTestAttachmentMapFromSummary(summaryJsonFilePath: string, outputDirs: string[], doNotNormalize?: boolean): TestAttachmentMap;
|
|
25
25
|
export declare function checkFileExistsAsync(filePath: string): Promise<boolean>;
|
|
26
|
-
export declare function updateSummaryJsonAttachmentPaths(filePath: string,
|
|
26
|
+
export declare function updateSummaryJsonAttachmentPaths(filePath: string, outputDirs: string[], urlPrefix: string): Promise<PlaywrightJSONReport | undefined>;
|
|
27
27
|
//# sourceMappingURL=util.d.ts.map
|
|
@@ -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;AAQhE,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACtB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACL,UAAU,IAAI,oBAAoB,EAElC,QAAQ,EACT,MAAM,2BAA2B,CAAC;
|
|
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,EACL,qBAAqB,EACrB,qBAAqB,EACtB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACL,UAAU,IAAI,oBAAoB,EAElC,QAAQ,EACT,MAAM,2BAA2B,CAAC;AA2BnC,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAqB7D;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,SAAS,UAQhC;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,CA6CD;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,QAAQ;IAmBlD,MAAM;IACN,WAAW;EAEd;AAED,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAoBf;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,UAAU,EAAE,MAAM,EAAE,iBAkFrB;AAED,wBAAgB,iCAAiC,CAC/C,mBAAmB,EAAE,MAAM,EAC3B,UAAU,EAAE,MAAM,EAAE,EACpB,cAAc,GAAE,OAAe,GAC9B,iBAAiB,CAkBnB;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO7E;AAED,wBAAsB,gCAAgC,CACpD,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAAE,EACpB,SAAS,EAAE,MAAM,6CA8BlB"}
|