@empiricalrun/playwright-utils 0.14.17 → 0.14.19

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,18 @@
1
1
  # @empiricalrun/playwright-utils
2
2
 
3
+ ## 0.14.19
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [e547617]
8
+ - @empiricalrun/llm@0.9.12
9
+
10
+ ## 0.14.18
11
+
12
+ ### Patch Changes
13
+
14
+ - 0e75cfc: feat: custom reporter checks all attachments are processed after test run
15
+
3
16
  ## 0.14.17
4
17
 
5
18
  ### Patch Changes
@@ -42,6 +42,7 @@ declare class HtmlReporter implements ReporterV2 {
42
42
  private uploadExecutionQueue;
43
43
  private uploadWaitingQueue;
44
44
  private uploadMaxQueueSize;
45
+ private haveSeenAttachments;
45
46
  private processQueue;
46
47
  private waitForAllTasksToFinish;
47
48
  private _buildResult;
@@ -55,6 +56,7 @@ declare class HtmlReporter implements ReporterV2 {
55
56
  onTestBegin(): void;
56
57
  version(): "v2";
57
58
  onTestEnd(test: TestCasePublic, result: TestResultPublic): void;
59
+ private processTestAttachment;
58
60
  onConfigure(config: FullConfig): void;
59
61
  onBegin(suite: Suite): void;
60
62
  _resolveOptions(): {
@@ -1 +1 @@
1
- {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/reporter/custom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EAEV,KAAK,EACL,QAAQ,IAAI,cAAc,EAC1B,SAAS,EACT,UAAU,IAAI,gBAAgB,EAE/B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAML,UAAU,EAMX,MAAM,2BAA2B,CAAC;AAiBnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAiC/C,QAAA,MAAM,iBAAiB,UAAoC,CAAC;AAC5D,KAAK,oBAAoB,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAM/D,KAAK,mBAAmB,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AA6BF,cAAM,YAAa,YAAW,UAAU;IACtC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,mBAAmB,CAAU;IACrC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,oBAAoB,CAAiC;IAC7D,OAAO,CAAC,kBAAkB,CAAyC;IACnE,OAAO,CAAC,kBAAkB,CAEpB;IAEN,OAAO,CAAC,YAAY;YA4BN,uBAAuB;IAQrC,OAAO,CAAC,YAAY,CAEN;IACd,OAAO,CAAC,eAAe,CAAmB;gBAE9B,OAAO,EAAE,mBAAmB;IAIxC,aAAa;IAIb,QAAQ;IAER,QAAQ;IAER,WAAW;IAEX,SAAS;IAET,WAAW;IAEX,OAAO,IAAI,IAAI;IAIf,SAAS,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,gBAAgB;IA0DxD,WAAW,CAAC,MAAM,EAAE,UAAU;IAI9B,OAAO,CAAC,KAAK,EAAE,KAAK;IAYpB,eAAe,IAAI;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,IAAI,EAAE,oBAAoB,CAAC;QAC3B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;QACzB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;KAC1B;IAsBD,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IASxD,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAIzB,KAAK,CAAC,MAAM,EAAE,UAAU;IAoIxB,MAAM;CA8Bb;AAkCD,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,GAAE,MAAoB,EAC1B,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,iBAqBhB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAsBhE;AAqiBD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/reporter/custom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EAMV,KAAK,EACL,QAAQ,IAAI,cAAc,EAC1B,SAAS,EACT,UAAU,IAAI,gBAAgB,EAE/B,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAML,UAAU,EAMX,MAAM,2BAA2B,CAAC;AAiBnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAiC/C,QAAA,MAAM,iBAAiB,UAAoC,CAAC;AAC5D,KAAK,oBAAoB,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAM/D,KAAK,mBAAmB,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AA6BF,cAAM,YAAa,YAAW,UAAU;IACtC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,mBAAmB,CAAU;IACrC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,oBAAoB,CAAiC;IAC7D,OAAO,CAAC,kBAAkB,CAAyC;IACnE,OAAO,CAAC,kBAAkB,CAEpB;IACN,OAAO,CAAC,mBAAmB,CAAqB;IAEhD,OAAO,CAAC,YAAY;YA4BN,uBAAuB;IAQrC,OAAO,CAAC,YAAY,CAEN;IACd,OAAO,CAAC,eAAe,CAAmB;gBAE9B,OAAO,EAAE,mBAAmB;IAIxC,aAAa;IAIb,QAAQ;IAER,QAAQ;IAER,WAAW;IAEX,SAAS;IAET,WAAW;IAEX,OAAO,IAAI,IAAI;IAIf,SAAS,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,gBAAgB;IAUxD,OAAO,CAAC,qBAAqB;IAoD7B,WAAW,CAAC,MAAM,EAAE,UAAU;IAI9B,OAAO,CAAC,KAAK,EAAE,KAAK;IAYpB,eAAe,IAAI;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,IAAI,EAAE,oBAAoB,CAAC;QAC3B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;QACzB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;KAC1B;IAsBD,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IASxD,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAIzB,KAAK,CAAC,MAAM,EAAE,UAAU;IA+IxB,MAAM;CA8Bb;AAwED,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,GAAE,MAAoB,EAC1B,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,iBAqBhB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAsBhE;AAqiBD,eAAe,YAAY,CAAC"}
@@ -75,6 +75,7 @@ class HtmlReporter {
75
75
  uploadMaxQueueSize = process.env.UPLOAD_MAX_QUEUE_SIZE
76
76
  ? parseInt(process.env.UPLOAD_MAX_QUEUE_SIZE)
77
77
  : 2;
78
+ haveSeenAttachments = new Set();
78
79
  processQueue() {
79
80
  try {
80
81
  while (this.uploadExecutionQueue.length <= this.uploadMaxQueueSize &&
@@ -125,55 +126,60 @@ class HtmlReporter {
125
126
  onTestEnd(test, result) {
126
127
  try {
127
128
  result.attachments.forEach(async (attachment) => {
128
- if (!attachment.path)
129
- return;
130
- const folder = path_1.default.relative(this._outputFolder + "/data", attachment.path);
131
- const folderName = folder.split("/")[0];
132
- // on test gen run, we don't have PROJECT_NAME or TEST_RUN_GITHUB_ACTION_ID so we skip uploading since we anyways handle uploads for that, this is a stopgap
133
- if (!process.env.PROJECT_NAME ||
134
- !process.env.TEST_RUN_GITHUB_ACTION_ID) {
135
- return;
136
- }
137
- try {
138
- const uploadTask = async () => (0, r2_uploader_1.uploadDirectory)({
139
- fileList: [attachment.path],
140
- sourceDir: this._outputFolder + "/data/" + folderName,
141
- destinationDir: process.env.PROJECT_NAME +
142
- "/" +
143
- process.env.TEST_RUN_GITHUB_ACTION_ID +
144
- "/data/" +
145
- folderName,
146
- uploadBucket: "test-report",
147
- });
148
- if (this.uploadExecutionQueue.length <= this.uploadMaxQueueSize) {
149
- const promise = uploadTask()
150
- .catch((e) => {
151
- logger_1.logger.error("Upload failed for", attachment.path, e);
152
- // this.retryTask(uploadTask); // Retry logic
153
- })
154
- .finally(() => {
155
- // this is a list of promises which we dont want to await right now
156
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
157
- this.uploadExecutionQueue = this.uploadExecutionQueue.filter((p) => p !== promise);
158
- this.processQueue(); // Keep processing queue
159
- });
160
- this.uploadExecutionQueue.push(promise);
161
- }
162
- else {
163
- logger_1.logger.debug("Queuing upload task ", attachment.path);
164
- this.uploadWaitingQueue.push(uploadTask);
165
- }
166
- }
167
- catch (e) {
168
- logger_1.logger.error("Error while uploading attachment", e);
169
- // tests shouldn't stop no matter whatever error we get
170
- }
129
+ return this.processTestAttachment(attachment);
171
130
  });
172
131
  }
173
132
  catch (e) {
174
133
  logger_1.logger.error("Error while processing attachments for test", e);
175
134
  }
176
135
  }
136
+ processTestAttachment(attachment) {
137
+ if (!attachment.path)
138
+ return;
139
+ if (this.haveSeenAttachments.has(attachment.path))
140
+ return;
141
+ this.haveSeenAttachments.add(attachment.path);
142
+ const folder = path_1.default.relative(this._outputFolder + "/data", attachment.path);
143
+ const folderName = folder.split("/")[0];
144
+ // on test gen run, we don't have PROJECT_NAME or TEST_RUN_GITHUB_ACTION_ID so we skip uploading since we anyways handle uploads for that, this is a stopgap
145
+ if (!process.env.PROJECT_NAME || !process.env.TEST_RUN_GITHUB_ACTION_ID) {
146
+ return;
147
+ }
148
+ try {
149
+ const uploadTask = async () => (0, r2_uploader_1.uploadDirectory)({
150
+ fileList: [attachment.path],
151
+ sourceDir: this._outputFolder + "/data/" + folderName,
152
+ destinationDir: process.env.PROJECT_NAME +
153
+ "/" +
154
+ process.env.TEST_RUN_GITHUB_ACTION_ID +
155
+ "/data/" +
156
+ folderName,
157
+ uploadBucket: "test-report",
158
+ });
159
+ if (this.uploadExecutionQueue.length <= this.uploadMaxQueueSize) {
160
+ const promise = uploadTask()
161
+ .catch((e) => {
162
+ logger_1.logger.error("Upload failed for", attachment.path, e);
163
+ // this.retryTask(uploadTask); // Retry logic
164
+ })
165
+ .finally(() => {
166
+ // this is a list of promises which we dont want to await right now
167
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
168
+ this.uploadExecutionQueue = this.uploadExecutionQueue.filter((p) => p !== promise);
169
+ this.processQueue(); // Keep processing queue
170
+ });
171
+ this.uploadExecutionQueue.push(promise);
172
+ }
173
+ else {
174
+ logger_1.logger.debug("Queuing upload task ", attachment.path);
175
+ this.uploadWaitingQueue.push(uploadTask);
176
+ }
177
+ }
178
+ catch (e) {
179
+ logger_1.logger.error("Error while uploading attachment", e);
180
+ // tests shouldn't stop no matter whatever error we get
181
+ }
182
+ }
177
183
  onConfigure(config) {
178
184
  this.config = config;
179
185
  }
@@ -231,6 +237,15 @@ class HtmlReporter {
231
237
  try {
232
238
  logger_1.logger.debug("uploading path", this._outputFolder);
233
239
  logger_1.logger.debug("file list", listFilesRecursively(this._outputFolder));
240
+ const summaryJsonPath = path_1.default.join(this._outputFolder, "summary.json");
241
+ if (fs_1.default.existsSync(summaryJsonPath)) {
242
+ logger_1.logger.debug("reading json to ensure all attachments are processed");
243
+ const summaryJson = JSON.parse(fs_1.default.readFileSync(summaryJsonPath, "utf-8"));
244
+ const attachments = getAttachmentsFromJSONReport(summaryJson);
245
+ attachments.forEach(async (attachment) => {
246
+ return this.processTestAttachment(attachment);
247
+ });
248
+ }
234
249
  const tracePath = this._outputFolder + "/trace";
235
250
  const traceExists = fs_1.default.existsSync(tracePath);
236
251
  logger_1.logger.debug("trace exists:", traceExists);
@@ -333,6 +348,42 @@ class HtmlReporter {
333
348
  }
334
349
  }
335
350
  }
351
+ function getAttachmentsFromJSONReport(report) {
352
+ const { suites } = report;
353
+ return getAttachmentsFromSuites(suites);
354
+ }
355
+ function getAttachmentsFromSuites(suites) {
356
+ if (!suites)
357
+ return [];
358
+ if (!suites.length)
359
+ return [];
360
+ let allAttachments = [];
361
+ suites.forEach((currentSuite) => {
362
+ const { specs } = currentSuite;
363
+ const { suites } = currentSuite;
364
+ const attachmentsFromSuites = getAttachmentsFromSuites(suites);
365
+ const attachmentsFromSpecs = getAttachmentsFromSpecs(specs);
366
+ allAttachments = allAttachments.concat(attachmentsFromSuites, attachmentsFromSpecs);
367
+ });
368
+ return allAttachments;
369
+ }
370
+ function getAttachmentsFromSpecs(specs) {
371
+ if (!specs)
372
+ return [];
373
+ if (!specs.length)
374
+ return [];
375
+ let allAttachments = [];
376
+ specs.forEach((spec) => {
377
+ spec.tests.forEach((test) => {
378
+ const { results } = test;
379
+ results.forEach((result) => {
380
+ const { attachments } = result;
381
+ allAttachments = allAttachments.concat(attachments);
382
+ });
383
+ });
384
+ });
385
+ return allAttachments;
386
+ }
336
387
  function reportFolderFromEnv() {
337
388
  // Note: PLAYWRIGHT_HTML_REPORT is for backwards compatibility.
338
389
  const envValue = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/playwright-utils",
3
- "version": "0.14.17",
3
+ "version": "0.14.19",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -40,7 +40,7 @@
40
40
  "playwright-core": "1.47.1",
41
41
  "playwright-extra": "^4.3.6",
42
42
  "puppeteer-extra-plugin-recaptcha": "^3.6.8",
43
- "@empiricalrun/llm": "^0.9.11",
43
+ "@empiricalrun/llm": "^0.9.12",
44
44
  "@empiricalrun/r2-uploader": "^0.3.6"
45
45
  },
46
46
  "scripts": {