@empiricalrun/playwright-utils 0.41.1 → 0.43.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,27 @@
1
1
  # @empiricalrun/playwright-utils
2
2
 
3
+ ## 0.43.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ab403b8: fix: move json report location to avoid accidental agent commits
8
+
9
+ ### Patch Changes
10
+
11
+ - 002127f: feat: add code coverage helper in base fixtures
12
+
13
+ ## 0.42.0
14
+
15
+ ### Minor Changes
16
+
17
+ - c815fc2: feat: use common code to modify html report paths for shard/non-shard
18
+ - d7cdace: feat: added non sharded support to upload partial html and json
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies [c815fc2]
23
+ - @empiricalrun/reporter@0.28.0
24
+
3
25
  ## 0.41.1
4
26
 
5
27
  ### Patch Changes
@@ -49,21 +49,21 @@ function getReporters() {
49
49
  fileName: `report-${process.env.SHARD_INDEX}.zip`,
50
50
  },
51
51
  ],
52
- ...(useIncrementalReporter
53
- ? [
54
- [
55
- "./node_modules/@empiricalrun/playwright-utils/dist/reporter/incremental-blob-reporter.js",
56
- ],
57
- ]
58
- : []),
59
52
  ]
60
53
  : [
61
- ["json", { outputFile: "summary.json" }],
54
+ ["json", { outputFile: "playwright-report/summary.json" }],
62
55
  ["html", { open: "never" }],
63
56
  ];
64
57
  return [
65
58
  ["list"],
66
59
  ...middle,
60
+ ...(useIncrementalReporter
61
+ ? [
62
+ [
63
+ "./node_modules/@empiricalrun/playwright-utils/dist/reporter/incremental-blob-reporter.js",
64
+ ],
65
+ ]
66
+ : []),
67
67
  [
68
68
  "./node_modules/@empiricalrun/playwright-utils/dist/reporter/empirical-reporter.js",
69
69
  ],
@@ -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,QAAQ,EACR,QAAQ,EACR,UAAU,EACX,MAAM,2BAA2B,CAAC;AAqBnC,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;;IAM1C,OAAO,CAAC,6BAA6B,CAkCnC;IAEF,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU;IAuGtC,KAAK,CAAC,MAAM,EAAE,UAAU;IA8G9B,OAAO,CAAC,gBAAgB;YAoBV,gBAAgB;YAOhB,iBAAiB;CAmChC;AAED,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"empirical-reporter.d.ts","sourceRoot":"","sources":["../../src/reporter/empirical-reporter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,UAAU,EACX,MAAM,2BAA2B,CAAC;AAqBnC,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;;IAM1C,OAAO,CAAC,6BAA6B,CAkCnC;IAEF,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU;IAuGtC,KAAK,CAAC,MAAM,EAAE,UAAU;IAkH9B,OAAO,CAAC,gBAAgB;YAoBV,gBAAgB;YAOhB,iBAAiB;CAmChC;AAED,eAAe,iBAAiB,CAAC"}
@@ -134,7 +134,7 @@ class EmpiricalReporter {
134
134
  minute: "2-digit",
135
135
  second: "2-digit",
136
136
  }).format(startTime));
137
- const jsonFilePath = path_1.default.join(this._currentWorkingDir, "summary.json");
137
+ const jsonFilePath = path_1.default.join(this._currentWorkingDir, "playwright-report", "summary.json");
138
138
  const jsonExists = fs_1.default.existsSync(jsonFilePath);
139
139
  const htmlFilePath = path_1.default.join(this._currentWorkingDir, "playwright-report/index.html");
140
140
  const htmlExists = await (0, util_1.checkFileExistsAsync)(htmlFilePath);
