@bigbinary/neeto-playwright-reporter 1.2.1 → 1.3.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/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,
@@ -18570,6 +18582,7 @@ class MyReporter {
18570
18582
  this.onBegin = async (config, rootSuite) => {
18571
18583
  const shard = config.shard;
18572
18584
  let attempts;
18585
+ this.totalTestCount = rootSuite.allTests().length;
18573
18586
  try {
18574
18587
  const runDetails = {
18575
18588
  commit_id: getCurrentCommitSha(),
@@ -18603,11 +18616,28 @@ class MyReporter {
18603
18616
  this.onTestBegin = async ({ id, title }, { retry }) => {
18604
18617
  consoleLogFormatted.invertBackground(MESSAGES.onTestBegin.startingTest(title));
18605
18618
  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));
18619
+ this.retryAttemptStartedAt = new Date();
18620
+ while (!this.attempts[id]["0"])
18621
+ await waitUntilTimeout(100); // Poll every 100 milliseconds
18622
+ if (retry === 0) {
18623
+ await attemptsApi.update(this.ciBuildId, id, this.attempts[id]["0"], {
18624
+ status: "running",
18625
+ started_at: new Date().toString(),
18626
+ });
18627
+ }
18628
+ else {
18629
+ const { data: { history_id, attempt_id }, } = await attemptsApi.create(this.ciBuildId, id, {
18630
+ status: "running",
18631
+ started_at: new Date().toString(),
18632
+ });
18633
+ this.attempts = {
18634
+ ...this.attempts,
18635
+ [history_id]: {
18636
+ ...this.attempts[history_id],
18637
+ [String(retry)]: attempt_id,
18638
+ },
18639
+ };
18640
+ }
18611
18641
  }
18612
18642
  catch (error) {
18613
18643
  consoleLogFormatted.error(error.message);
@@ -18615,6 +18645,7 @@ class MyReporter {
18615
18645
  }
18616
18646
  };
18617
18647
  this.onTestEnd = async (testCase, { status, duration, errors, retry, attachments }) => {
18648
+ const completedAt = new Date();
18618
18649
  const { id, title, expectedStatus } = testCase;
18619
18650
  try {
18620
18651
  const testResult = {
@@ -18623,33 +18654,44 @@ class MyReporter {
18623
18654
  status,
18624
18655
  duration,
18625
18656
  log: errors.map(error => { var _a; return (_a = error.message) !== null && _a !== void 0 ? _a : ""; }).join("\n"),
18657
+ screenshots: [],
18658
+ videos: [],
18659
+ traces: [],
18660
+ completed_at: completedAt.toString(),
18626
18661
  };
18627
18662
  consoleLogFormatted.underline(title);
18628
- const formData = new FormData();
18629
- attachments.map(({ name, path, body, contentType }) => {
18663
+ await Promise.all(attachments.map(async ({ name, path, body, contentType, }) => {
18630
18664
  consoleLogFormatted.dim(`${name}: ${path}`);
18631
18665
  if (["screenshot", "video", "trace"].includes(name)) {
18632
18666
  const buffer = path ? require$$6.readFileSync(path) : body;
18633
- formData.append(`attempt[${name}s][]`, convertBufferToBlob(buffer, contentType));
18667
+ const fileName = path
18668
+ ? path.split("/").slice(-1)[0]
18669
+ : `${name}.${contentType.split("/").slice(-1)[0]}`;
18670
+ const { file, ...metadata } = getFileData(buffer, contentType, fileName);
18671
+ const { data: { signed_id, direct_upload }, } = await getDirectUploadURL(metadata);
18672
+ const pluralizedAsset = `${name}s`;
18673
+ testResult[pluralizedAsset].push(signed_id);
18674
+ return uploadToS3(file, direct_upload);
18634
18675
  }
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);
18676
+ }));
18677
+ while (!this.attempts[id][retry])
18678
+ await waitUntilTimeout(100);
18679
+ this.testResultCalls.push(attemptsApi.update(this.ciBuildId, id, this.attempts[id][retry], testResult));
18644
18680
  consoleLogFormatted.invertBackground(MESSAGES.onTestEnd.reportedTest(title));
18645
18681
  }
18646
18682
  catch (error) {
18647
18683
  consoleLogFormatted.error(error.message);
18648
18684
  consoleLogFormatted.error(ERRORS.onTestBegin.failedToReportTest(title, id));
18649
18685
  }
18686
+ finally {
18687
+ retry === 0 && this.reportedTestCount++;
18688
+ }
18650
18689
  };
18651
18690
  this.onEnd = async ({ status, duration }) => {
18652
18691
  try {
18692
+ await Promise.allSettled(this.testResultCalls);
18693
+ while (this.totalTestCount !== this.reportedTestCount)
18694
+ await waitUntilTimeout(100);
18653
18695
  await runsApi.update(this.ciBuildId, {
18654
18696
  shards: createShardObject({
18655
18697
  currentShard: this.currentShard,
@@ -18666,6 +18708,10 @@ class MyReporter {
18666
18708
  initializeAxios(options);
18667
18709
  this.attempts = {};
18668
18710
  this.ciBuildId = options.ciBuildId;
18711
+ this.retryAttemptStartedAt = new Date();
18712
+ this.testResultCalls = [];
18713
+ this.totalTestCount = 0;
18714
+ this.reportedTestCount = 0;
18669
18715
  }
18670
18716
  }
18671
18717