@empiricalrun/playwright-utils 0.18.15 → 0.18.18

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,25 @@
1
1
  # @empiricalrun/playwright-utils
2
2
 
3
+ ## 0.18.18
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [05f9a03]
8
+ - @empiricalrun/test-gen@0.38.43
9
+
10
+ ## 0.18.17
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies [2e5073f]
15
+ - @empiricalrun/test-gen@0.38.42
16
+
17
+ ## 0.18.16
18
+
19
+ ### Patch Changes
20
+
21
+ - 8952f35: fix: new task queue in custom reporter to wait on test case events
22
+
3
23
  ## 0.18.15
4
24
 
5
25
  ### Patch Changes
@@ -39,12 +39,7 @@ declare class HtmlReporter implements ReporterV2 {
39
39
  private _open;
40
40
  private _port;
41
41
  private _host;
42
- private uploadExecutionQueue;
43
- private uploadWaitingQueue;
44
- private uploadMaxQueueSize;
45
42
  private haveSeenAttachments;
46
- private processQueue;
47
- private waitForAllTasksToFinish;
48
43
  private _buildResult;
49
44
  private _topLevelErrors;
50
45
  constructor(options: HtmlReporterOptions);
@@ -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,EAMV,KAAK,EACL,QAAQ,IAAI,cAAc,EAC1B,SAAS,EACT,UAAU,IAAI,gBAAgB,EAE/B,MAAM,2BAA2B,CAAC;AAInC,OAAO,EAML,UAAU,EAMX,MAAM,2BAA2B,CAAC;AAiBnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAsC/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,CAAC,IAAI,EAAE,cAAc;IAIhC,OAAO,IAAI,IAAI;IAIf,SAAS,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,gBAAgB;YA0D1C,qBAAqB;IAuDnC,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;AAsiBD,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;AAInC,OAAO,EAML,UAAU,EAMX,MAAM,2BAA2B,CAAC;AAkBnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAsC/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;AA+BF,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;IAKlC,OAAO,CAAC,mBAAmB,CAAqB;IAEhD,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,CAAC,IAAI,EAAE,cAAc;IAIhC,OAAO,IAAI,IAAI;IAIf,SAAS,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,gBAAgB;YA4D1C,qBAAqB;IA6CnC,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;IAkIxB,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;AAsiBD,eAAe,YAAY,CAAC"}
@@ -34,6 +34,7 @@ const zipBundle_1 = require("playwright-core/lib/zipBundle");
34
34
  const stream_1 = require("stream");
35
35
  const logger_1 = require("../logger");
36
36
  const base_1 = require("./base");
37
+ const queue_1 = require("./queue");
37
38
  const util_1 = require("./util");
38
39
  const htmlReportOptions = ["always", "never", "on-failure"];
39
40
  const isHtmlReportOption = (type) => {
@@ -62,6 +63,7 @@ function listFilesRecursively(dir) {
62
63
  }
63
64
  return files;
64
65
  }
66
+ const R2_BUCKET_NAME = "test-report";
65
67
  class HtmlReporter {
66
68
  config;
67
69
  suite;
@@ -71,43 +73,10 @@ class HtmlReporter {
71
73
  _open;
72
74
  _port;
73
75
  _host;
74
- uploadExecutionQueue = [];
75
- uploadWaitingQueue = [];
76
- uploadMaxQueueSize = process.env.UPLOAD_MAX_QUEUE_SIZE
77
- ? parseInt(process.env.UPLOAD_MAX_QUEUE_SIZE)
78
- : 2;
76
+ // Appwright persistent device tests generate attachments after onTestEnd
77
+ // We use the summary.json to re-process all attachments and this set ensures
78
+ // we don't upload the same attachment multiple times
79
79
  haveSeenAttachments = new Set();
80
- processQueue() {
81
- try {
82
- while (this.uploadExecutionQueue.length <= this.uploadMaxQueueSize &&
83
- this.uploadWaitingQueue.length > 0) {
84
- const task = this.uploadWaitingQueue.shift();
85
- if (task) {
86
- const promise = task()
87
- .catch((e) => {
88
- logger_1.logger.error("Error in processing task", e);
89
- })
90
- .finally(() => {
91
- // console.log("Finished upload execution from waiting queue"); // we already log in the upload function on successful upload
92
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
93
- this.uploadExecutionQueue = this.uploadExecutionQueue.filter((p) => p !== promise);
94
- this.processQueue();
95
- });
96
- this.uploadExecutionQueue.push(promise);
97
- }
98
- }
99
- }
100
- catch (e) {
101
- logger_1.logger.error("Error while processing queue", e);
102
- }
103
- }
104
- async waitForAllTasksToFinish() {
105
- return Promise.allSettled(this.uploadExecutionQueue).then(async () => {
106
- if (this.uploadExecutionQueue.length > 0) {
107
- await this.waitForAllTasksToFinish();
108
- }
109
- });
110
- }
111
80
  _buildResult;
112
81
  _topLevelErrors = [];
113
82
  constructor(options) {
@@ -127,62 +96,68 @@ class HtmlReporter {
127
96
  return "v2";
128
97
  }
129
98
  onTestEnd(test, result) {
99
+ if (!process.env.TEST_RUN_GITHUB_ACTION_ID) {
100
+ return;
101
+ }
130
102
  try {
131
103
  const attachmentPromises = result.attachments.map((attachment) => {
132
104
  return this.processTestAttachment(attachment);
133
105
  });
134
- Promise.all(attachmentPromises)
135
- .then((uploadedAttachments) => {
136
- if (!uploadedAttachments || !process.env.TEST_RUN_GITHUB_ACTION_ID) {
137
- return;
138
- }
139
- logger_1.logger.info(`All attachments processed, test data sent for test: ${test.title}`);
140
- const { suites, projectName } = (0, util_1.suitesAndProjectForTest)(test);
141
- let params = {
142
- test,
143
- result,
144
- assetsURL: {
145
- trace: "",
146
- videos: [],
147
- },
148
- suites,
149
- projectName,
150
- runId: process.env.TEST_RUN_GITHUB_ACTION_ID || "",
151
- };
152
- uploadedAttachments.forEach((attachment) => {
153
- if (attachment) {
154
- Object.entries(attachment).forEach(([key, value]) => {
155
- if (key.includes("video")) {
156
- params.assetsURL.videos.push({
157
- name: `test-${test.id}-slug-${(0, crypto_1.randomUUID)()}`,
158
- url: value,
159
- });
160
- }
161
- if (key.includes("trace")) {
162
- params.assetsURL.trace = value;
163
- }
164
- });
165
- }
106
+ const testCaseRunEventTask = async () => {
107
+ return Promise.all(attachmentPromises)
108
+ .then((uploadedAttachments) => {
109
+ logger_1.logger.info(`Attachments for test ${test.title} are uploaded:`, uploadedAttachments);
110
+ const { suites, projectName } = (0, util_1.suitesAndProjectForTest)(test);
111
+ let params = {
112
+ test,
113
+ result,
114
+ assetsURL: {
115
+ trace: "",
116
+ videos: [],
117
+ },
118
+ suites,
119
+ projectName,
120
+ runId: process.env.TEST_RUN_GITHUB_ACTION_ID || "",
121
+ };
122
+ uploadedAttachments.forEach((attachment) => {
123
+ if (attachment) {
124
+ Object.entries(attachment).forEach(([key, value]) => {
125
+ if (key.includes("video")) {
126
+ params.assetsURL.videos.push({
127
+ name: `test-${test.id}-slug-${(0, crypto_1.randomUUID)()}`,
128
+ url: value,
129
+ });
130
+ }
131
+ if (key.includes("trace")) {
132
+ params.assetsURL.trace = value;
133
+ }
134
+ });
135
+ }
136
+ });
137
+ return (0, util_1.sendTestCaseUpdateToDashboard)(params);
138
+ })
139
+ .catch((error) => {
140
+ logger_1.logger.error(`Error sending test case event for: ${test.title}:`, error);
166
141
  });
167
- return (0, util_1.sendTestCaseUpdateToDashboard)(params);
168
- })
169
- .catch((error) => {
170
- logger_1.logger.error(`Error processing attachments for test: ${test.title}:`, error);
171
- });
142
+ };
143
+ void (0, queue_1.sendTaskToQueue)(testCaseRunEventTask);
172
144
  }
173
145
  catch (e) {
174
- logger_1.logger.error(`Error while processing attachments for test ${test.title}:`, e);
146
+ logger_1.logger.error(`Error in onTestEnd for ${test.title}:`, e);
175
147
  }
176
148
  }
177
149
  async processTestAttachment(attachment) {
178
- if (!attachment.path)
150
+ if (!attachment.path) {
179
151
  return;
180
- if (this.haveSeenAttachments.has(attachment.path))
152
+ }
153
+ if (this.haveSeenAttachments.has(attachment.path)) {
181
154
  return;
155
+ }
182
156
  this.haveSeenAttachments.add(attachment.path);
183
157
  const folder = path_1.default.relative(this._outputFolder + "/data", attachment.path);
184
158
  const folderName = folder.split("/")[0];
185
- // 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
159
+ // on test gen run, we don't have PROJECT_NAME or TEST_RUN_GITHUB_ACTION_ID so we
160
+ // skip uploading since we anyways handle uploads for that
186
161
  if (!process.env.PROJECT_NAME || !process.env.TEST_RUN_GITHUB_ACTION_ID) {
187
162
  return;
188
163
  }
@@ -196,33 +171,19 @@ class HtmlReporter {
196
171
  process.env.TEST_RUN_GITHUB_ACTION_ID +
197
172
  "/data/" +
198
173
  folderName,
199
- uploadBucket: "test-report",
200
- });
174
+ uploadBucket: R2_BUCKET_NAME,
175
+ })
176
+ .then((fileMap) => {
177
+ logger_1.logger.debug("Finished uploading test attachment", fileMap);
178
+ return fileMap;
179
+ })
180
+ .catch((e) => logger_1.logger.error("Error uploading test attachment", e));
201
181
  return uploadedFiles;
202
182
  };
203
- if (this.uploadExecutionQueue.length <= this.uploadMaxQueueSize) {
204
- const promise = uploadTask()
205
- .catch((e) => {
206
- logger_1.logger.error("Upload failed for", attachment.path, e);
207
- // this.retryTask(uploadTask); // Retry logic
208
- })
209
- .finally(() => {
210
- // this is a list of promises which we dont want to await right now
211
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
212
- this.uploadExecutionQueue = this.uploadExecutionQueue.filter((p) => p !== promise);
213
- this.processQueue(); // Keep processing queue
214
- });
215
- this.uploadExecutionQueue.push(promise);
216
- return promise;
217
- }
218
- else {
219
- logger_1.logger.debug("Queuing upload task ", attachment.path);
220
- this.uploadWaitingQueue.push(uploadTask);
221
- }
183
+ return (0, queue_1.sendTaskToQueue)(uploadTask);
222
184
  }
223
185
  catch (e) {
224
186
  logger_1.logger.error("Error while uploading attachment", e);
225
- // tests shouldn't stop no matter whatever error we get
226
187
  }
227
188
  }
228
189
  onConfigure(config) {
@@ -269,11 +230,10 @@ class HtmlReporter {
269
230
  // await removeFolders([this._outputFolder]);
270
231
  const builder = new HtmlBuilder(this.config, this._outputFolder, this._attachmentsBaseURL);
271
232
  this._buildResult = await builder.build(this.config.metadata, projectSuites, result, this._topLevelErrors);
272
- const startTime = new Date().getTime();
273
233
  if (!process.env.PROJECT_NAME || !process.env.TEST_RUN_GITHUB_ACTION_ID) {
274
- // Skipping uploads since PROJECT_NAME or TEST_RUN_GITHUB_ACTION_ID is not set,
275
234
  return;
276
235
  }
236
+ const startTime = new Date().getTime();
277
237
  logger_1.logger.info("Starting final report upload at: ", new Intl.DateTimeFormat("en-US", {
278
238
  hour: "2-digit",
279
239
  minute: "2-digit",
@@ -302,7 +262,7 @@ class HtmlReporter {
302
262
  "/" +
303
263
  process.env.TEST_RUN_GITHUB_ACTION_ID +
304
264
  "/trace",
305
- uploadBucket: "test-report",
265
+ uploadBucket: R2_BUCKET_NAME,
306
266
  })
307
267
  .then((fileMap) => {
308
268
  logger_1.logger.debug("Finished uploading playwright trace", fileMap);
@@ -318,7 +278,7 @@ class HtmlReporter {
318
278
  destinationDir: process.env.PROJECT_NAME +
319
279
  "/" +
320
280
  process.env.TEST_RUN_GITHUB_ACTION_ID,
321
- uploadBucket: "test-report",
281
+ uploadBucket: R2_BUCKET_NAME,
322
282
  })
323
283
  .then((fileMap) => {
324
284
  logger_1.logger.debug("Finished uploading html report", fileMap);
@@ -334,26 +294,20 @@ class HtmlReporter {
334
294
  destinationDir: process.env.PROJECT_NAME +
335
295
  "/" +
336
296
  process.env.TEST_RUN_GITHUB_ACTION_ID,
337
- uploadBucket: "test-report",
297
+ uploadBucket: R2_BUCKET_NAME,
338
298
  })
339
299
  .then((fileMap) => {
340
300
  logger_1.logger.debug("Finished uploading json report", fileMap);
341
301
  })
342
302
  .catch((e) => logger_1.logger.error("Error uploading json report", e));
343
303
  };
344
- logger_1.logger.debug("Uploading waiting queue", this.uploadWaitingQueue.length);
345
- logger_1.logger.debug("Uploading execution queue", this.uploadExecutionQueue.length);
346
- const processQueue = !this.uploadExecutionQueue.length;
347
304
  if (traceExists) {
348
- this.uploadWaitingQueue.push(uploadTraceTask);
349
- }
350
- this.uploadWaitingQueue.push(uploadIndexTask);
351
- this.uploadWaitingQueue.push(uploadSummaryTask);
352
- if (processQueue) {
353
- this.processQueue();
305
+ void (0, queue_1.sendTaskToQueue)(uploadTraceTask);
354
306
  }
307
+ void (0, queue_1.sendTaskToQueue)(uploadIndexTask);
308
+ void (0, queue_1.sendTaskToQueue)(uploadSummaryTask);
355
309
  logger_1.logger.info("Waiting for all uploads to finish");
356
- await this.waitForAllTasksToFinish();
310
+ await (0, queue_1.waitForTaskQueueToFinish)();
357
311
  logger_1.logger.info("All uploads finished");
358
312
  const endTime = new Date().getTime();
359
313
  logger_1.logger.info("Finished final report upload at: ", new Intl.DateTimeFormat("en-US", {
@@ -361,7 +315,6 @@ class HtmlReporter {
361
315
  minute: "2-digit",
362
316
  second: "2-digit",
363
317
  }).format(endTime));
364
- // time difference
365
318
  const timeDiff = endTime - startTime;
366
319
  logger_1.logger.info("Time taken to upload after tests ended: ", timeDiff, "ms");
367
320
  }
@@ -0,0 +1,8 @@
1
+ import { FileMap } from "@empiricalrun/r2-uploader";
2
+ type AsyncTask = () => Promise<FileMap | void>;
3
+ type AsyncTaskReturnType = FileMap | void;
4
+ type AsyncTaskResult = Promise<AsyncTaskReturnType>;
5
+ export declare function sendTaskToQueue(task: AsyncTask): AsyncTaskResult;
6
+ export declare function waitForTaskQueueToFinish(): Promise<void>;
7
+ export {};
8
+ //# sourceMappingURL=queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/reporter/queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAIpD,KAAK,SAAS,GAAG,MAAM,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;AAC/C,KAAK,mBAAmB,GAAG,OAAO,GAAG,IAAI,CAAC;AAC1C,KAAK,eAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAoGpD,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,eAAe,CAQhE;AAED,wBAAgB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOxD"}
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.waitForTaskQueueToFinish = exports.sendTaskToQueue = void 0;
4
+ const logger_1 = require("../logger");
5
+ class TaskQueue {
6
+ waitingQueue = [];
7
+ executingTasks = [];
8
+ maxConcurrent;
9
+ constructor() {
10
+ this.maxConcurrent = process.env.UPLOAD_MAX_QUEUE_SIZE
11
+ ? parseInt(process.env.UPLOAD_MAX_QUEUE_SIZE)
12
+ : 2;
13
+ }
14
+ async processNextTask() {
15
+ logger_1.logger.debug("[queue] processing next task in queue, with queue lengths:", taskQueue.queueLength, taskQueue.executingTasksCount);
16
+ if (this.waitingQueue.length === 0 ||
17
+ this.executingTasks.length >= this.maxConcurrent) {
18
+ return;
19
+ }
20
+ const queuedTask = this.waitingQueue.shift();
21
+ if (!queuedTask)
22
+ return;
23
+ const { task, resolve, reject } = queuedTask;
24
+ // Create the promise first
25
+ let executingPromise;
26
+ const executeTask = async () => {
27
+ try {
28
+ const result = await task();
29
+ resolve(result);
30
+ }
31
+ catch (error) {
32
+ logger_1.logger.error("Error in processing task", error);
33
+ reject(error);
34
+ }
35
+ finally {
36
+ // Remove this task from executing tasks
37
+ const index = this.executingTasks.indexOf(executingPromise);
38
+ if (index > -1) {
39
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
40
+ this.executingTasks.splice(index, 1);
41
+ }
42
+ // Try to process next task
43
+ await this.processNextTask();
44
+ }
45
+ };
46
+ // Assign the promise
47
+ executingPromise = executeTask();
48
+ this.executingTasks.push(executingPromise);
49
+ }
50
+ enqueue(task) {
51
+ return new Promise((resolve, reject) => {
52
+ this.waitingQueue.push({ task, resolve, reject });
53
+ this.processNextTask().catch((error) => {
54
+ logger_1.logger.error("Error processing queue", error);
55
+ });
56
+ });
57
+ }
58
+ async waitForCompletion() {
59
+ if (this.waitingQueue.length === 0 && this.executingTasks.length === 0) {
60
+ return;
61
+ }
62
+ // First wait for all currently executing tasks
63
+ if (this.executingTasks.length > 0) {
64
+ await Promise.all(this.executingTasks);
65
+ }
66
+ // If there are still tasks in the waiting queue, process them
67
+ if (this.waitingQueue.length > 0) {
68
+ await this.processNextTask();
69
+ }
70
+ await this.waitForCompletion();
71
+ }
72
+ get queueLength() {
73
+ return this.waitingQueue.length;
74
+ }
75
+ get executingTasksCount() {
76
+ return this.executingTasks.length;
77
+ }
78
+ }
79
+ const taskQueue = new TaskQueue();
80
+ function sendTaskToQueue(task) {
81
+ logger_1.logger.debug("[queue] sending task to queue, with queue lengths:", taskQueue.queueLength, taskQueue.executingTasksCount, task);
82
+ return taskQueue.enqueue(task);
83
+ }
84
+ exports.sendTaskToQueue = sendTaskToQueue;
85
+ function waitForTaskQueueToFinish() {
86
+ logger_1.logger.debug("[queue] waiting for queue to finish, with queue lengths:", taskQueue.queueLength, taskQueue.executingTasksCount);
87
+ return taskQueue.waitForCompletion();
88
+ }
89
+ exports.waitForTaskQueueToFinish = waitForTaskQueueToFinish;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/playwright-utils",
3
- "version": "0.18.15",
3
+ "version": "0.18.18",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -43,9 +43,9 @@
43
43
  "playwright-extra": "^4.3.6",
44
44
  "puppeteer-extra-plugin-recaptcha": "^3.6.8",
45
45
  "rimraf": "^6.0.1",
46
- "@empiricalrun/test-gen": "^0.38.41",
47
- "@empiricalrun/llm": "^0.9.28",
48
- "@empiricalrun/r2-uploader": "^0.3.7"
46
+ "@empiricalrun/r2-uploader": "^0.3.7",
47
+ "@empiricalrun/test-gen": "^0.38.43",
48
+ "@empiricalrun/llm": "^0.9.28"
49
49
  },
50
50
  "scripts": {
51
51
  "dev": "tsc --build --watch",