@bigbinary/neeto-playwright-reporter 1.2.1 → 1.3.1

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/index.d.ts CHANGED
@@ -6,10 +6,14 @@ interface ReporterOptionParams {
6
6
  ciBuildId: string;
7
7
  }
8
8
  declare class MyReporter implements Reporter {
9
- attempts: Record<string, string>;
9
+ attempts: Record<string, Record<string, string>>;
10
10
  ciBuildId: string;
11
11
  config: FullConfig | undefined;
12
12
  currentShard: number | undefined;
13
+ retryAttemptStartedAt: Date;
14
+ testResultCalls: Promise<unknown>[];
15
+ totalTestCount: number;
16
+ reportedTestCount: number;
13
17
  constructor(options: ReporterOptionParams);
14
18
  onBegin: (config: FullConfig, rootSuite: Suite) => Promise<void>;
15
19
  onTestBegin: ({ id, title }: TestCase, { retry }: TestResult) => Promise<void>;
package/index.js CHANGED
@@ -11,6 +11,7 @@ import require$$0$2 from 'os';
11
11
  import zlib from 'zlib';
12
12
  import EventEmitter from 'events';
13
13
  import childProcess from 'child_process';
14
+ import crypto from 'crypto';
14
15
 
15
16
  function bind(fn, thisArg) {
16
17
  return function wrap() {
@@ -18439,10 +18440,15 @@ const HEADERS_KEYS = {
18439
18440
  };
18440
18441
  const API_BASE_URL = "/api/v1";
18441
18442
 
18442
- const create$2 = (ciBuildId, history_id, payload) => axios.post(`${API_BASE_URL}/reporter/runs/${ciBuildId}/test_entities/${history_id}/attempts`, payload, { headers: { "Content-Type": "multipart/form-data" } });
18443
- const update$1 = (ciBuildId, history_id, id, payload) => axios.put(`${API_BASE_URL}/reporter/runs/${ciBuildId}/test_entities/${history_id}/attempts/${id}`, payload, { headers: { "Content-Type": "multipart/form-data" } });
18443
+ const create$2 = (ciBuildId, history_id, payload) => axios.post(`${API_BASE_URL}/reporter/runs/${ciBuildId}/test_entities/${history_id}/attempts`, payload);
18444
+ const update$1 = (ciBuildId, history_id, id, payload) => axios.put(`${API_BASE_URL}/reporter/runs/${ciBuildId}/test_entities/${history_id}/attempts/${id}`, payload);
18444
18445
  const attemptsApi = { create: create$2, update: update$1 };
18445
18446
 
18447
+ const getDirectUploadURL = (payload) => axios.post(`${API_BASE_URL}/reporter/direct_uploads`, {
18448
+ blob: payload,
18449
+ });
18450
+ const uploadToS3 = (data, { url, headers }) => axios.put(url, data, { headers });
18451
+
18446
18452
  const ERRORS = {
18447
18453
  onBegin: {
18448
18454
  failedToGetCommitSha: "Failed to get current commit SHA.",
@@ -18502,7 +18508,13 @@ const executeCommandLine = ({ command, messageOnError, shouldThrowError = false,
18502
18508
  const createShardObject = ({ currentShard = 0, status = "running", duration = null, }) => ({
18503
18509
  [currentShard]: { status, duration },
18504
18510
  });
18505
- const convertBufferToBlob = (buffer, contentType) => new Blob([buffer], { type: contentType });
18511
+ const waitUntilTimeout = (timeout) => new Promise(resolve => setTimeout(resolve, timeout));
18512
+
18513
+ const getFileData = (file, contentType, filename) => {
18514
+ const byte_size = file.byteLength;
18515
+ const checksum = crypto.createHash("md5").update(file).digest("base64");
18516
+ return { file, filename, checksum, byte_size, content_type: contentType };
18517
+ };
18506
18518
 
18507
18519
  const create$1 = (payload) => axios.post(`${API_BASE_URL}/reporter/runs`, {
18508
18520
  run: payload,
@@ -18540,6 +18552,7 @@ const sendHeartBeatSignal = async (ciBuildId) => {
18540
18552
  await runsApi.heartbeat(ciBuildId);
18541
18553
  }
18542
18554
  catch (error) {
18555
+ console.log(error.message);
18543
18556
  consoleLogFormatted.error(ERRORS.heartbeat.stopped);
18544
18557
  process.exit(1);
18545
18558
  }
@@ -18570,6 +18583,7 @@ class MyReporter {
18570
18583
  this.onBegin = async (config, rootSuite) => {
18571
18584
  const shard = config.shard;
18572
18585
  let attempts;
18586
+ this.totalTestCount = rootSuite.allTests().length;
18573
18587
  try {
18574
18588
  const runDetails = {
18575
18589
  commit_id: getCurrentCommitSha(),
@@ -18601,13 +18615,31 @@ class MyReporter {
18601
18615
  this.currentShard = shard === null || shard === void 0 ? void 0 : shard.current;
18602
18616
  };
18603
18617
  this.onTestBegin = async ({ id, title }, { retry }) => {
18618
+ var _a, _b;
18604
18619
  consoleLogFormatted.invertBackground(MESSAGES.onTestBegin.startingTest(title));
18605
18620
  try {
18606
- const formData = new FormData();
18607
- formData.append("attempt[status]", "running");
18608
- formData.append("attempt[started_at]", new Date().toString());
18609
- retry === 0 &&
18610
- (await attemptsApi.update(this.ciBuildId, id, this.attempts[id], formData));
18621
+ this.retryAttemptStartedAt = new Date();
18622
+ while (!((_b = (_a = this.attempts) === null || _a === void 0 ? void 0 : _a[id]) === null || _b === void 0 ? void 0 : _b["0"]))
18623
+ await waitUntilTimeout(100); // Poll every 100 milliseconds
18624
+ if (retry === 0) {
18625
+ await attemptsApi.update(this.ciBuildId, id, this.attempts[id]["0"], {
18626
+ status: "running",
18627
+ started_at: new Date().toString(),
18628
+ });
18629
+ }
18630
+ else {
18631
+ const { data: { history_id, attempt_id }, } = await attemptsApi.create(this.ciBuildId, id, {
18632
+ status: "running",
18633
+ started_at: new Date().toString(),
18634
+ });
18635
+ this.attempts = {
18636
+ ...this.attempts,
18637
+ [history_id]: {
18638
+ ...this.attempts[history_id],
18639
+ [String(retry)]: attempt_id,
18640
+ },
18641
+ };
18642
+ }
18611
18643
  }
18612
18644
  catch (error) {
18613
18645
  consoleLogFormatted.error(error.message);
@@ -18615,6 +18647,7 @@ class MyReporter {
18615
18647
  }
18616
18648
  };
18617
18649
  this.onTestEnd = async (testCase, { status, duration, errors, retry, attachments }) => {
18650
+ const completedAt = new Date();
18618
18651
  const { id, title, expectedStatus } = testCase;
18619
18652
  try {
18620
18653
  const testResult = {
@@ -18623,33 +18656,44 @@ class MyReporter {
18623
18656
  status,
18624
18657
  duration,
18625
18658
  log: errors.map(error => { var _a; return (_a = error.message) !== null && _a !== void 0 ? _a : ""; }).join("\n"),
18659
+ screenshots: [],
18660
+ videos: [],
18661
+ traces: [],
18662
+ completed_at: completedAt.toString(),
18626
18663
  };
18627
18664
  consoleLogFormatted.underline(title);
18628
- const formData = new FormData();
18629
- attachments.map(({ name, path, body, contentType }) => {
18665
+ await Promise.all(attachments.map(async ({ name, path, body, contentType, }) => {
18630
18666
  consoleLogFormatted.dim(`${name}: ${path}`);
18631
18667
  if (["screenshot", "video", "trace"].includes(name)) {
18632
18668
  const buffer = path ? require$$6.readFileSync(path) : body;
18633
- formData.append(`attempt[${name}s][]`, convertBufferToBlob(buffer, contentType));
18669
+ const fileName = path
18670
+ ? path.split("/").slice(-1)[0]
18671
+ : `${name}.${contentType.split("/").slice(-1)[0]}`;
18672
+ const { file, ...metadata } = getFileData(buffer, contentType, fileName);
18673
+ const { data: { signed_id, direct_upload }, } = await getDirectUploadURL(metadata);
18674
+ const pluralizedAsset = `${name}s`;
18675
+ testResult[pluralizedAsset].push(signed_id);
18676
+ return uploadToS3(file, direct_upload);
18634
18677
  }
18635
- });
18636
- Object.entries(testResult).map(([resultKey, resultValue]) => {
18637
- formData.append(`attempt[${resultKey}]`, resultValue.toString());
18638
- });
18639
- retry !== 0 &&
18640
- formData.append("attempt[started_at]", new Date().toString());
18641
- retry === 0
18642
- ? await attemptsApi.update(this.ciBuildId, id, this.attempts[id], formData)
18643
- : await attemptsApi.create(this.ciBuildId, id, formData);
18678
+ }));
18679
+ while (!this.attempts[id][retry])
18680
+ await waitUntilTimeout(100);
18681
+ this.testResultCalls.push(attemptsApi.update(this.ciBuildId, id, this.attempts[id][retry], testResult));
18644
18682
  consoleLogFormatted.invertBackground(MESSAGES.onTestEnd.reportedTest(title));
18645
18683
  }
18646
18684
  catch (error) {
18647
18685
  consoleLogFormatted.error(error.message);
18648
18686
  consoleLogFormatted.error(ERRORS.onTestBegin.failedToReportTest(title, id));
18649
18687
  }
18688
+ finally {
18689
+ retry === 0 && this.reportedTestCount++;
18690
+ }
18650
18691
  };
18651
18692
  this.onEnd = async ({ status, duration }) => {
18652
18693
  try {
18694
+ await Promise.allSettled(this.testResultCalls);
18695
+ while (this.totalTestCount !== this.reportedTestCount)
18696
+ await waitUntilTimeout(100);
18653
18697
  await runsApi.update(this.ciBuildId, {
18654
18698
  shards: createShardObject({
18655
18699
  currentShard: this.currentShard,
@@ -18666,6 +18710,10 @@ class MyReporter {
18666
18710
  initializeAxios(options);
18667
18711
  this.attempts = {};
18668
18712
  this.ciBuildId = options.ciBuildId;
18713
+ this.retryAttemptStartedAt = new Date();
18714
+ this.testResultCalls = [];
18715
+ this.totalTestCount = 0;
18716
+ this.reportedTestCount = 0;
18669
18717
  }
18670
18718
  }
18671
18719