@@ -10,6 +10,7 @@ import type { FullConfig, FullResult, Reporter, Suite, TestCase, TestResult, Tes
10
10
  export type AttachmentUrlMap = Map<string, string>;
11
11
  declare class IncrementalBlobReporter implements Reporter {
12
12
  private _currentWorkingDir;
13
+ private _stagingDir;
13
14
  private _outputDir;
14
15
  private _shardIndex;
15
16
  private _totalShards;
@@ -32,7 +33,9 @@ declare class IncrementalBlobReporter implements Reporter {
32
33
  private get _zipPath();
33
34
  private get _jsonlPath();
34
35
  private get _urlsJsonPath();
35
- private _ensureOutputDir;
36
+ private _ensureDirs;
37
+ private _serializePatterns;
38
+ private _embedAttachment;
36
39
  private _generateId;
37
40
  private _getResultId;
38
41
  private _getStepId;
@@ -47,6 +50,7 @@ declare class IncrementalBlobReporter implements Reporter {
47
50
  onStepBegin(test: TestCase, result: TestResult, step: TestStep): void;
48
51
  onStepEnd(test: TestCase, result: TestResult, step: TestStep): void;
49
52
  onEnd(result: FullResult): Promise<void>;
53
+ private _mergeForLocalTest;
50
54
  /**
51
55
  * Add a single attachment URL mapping
52
56
  */
@@ -1 +1 @@
1
- {"version":3,"file":"incremental-blob-reporter.d.ts","sourceRoot":"","sources":["../../src/reporter/incremental-blob-reporter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,UAAU,EACV,QAAQ,EACT,MAAM,2BAA2B,CAAC;AASnC;;;;;;;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,UAAU,CAGhB;IACF,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,UAAU,CAAsB;;IAexC,OAAO,CAAC,cAAc,CAA6B;IAEnD,OAAO,CAAC,mBAAmB;IAwB3B,OAAO,CAAC,oBAAoB;YAOd,eAAe;IA0B7B,OAAO,CAAC,2BAA2B;IA4BnC,OAAO,KAAK,QAAQ,GAKnB;IAED,OAAO,KAAK,UAAU,GAErB;IAED,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,oBAAoB;IAgB5B,OAAO,CAAC,eAAe;IA2BvB,OAAO,CAAC,cAAc;YAQR,SAAS;IAwBvB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IA6E/C,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAerD,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAwCnD,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI;IAmBrE,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI;IAsB7D,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB9C;;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":"AACA,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,UAAU,EACV,QAAQ,EACT,MAAM,2BAA2B,CAAC;AAUnC;;;;;;;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,OAAO,CAA2B;IAC1C,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,UAAU,CAAsB;;IAexC,OAAO,CAAC,cAAc,CAA6B;IAEnD,OAAO,CAAC,mBAAmB;IAwB3B,OAAO,CAAC,oBAAoB;YAOd,eAAe;IAiC7B,OAAO,CAAC,2BAA2B;IA4BnC,OAAO,KAAK,QAAQ,GAKnB;IAED,OAAO,KAAK,UAAU,GAErB;IAED,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,gBAAgB;IAoBxB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,oBAAoB;IAgB5B,OAAO,CAAC,eAAe;IA2BvB,OAAO,CAAC,cAAc;YAQR,SAAS;IAwBvB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IA+E/C,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAerD,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAyCnD,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI;IAmBrE,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI;IAsB7D,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;YAmBhC,kBAAkB;IA2ChC;;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"}
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getIncrementalBlobReporter = getIncrementalBlobReporter;
7
7
  exports.setIncrementalBlobReporterInstance = setIncrementalBlobReporterInstance;
8
8
  const zip_1 = require("@empiricalrun/r2-uploader/zip");
9
+ const child_process_1 = require("child_process");
9
10
  const crypto_1 = __importDefault(require("crypto"));
10
11
  const fs_1 = __importDefault(require("fs"));
11
12
  const os_1 = __importDefault(require("os"));
@@ -14,6 +15,7 @@ const uploader_1 = require("./uploader");
14
15
  const BLOB_REPORT_VERSION = 2;
15
16
  class IncrementalBlobReporter {
16
17
  _currentWorkingDir = process.cwd();
18
+ _stagingDir = path_1.default.join(this._currentWorkingDir, "blob-report-incremental", "staging");
17
19
  _outputDir = path_1.default.join(this._currentWorkingDir, "blob-report-incremental");
18
20
  _shardIndex;
19
21
  _totalShards;
@@ -28,11 +30,14 @@ class IncrementalBlobReporter {
28
30
  _finalized = false;
29
31
  _startTime = Date.now();
30
32
  constructor() {
31
- if (!process.env.SHARD_INDEX || !process.env.TOTAL_SHARDS) {
32
- throw new Error("[IncrementalBlobReporter] SHARD_INDEX and TOTAL_SHARDS environment variables are required");
33
+ if (process.env.SHARD_INDEX && process.env.TOTAL_SHARDS) {
34
+ this._shardIndex = Number.parseInt(process.env.SHARD_INDEX, 10);
35
+ this._totalShards = Number.parseInt(process.env.TOTAL_SHARDS, 10);
36
+ }
37
+ else {
38
+ this._shardIndex = 1;
39
+ this._totalShards = 1;
33
40
  }
34
- this._shardIndex = Number.parseInt(process.env.SHARD_INDEX, 10);
35
- this._totalShards = Number.parseInt(process.env.TOTAL_SHARDS, 10);
36
41
  this._uploader = (0, uploader_1.createUploader)();
37
42
  setIncrementalBlobReporterInstance(this);
38
43
  this._setupSignalHandler();
@@ -74,7 +79,10 @@ class IncrementalBlobReporter {
74
79
  }
75
80
  await this._uploader.uploadFile(this._zipPath, `blobs/incremental-report-${this._shardIndex}.zip`);
76
81
  await this._uploader.waitForUploads();
77
- console.log("[IncrementalBlobReporter] Blob uploaded on SIGINT");
82
+ console.log("[IncrementalBlobReporter] Flush and upload complete on SIGINT");
83
+ if (process.env.LOCAL_TEST === "true") {
84
+ await this._mergeForLocalTest();
85
+ }
78
86
  }
79
87
  _finalizeReportForInterrupt() {
80
88
  if (this._finalized)
@@ -101,14 +109,36 @@ class IncrementalBlobReporter {
101
109
  return path_1.default.join(this._outputDir, `incremental-report-${this._shardIndex}.zip`);
102
110
  }
103
111
  get _jsonlPath() {
104
- return path_1.default.join(this._outputDir, "report.jsonl");
112
+ return path_1.default.join(this._stagingDir, "report.jsonl");
105
113
  }
106
114
  get _urlsJsonPath() {
107
- return path_1.default.join(this._outputDir, "_empirical_urls.json");
115
+ return path_1.default.join(this._stagingDir, "_empirical_urls.json");
108
116
  }
109
- _ensureOutputDir() {
117
+ _ensureDirs() {
118
+ fs_1.default.mkdirSync(this._stagingDir, { recursive: true });
110
119
  fs_1.default.mkdirSync(this._outputDir, { recursive: true });
111
120
  }
121
+ _serializePatterns(patterns) {
122
+ const arr = Array.isArray(patterns) ? patterns : [patterns];
123
+ return arr.map((p) => typeof p === "string"
124
+ ? { s: p }
125
+ : { r: { source: p.source, flags: p.flags } });
126
+ }
127
+ _embedAttachment(attachmentPath, resultId) {
128
+ if (!attachmentPath || !fs_1.default.existsSync(attachmentPath))
129
+ return null;
130
+ const ext = path_1.default.extname(attachmentPath);
131
+ const uniqueName = `${resultId}-${this._generateId()}${ext}`;
132
+ const destPath = path_1.default.join(this._stagingDir, uniqueName);
133
+ try {
134
+ fs_1.default.copyFileSync(attachmentPath, destPath);
135
+ return uniqueName;
136
+ }
137
+ catch (err) {
138
+ console.error(`[IncrementalBlobReporter] Failed to copy attachment ${attachmentPath}:`, err);
139
+ return null;
140
+ }
141
+ }
112
142
  _generateId() {
113
143
  return crypto_1.default.randomBytes(16).toString("hex");
114
144
  }
@@ -180,21 +210,21 @@ class IncrementalBlobReporter {
180
210
  return urlMap;
181
211
  }
182
212
  async _writeZip() {
183
- this._ensureOutputDir();
213
+ this._ensureDirs();
184
214
  // Write report.jsonl to the output directory
185
215
  const jsonlContent = this._reportLines.join("\n") + "\n";
186
216
  fs_1.default.writeFileSync(this._jsonlPath, jsonlContent, "utf8");
187
217
  // Write _empirical_urls.json with attachment URL mappings
188
218
  const urlsJson = this._buildUrlsJson();
189
219
  fs_1.default.writeFileSync(this._urlsJsonPath, JSON.stringify(urlsJson, null, 2), "utf8");
190
- // Create zip from the output directory
191
- const zipBuffer = await (0, zip_1.createZipFromDirectory)(this._outputDir);
220
+ // Create zip from the staging directory
221
+ const zipBuffer = await (0, zip_1.createZipFromDirectory)(this._stagingDir);
192
222
  fs_1.default.writeFileSync(this._zipPath, zipBuffer);
193
223
  console.log(`[IncrementalBlobReporter] Zip updated: ${this._zipPath} (${this._reportLines.length} events, ${this._attachmentUrlMap.size} attachments)`);
194
224
  }
195
225
  onBegin(config, suite) {
196
226
  this._config = config;
197
- this._ensureOutputDir();
227
+ this._ensureDirs();
198
228
  // 1. Emit onBlobReportMetadata (first event)
199
229
  const osName = process.platform === "darwin" ? "macOS" : process.platform;
200
230
  const osVersion = os_1.default.release();
@@ -242,12 +272,14 @@ class IncrementalBlobReporter {
242
272
  repeatEach: project.repeatEach,
243
273
  retries: project.retries,
244
274
  testDir: project.testDir,
245
- testIgnore: project.testIgnore,
246
- testMatch: project.testMatch,
275
+ testIgnore: this._serializePatterns(project.testIgnore),
276
+ testMatch: this._serializePatterns(project.testMatch),
247
277
  timeout: project.timeout,
248
278
  suites,
249
- grep: project.grep,
250
- grepInvert: project.grepInvert,
279
+ grep: this._serializePatterns(project.grep),
280
+ grepInvert: project.grepInvert
281
+ ? this._serializePatterns(project.grepInvert)
282
+ : [],
251
283
  dependencies: project.dependencies,
252
284
  snapshotDir: project.snapshotDir,
253
285
  use: project.use,
@@ -275,6 +307,7 @@ class IncrementalBlobReporter {
275
307
  const resultId = this._getResultId(test.id, result.retry);
276
308
  // Emit separate onAttach for each attachment (matching Playwright's blob format)
277
309
  for (const attachment of result.attachments) {
310
+ const embeddedPath = this._embedAttachment(attachment.path, resultId);
278
311
  this._appendEvent("onAttach", {
279
312
  testId: test.id,
280
313
  resultId,
@@ -282,7 +315,7 @@ class IncrementalBlobReporter {
282
315
  {
283
316
  name: attachment.name,
284
317
  contentType: attachment.contentType,
285
- path: attachment.path,
318
+ path: embeddedPath ?? attachment.path,
286
319
  },
287
320
  ],
288
321
  });
@@ -359,6 +392,33 @@ class IncrementalBlobReporter {
359
392
  await this._writeZip();
360
393
  console.log(`[IncrementalBlobReporter] Finished with status: ${result.status}`);
361
394
  }
395
+ async _mergeForLocalTest() {
396
+ const htmlOutputDir = path_1.default.join(this._currentWorkingDir, "partial-playwright-report");
397
+ const summaryJsonPath = path_1.default.join(this._currentWorkingDir, "partial-summary.json");
398
+ console.log(`[IncrementalBlobReporter] Running merge report on ${this._outputDir}`);
399
+ try {
400
+ (0, child_process_1.execFileSync)("npx", [
401
+ "playwright",
402
+ "merge-reports",
403
+ this._outputDir,
404
+ "--reporter",
405
+ "html,json",
406
+ ], {
407
+ cwd: this._currentWorkingDir,
408
+ env: {
409
+ ...process.env,
410
+ PLAYWRIGHT_HTML_OPEN: "never",
411
+ PLAYWRIGHT_HTML_OUTPUT_DIR: htmlOutputDir,
412
+ PLAYWRIGHT_JSON_OUTPUT_NAME: summaryJsonPath,
413
+ },
414
+ stdio: "inherit",
415
+ });
416
+ console.log(`[IncrementalBlobReporter] Merge report completed. HTML: ${htmlOutputDir}, JSON: ${summaryJsonPath}`);
417
+ }
418
+ catch (err) {
419
+ console.error(`[IncrementalBlobReporter] Merge report failed:`, err);
420
+ }
421
+ }
362
422
  /**
363
423
  * Add a single attachment URL mapping
364
424
  */
@@ -1,5 +1,6 @@
1
- import { GenericPlaywrightAttachment, TestCaseRunEndEventV2 } from "@empiricalrun/shared-types/playwright-utils";
2
- import { JSONReportSpec, JSONReport as PlaywrightJSONReport, TestCase } from "@playwright/test/reporter";
1
+ import type { TestAttachmentMap } from "@empiricalrun/reporter";
2
+ import { TestCaseRunEndEventV2 } from "@empiricalrun/shared-types/playwright-utils";
3
+ import { JSONReport as PlaywrightJSONReport, TestCase } from "@playwright/test/reporter";
3
4
  export declare function getPackageJsonPath(folderPath: string): string;
4
5
  export declare function resolveReporterOutputPath(defaultValue: string, configDir: string, configValue: string | undefined): string;
5
6
  export declare function normalizeAndSaveAttachment(outputPath: string, name: string, options?: {
@@ -30,19 +31,13 @@ export declare function updateHtmlZipFileAttachmentPaths(jsonFilePath: string, h
30
31
  * objects containing attachments with updated path for each test result
31
32
  * @returns void
32
33
  */
33
- export declare function replaceMediaPaths(jsonData: any, testAttachmentMap: Map<string, {
34
- attachments: GenericPlaywrightAttachment[];
35
- }[]>): void;
36
- export declare function traverseJsonReportSuites(summaryJson: PlaywrightJSONReport, specFn: (spec: JSONReportSpec) => void): void;
37
34
  /**
38
35
  * Builds a map from test ID to an array of objects containing attachments for each result (retry).
39
36
  * The attachments are normalized to use relative paths starting with 'data/'.
40
37
  * @param summaryJsonFilePath Path to the summary JSON file
41
38
  * @returns Map<string, { attachments: GenericPlaywrightAttachment[] }[]>
42
39
  */
43
- export declare function buildTestAttachmentMapFromSummary(summaryJsonFilePath: string, repoPath: string, doNotNormalize?: boolean): Map<string, {
44
- attachments: GenericPlaywrightAttachment[];
45
- }[]>;
40
+ export declare function buildTestAttachmentMapFromSummary(summaryJsonFilePath: string, repoPath: string, doNotNormalize?: boolean): TestAttachmentMap;
46
41
  /**
47
42
  * Checks asynchronously if a file exists at the given path.
48
43
  * @param filePath - The path to the file to check
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/reporter/util.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,2BAA2B,EAC3B,qBAAqB,EACtB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACL,cAAc,EAGd,UAAU,IAAI,oBAAoB,EAElC,QAAQ,EACT,MAAM,2BAA2B,CAAC;AAmBnC,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,CAyDf;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,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,GAAG,EACb,iBAAiB,EAAE,GAAG,CACpB,MAAM,EACN;IAAE,WAAW,EAAE,2BAA2B,EAAE,CAAA;CAAE,EAAE,CACjD,QA+BF;AAGD,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,oBAAoB,EACjC,MAAM,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,QAavC;AAED;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAC/C,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,MAAM,EAChB,cAAc,GAAE,OAAe,GAC9B,GAAG,CAAC,MAAM,EAAE;IAAE,WAAW,EAAE,2BAA2B,EAAE,CAAA;CAAE,EAAE,CAAC,CA4C/D;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,6CAoClB"}
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;AAmBnC,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,CAyDf;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"}
@@ -10,12 +10,11 @@ exports.suitesAndProjectForTest = suitesAndProjectForTest;
10
10
  exports.sendTestCaseUpdateToDashboard = sendTestCaseUpdateToDashboard;
11
11
  exports.safelySerialiseJSON = safelySerialiseJSON;
12
12
  exports.updateHtmlZipFileAttachmentPaths = updateHtmlZipFileAttachmentPaths;
13
- exports.replaceMediaPaths = replaceMediaPaths;
14
- exports.traverseJsonReportSuites = traverseJsonReportSuites;
15
13
  exports.buildTestAttachmentMapFromSummary = buildTestAttachmentMapFromSummary;
16
14
  exports.checkFileExistsAsync = checkFileExistsAsync;
17
15
  exports.updateSummaryJsonAttachmentPaths = updateSummaryJsonAttachmentPaths;
18
16
  const zip_1 = require("@empiricalrun/r2-uploader/zip");
17
+ const reporter_1 = require("@empiricalrun/reporter");
19
18
  const async_retry_1 = __importDefault(require("async-retry"));
20
19
  const fs_1 = __importDefault(require("fs"));
21
20
  const path_1 = __importDefault(require("path"));
@@ -191,14 +190,14 @@ async function updateHtmlZipFileAttachmentPaths(jsonFilePath, htmlFilePath, repo
191
190
  try {
192
191
  const reportPath = path_1.default.join(tempDir, "report.json");
193
192
  const reportData = JSON.parse(await fs_1.default.promises.readFile(reportPath, "utf8"));
194
- replaceMediaPaths(reportData, testAttachmentMap);
193
+ (0, reporter_1.replaceMediaPaths)(reportData, testAttachmentMap);
195
194
  await fs_1.default.promises.writeFile(reportPath, JSON.stringify(reportData, null, 2), "utf8");
196
195
  const files = await fs_1.default.promises.readdir(tempDir);
197
196
  for (const file of files.filter((f) => f.endsWith(".json") && f !== "report.json")) {
198
197
  try {
199
198
  const filePath = path_1.default.join(tempDir, file);
200
199
  const jsonData = JSON.parse(await fs_1.default.promises.readFile(filePath, "utf8"));
201
- replaceMediaPaths(jsonData, testAttachmentMap);
200
+ (0, reporter_1.replaceMediaPaths)(jsonData, testAttachmentMap);
202
201
  await fs_1.default.promises.writeFile(filePath, JSON.stringify(jsonData, null, 2), "utf8");
203
202
  }
204
203
  catch (err) {
@@ -238,48 +237,6 @@ async function updateHtmlZipFileAttachmentPaths(jsonFilePath, htmlFilePath, repo
238
237
  * objects containing attachments with updated path for each test result
239
238
  * @returns void
240
239
  */
241
- function replaceMediaPaths(jsonData, testAttachmentMap) {
242
- const testsArray = jsonData.files?.flatMap((f) => f.tests) || jsonData.tests || [];
243
- if (!testsArray.length) {
244
- console.warn("⚠️ No test entries found in JSON.");
245
- return;
246
- }
247
- for (const test of testsArray) {
248
- const testId = test?.testId;
249
- if (!testId) {
250
- console.warn("⚠️ Test without testId encountered, skipping.");
251
- continue;
252
- }
253
- const mapped = testAttachmentMap.get(testId);
254
- if (!mapped) {
255
- console.warn(`⚠️ No mapped attachments found for test: "${testId}"`);
256
- continue;
257
- }
258
- // Update each result's attachments directly by index
259
- for (let i = 0; i < (test.results || []).length; i++) {
260
- const result = test.results[i];
261
- const mappedResult = mapped[i];
262
- if (!result || !mappedResult)
263
- continue;
264
- // Overwrite the attachments array directly
265
- result.attachments = mappedResult.attachments;
266
- }
267
- }
268
- }
269
- // Generic suite traversal utility
270
- function traverseJsonReportSuites(summaryJson, specFn) {
271
- function recurse(suite) {
272
- for (const spec of suite.specs || []) {
273
- specFn(spec);
274
- }
275
- for (const childSuite of suite.suites || []) {
276
- recurse(childSuite);
277
- }
278
- }
279
- for (const suite of summaryJson.suites || []) {
280
- recurse(suite);
281
- }
282
- }
283
240
  /**
284
241
  * Builds a map from test ID to an array of objects containing attachments for each result (retry).
285
242
  * The attachments are normalized to use relative paths starting with 'data/'.
@@ -288,32 +245,16 @@ function traverseJsonReportSuites(summaryJson, specFn) {
288
245
  */
289
246
  function buildTestAttachmentMapFromSummary(summaryJsonFilePath, repoPath, doNotNormalize = false) {
290
247
  const summaryJson = JSON.parse(fs_1.default.readFileSync(summaryJsonFilePath, "utf8"));
291
- const testAttachmentMap = new Map();
292
- function normalizeAttachmentPath(attachment) {
293
- if (!attachment?.path)
294
- return attachment;
295
- const relativePath = path_1.default.relative(repoPath, attachment.path);
296
- attachment.path = path_1.default.join("data", relativePath);
297
- return attachment;
298
- }
299
- const buildTestAttachmentMap = (spec) => {
300
- const testId = spec.id;
301
- for (const test of spec.tests) {
302
- if (!testId) {
303
- console.warn("⚠️ Test without testId encountered, skipping.");
304
- continue;
305
- }
306
- const resultAttachments = (test.results || []).map((result) => ({
307
- attachments: (result.attachments || []).map(doNotNormalize ? (a) => a : normalizeAttachmentPath),
308
- }));
309
- testAttachmentMap.set(testId, [
310
- ...(testAttachmentMap.get(testId) || []),
311
- ...resultAttachments,
312
- ]);
313
- }
314
- };
315
- traverseJsonReportSuites(summaryJson, buildTestAttachmentMap);
316
- return testAttachmentMap;
248
+ return (0, reporter_1.buildTestAttachmentMap)(summaryJson, {
249
+ transformAttachment: doNotNormalize
250
+ ? undefined
251
+ : (attachment) => {
252
+ if (!attachment?.path)
253
+ return attachment;
254
+ const relativePath = path_1.default.relative(repoPath, attachment.path);
255
+ return { ...attachment, path: path_1.default.join("data", relativePath) };
256
+ },
257
+ });
317
258
  }
318
259
  /**
319
260
  * Checks asynchronously if a file exists at the given path.
@@ -346,22 +287,18 @@ async function updateSummaryJsonAttachmentPaths(filePath, repoPath, urlPrefix) {
346
287
  return;
347
288
  }
348
289
  const summaryJson = JSON.parse(await fs_1.default.promises.readFile(filePath, "utf8"));
349
- const updateAttachmentPath = (spec) => {
290
+ (0, reporter_1.traverseJsonReportSuites)(summaryJson, (spec) => {
350
291
  for (const test of spec.tests) {
351
292
  for (const result of test.results || []) {
352
- if (result.attachments) {
353
- for (const attachment of result.attachments) {
354
- if (attachment && attachment.path) {
355
- const relativePath = path_1.default.relative(repoPath, attachment.path);
356
- const newPath = `${urlPrefix}/${relativePath}`;
357
- attachment.path = newPath;
358
- }
293
+ for (const attachment of result.attachments || []) {
294
+ if (attachment?.path) {
295
+ const relativePath = path_1.default.relative(repoPath, attachment.path);
296
+ attachment.path = `${urlPrefix}/${relativePath}`;
359
297
  }
360
298
  }
361
299
  }
362
300
  }
363
- };
364
- traverseJsonReportSuites(summaryJson, updateAttachmentPath);
301
+ });
365
302
  await fs_1.default.promises.writeFile(filePath, JSON.stringify(summaryJson, null, 2), "utf8");
366
303
  return summaryJson;
367
304
  }
@@ -0,0 +1,9 @@
1
+ import type { BrowserContext } from "@playwright/test";
2
+ export declare function setupCoverageCollection(context: BrowserContext): Promise<string[]>;
3
+ export declare function collectAndAttachCoverage(context: BrowserContext, coverageFiles: string[], testInfo: {
4
+ attach: (name: string, options: {
5
+ path: string;
6
+ contentType: string;
7
+ }) => Promise<void>;
8
+ }): Promise<void>;
9
+ //# sourceMappingURL=coverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/test/coverage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAYvD,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,cAAc,qBAwBpE;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,cAAc,EACvB,aAAa,EAAE,MAAM,EAAE,EACvB,QAAQ,EAAE;IACR,MAAM,EAAE,CACN,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,KAC3C,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,iBAqBF"}
@@ -0,0 +1,46 @@
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.setupCoverageCollection = setupCoverageCollection;
7
+ exports.collectAndAttachCoverage = collectAndAttachCoverage;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const istanbulCLIOutput = path_1.default.join(process.cwd(), ".nyc_output");
11
+ function generateCoverageFilename() {
12
+ const timestamp = Date.now();
13
+ const random = Math.random().toString(36).substring(2, 8);
14
+ return `coverage_${timestamp}_${random}.json`;
15
+ }
16
+ async function setupCoverageCollection(context) {
17
+ const coverageFiles = [];
18
+ await context.addInitScript(() => window.addEventListener("beforeunload", () => window.collectIstanbulCoverage(JSON.stringify(window.__coverage__))));
19
+ await fs_1.default.promises.mkdir(istanbulCLIOutput, { recursive: true });
20
+ await context.exposeFunction("collectIstanbulCoverage", (coverageJSON) => {
21
+ if (coverageJSON) {
22
+ const filepath = path_1.default.join(istanbulCLIOutput, generateCoverageFilename());
23
+ fs_1.default.writeFileSync(filepath, coverageJSON);
24
+ coverageFiles.push(filepath);
25
+ }
26
+ });
27
+ return coverageFiles;
28
+ }
29
+ async function collectAndAttachCoverage(context, coverageFiles, testInfo) {
30
+ for (const page of context.pages()) {
31
+ try {
32
+ await page.evaluate(() => window.collectIstanbulCoverage(JSON.stringify(window.__coverage__)));
33
+ }
34
+ catch {
35
+ // Page might be closed or coverage not available
36
+ }
37
+ }
38
+ for (const filepath of coverageFiles) {
39
+ if (fs_1.default.existsSync(filepath)) {
40
+ await testInfo.attach(path_1.default.basename(filepath), {
41
+ path: filepath,
42
+ contentType: "application/json",
43
+ });
44
+ }
45
+ }
46
+ }
@@ -3,7 +3,7 @@ import { KVClient } from "../kv";
3
3
  import { PostgresClient } from "../postgres";
4
4
  import { type WebhookMatcherOptions } from "./expect";
5
5
  import { injectLocatorHighlightScripts } from "./scripts";
6
- import { HighlighterOpts } from "./types";
6
+ import { type BaseTestFixtureOpts } from "./types";
7
7
  import { setVideoLabel } from "./video-labels";
8
8
  declare global {
9
9
  namespace PlaywrightTest {
@@ -24,6 +24,6 @@ type TestOptions = {
24
24
  }>;
25
25
  saveVideos: void;
26
26
  };
27
- declare const baseTestFixture: (testFn: TestType<PlaywrightTestArgs & PlaywrightTestOptions, PlaywrightWorkerArgs & PlaywrightWorkerOptions>, options?: HighlighterOpts) => TestType<PlaywrightTestArgs & PlaywrightTestOptions & TestOptions, PlaywrightWorkerArgs & PlaywrightWorkerOptions>;
27
+ declare const baseTestFixture: (testFn: TestType<PlaywrightTestArgs & PlaywrightTestOptions, PlaywrightWorkerArgs & PlaywrightWorkerOptions>, options?: BaseTestFixtureOpts) => TestType<PlaywrightTestArgs & PlaywrightTestOptions & TestOptions, PlaywrightWorkerArgs & PlaywrightWorkerOptions>;
28
28
  export { baseTestFixture, extendExpect, injectLocatorHighlightScripts, setVideoLabel, };
29
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,MAAM,EACN,IAAI,EACJ,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,QAAQ,EACT,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,6BAA6B,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAA8B,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE3E,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,cAAc,CAAC;QACvB,UAAU,QAAQ,CAAC,CAAC;YAClB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAC7C,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;SACnE;KACF;CACF;AAED,QAAA,MAAM,YAAY,GAAa,gBAAgB,OAAO,MAAM,0CAG3D,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,QAAQ,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,yBAAyB,EAAE,CACzB,OAAO,CAAC,EAAE,qBAAqB,KAC5B,OAAO,CAAC;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IACtD,UAAU,EAAE,IAAI,CAAC;CAClB,CAAC;AAYF,QAAA,MAAM,eAAe,GACnB,QAAQ,QAAQ,CACd,kBAAkB,GAAG,qBAAqB,EAC1C,oBAAoB,GAAG,uBAAuB,CAC/C,EACD,UAAS,eAAgC,uHA2G1C,CAAC;AAEF,OAAO,EACL,eAAe,EACf,YAAY,EACZ,6BAA6B,EAC7B,aAAa,GACd,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,MAAM,EACN,IAAI,EACJ,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,QAAQ,EACT,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,6BAA6B,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,KAAK,mBAAmB,EAAwB,MAAM,SAAS,CAAC;AACzE,OAAO,EAA8B,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE3E,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,cAAc,CAAC;QACvB,UAAU,QAAQ,CAAC,CAAC;YAClB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAC7C,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;SACnE;KACF;CACF;AAED,QAAA,MAAM,YAAY,GAAa,gBAAgB,OAAO,MAAM,0CAG3D,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,QAAQ,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,yBAAyB,EAAE,CACzB,OAAO,CAAC,EAAE,qBAAqB,KAC5B,OAAO,CAAC;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IACtD,UAAU,EAAE,IAAI,CAAC;CAClB,CAAC;AAYF,QAAA,MAAM,eAAe,GACnB,QAAQ,QAAQ,CACd,kBAAkB,GAAG,qBAAqB,EAC1C,oBAAoB,GAAG,uBAAuB,CAC/C,EACD,UAAS,mBAAoC,uHAqH9C,CAAC;AAEF,OAAO,EACL,eAAe,EACf,YAAY,EACZ,6BAA6B,EAC7B,aAAa,GACd,CAAC"}
@@ -7,6 +7,7 @@ exports.setVideoLabel = exports.injectLocatorHighlightScripts = exports.extendEx
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const kv_1 = require("../kv");
9
9
  const postgres_1 = require("../postgres");
10
+ const coverage_1 = require("./coverage");
10
11
  const expect_1 = require("./expect");
11
12
  const scripts_1 = require("./scripts");
12
13
  Object.defineProperty(exports, "injectLocatorHighlightScripts", { enumerable: true, get: function () { return scripts_1.injectLocatorHighlightScripts; } });
@@ -26,6 +27,7 @@ const defaultOptions = {
26
27
  agentCapabilities: true,
27
28
  };
28
29
  const baseTestFixture = function (testFn, options = defaultOptions) {
30
+ const coverageEnabled = options.collectCoverage ?? false;
29
31
  const extendedTestFn = testFn.extend({
30
32
  context: async ({ browser }, use, testInfo) => {
31
33
  const context = await browser.newContext({
@@ -36,7 +38,14 @@ const baseTestFixture = function (testFn, options = defaultOptions) {
36
38
  });
37
39
  const pages = [];
38
40
  context.on("page", (page) => pages.push(page));
41
+ let coverageFiles = [];
42
+ if (coverageEnabled) {
43
+ coverageFiles = await (0, coverage_1.setupCoverageCollection)(context);
44
+ }
39
45
  await use(context);
46
+ if (coverageEnabled) {
47
+ await (0, coverage_1.collectAndAttachCoverage)(context, coverageFiles, testInfo);
48
+ }
40
49
  if (!testPages.has(testInfo.testId)) {
41
50
  testPages.set(testInfo.testId, []);
42
51
  }
@@ -4,4 +4,7 @@ export type HighlighterOpts = {
4
4
  visionMethods?: boolean;
5
5
  agentCapabilities?: boolean;
6
6
  };
7
+ export type BaseTestFixtureOpts = HighlighterOpts & {
8
+ collectCoverage?: boolean;
9
+ };
7
10
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/test/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/test/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG;IAClD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/playwright-utils",
3
- "version": "0.41.1",
3
+ "version": "0.43.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -46,7 +46,8 @@
46
46
  "@empiricalrun/cua": "^0.3.0",
47
47
  "@empiricalrun/dashboard-client": "^0.2.0",
48
48
  "@empiricalrun/llm": "^0.26.0",
49
- "@empiricalrun/r2-uploader": "^0.9.1"
49
+ "@empiricalrun/r2-uploader": "^0.9.1",
50
+ "@empiricalrun/reporter": "^0.28.0"
50
51
  },
51
52
  "scripts": {
52
53
  "dev": "tsc --build --watch",
@@ -1 +1 @@
1
- {"root":["./src/email.ts","./src/index.ts","./src/kv.ts","./src/logger.ts","./src/mailosaur-client.ts","./src/playwright-extensions.ts","./src/postgres.ts","./src/telemetry.ts","./src/webhook.ts","./src/auth/google.ts","./src/auth/index.ts","./src/auth/types.ts","./src/captcha/index.ts","./src/config/index.ts","./src/config/proxy.ts","./src/config/devices/types.ts","./src/overlay-tests/cache.spec.ts","./src/overlay-tests/click.spec.ts","./src/overlay-tests/fixtures.ts","./src/overlay-tests/patch.spec.ts","./src/reporter/blob-utils.ts","./src/reporter/empirical-reporter.ts","./src/reporter/failing-line.ts","./src/reporter/incremental-blob-reporter.ts","./src/reporter/uploader.ts","./src/reporter/util.ts","./src/test/constants.ts","./src/test/index.ts","./src/test/types.ts","./src/test/video-labels.ts","./src/test/expect/index.ts","./src/test/expect/types.ts","./src/test/expect/visual.ts","./src/test/expect/webhook.ts","./src/test/scripts/agent-capabilities.ts","./src/test/scripts/index.ts","./src/test/scripts/locator-highlights.ts","./src/test/scripts/locator-vision.ts","./src/test/scripts/mouse-pointer.ts","./src/test/scripts/types.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/cache.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/index.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/prompt.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/types.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/utils.ts","./src/test/scripts/pw-locator-patch/highlight/click.ts","./src/test/scripts/pw-locator-patch/highlight/expect.ts","./src/test/scripts/pw-locator-patch/highlight/hover.ts","./src/test/scripts/pw-locator-patch/highlight/inner-text.ts","./src/test/scripts/pw-locator-patch/highlight/input-value.ts","./src/test/scripts/pw-locator-patch/highlight/is-checked.ts","./src/test/scripts/pw-locator-patch/highlight/is-disabled.ts","./src/test/scripts/pw-locator-patch/highlight/is-editable.ts","./src/test/scripts/pw-locator-patch/highlight/text-content.ts","./src/test/scripts/pw-locator-patch/utils/index.ts","./src/test/scripts/pw-locator-patch/vision/query.ts"],"version":"5.8.3"}
1
+ {"root":["./src/email.ts","./src/index.ts","./src/kv.ts","./src/logger.ts","./src/mailosaur-client.ts","./src/playwright-extensions.ts","./src/postgres.ts","./src/telemetry.ts","./src/webhook.ts","./src/auth/google.ts","./src/auth/index.ts","./src/auth/types.ts","./src/captcha/index.ts","./src/config/index.ts","./src/config/proxy.ts","./src/config/devices/types.ts","./src/overlay-tests/cache.spec.ts","./src/overlay-tests/click.spec.ts","./src/overlay-tests/fixtures.ts","./src/overlay-tests/patch.spec.ts","./src/reporter/blob-utils.ts","./src/reporter/empirical-reporter.ts","./src/reporter/failing-line.ts","./src/reporter/incremental-blob-reporter.ts","./src/reporter/uploader.ts","./src/reporter/util.ts","./src/test/constants.ts","./src/test/coverage.ts","./src/test/index.ts","./src/test/types.ts","./src/test/video-labels.ts","./src/test/expect/index.ts","./src/test/expect/types.ts","./src/test/expect/visual.ts","./src/test/expect/webhook.ts","./src/test/scripts/agent-capabilities.ts","./src/test/scripts/index.ts","./src/test/scripts/locator-highlights.ts","./src/test/scripts/locator-vision.ts","./src/test/scripts/mouse-pointer.ts","./src/test/scripts/types.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/cache.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/index.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/prompt.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/types.ts","./src/test/scripts/pw-locator-patch/dismiss-overlays/utils.ts","./src/test/scripts/pw-locator-patch/highlight/click.ts","./src/test/scripts/pw-locator-patch/highlight/expect.ts","./src/test/scripts/pw-locator-patch/highlight/hover.ts","./src/test/scripts/pw-locator-patch/highlight/inner-text.ts","./src/test/scripts/pw-locator-patch/highlight/input-value.ts","./src/test/scripts/pw-locator-patch/highlight/is-checked.ts","./src/test/scripts/pw-locator-patch/highlight/is-disabled.ts","./src/test/scripts/pw-locator-patch/highlight/is-editable.ts","./src/test/scripts/pw-locator-patch/highlight/text-content.ts","./src/test/scripts/pw-locator-patch/utils/index.ts","./src/test/scripts/pw-locator-patch/vision/query.ts"],"version":"5.8.3"}