@bigbinary/neeto-playwright-reporter 1.2.0 → 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,14 +6,18 @@ 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>;
16
- onTestEnd: ({ id, title }: TestCase, { status, duration, errors, retry, attachments }: TestResult) => Promise<void>;
20
+ onTestEnd: (testCase: TestCase, { status, duration, errors, retry, attachments }: TestResult) => Promise<void>;
17
21
  onEnd: ({ status, duration }: FullResult) => Promise<void>;
18
22
  }
19
23
 
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,13 +18440,19 @@ 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.",
18455
+ failedToGetBranch: "Failed to get current branch.",
18449
18456
  failedToGetCommitMessage: "Failed to get current commit message.",
18450
18457
  failedToInitializeRun: "Failed to initialize run in reporter",
18451
18458
  },
@@ -18501,7 +18508,13 @@ const executeCommandLine = ({ command, messageOnError, shouldThrowError = false,
18501
18508
  const createShardObject = ({ currentShard = 0, status = "running", duration = null, }) => ({
18502
18509
  [currentShard]: { status, duration },
18503
18510
  });
18504
- 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
+ };
18505
18518
 
18506
18519
  const create$1 = (payload) => axios.post(`${API_BASE_URL}/reporter/runs`, {
18507
18520
  run: payload,
@@ -18521,6 +18534,10 @@ const getCurrentCommitMessage = () => executeCommandLine({
18521
18534
  command: "git show-branch --no-name HEAD",
18522
18535
  messageOnError: ERRORS.onBegin.failedToGetCommitMessage,
18523
18536
  });
18537
+ const getCurrentBranch = () => executeCommandLine({
18538
+ command: "git branch --show-current",
18539
+ messageOnError: ERRORS.onBegin.failedToGetBranch,
18540
+ });
18524
18541
  const getInitializerData = ({ rootDir }, rootSuite) => rootSuite.allTests().map(test => {
18525
18542
  var _a;
18526
18543
  const { title, parent, id: history_id, location: { file }, } = test;
@@ -18565,10 +18582,12 @@ class MyReporter {
18565
18582
  this.onBegin = async (config, rootSuite) => {
18566
18583
  const shard = config.shard;
18567
18584
  let attempts;
18585
+ this.totalTestCount = rootSuite.allTests().length;
18568
18586
  try {
18569
18587
  const runDetails = {
18570
18588
  commit_id: getCurrentCommitSha(),
18571
18589
  commit_name: getCurrentCommitMessage(),
18590
+ branch: getCurrentBranch(),
18572
18591
  ci_build_id: this.ciBuildId,
18573
18592
  configuration: config,
18574
18593
  shards: createShardObject({ currentShard: shard === null || shard === void 0 ? void 0 : shard.current }),
@@ -18597,47 +18616,82 @@ class MyReporter {
18597
18616
  this.onTestBegin = async ({ id, title }, { retry }) => {
18598
18617
  consoleLogFormatted.invertBackground(MESSAGES.onTestBegin.startingTest(title));
18599
18618
  try {
18600
- const formData = new FormData();
18601
- formData.append("attempt[status]", "running");
18602
- retry === 0 &&
18603
- (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
+ }
18604
18641
  }
18605
18642
  catch (error) {
18606
18643
  consoleLogFormatted.error(error.message);
18607
18644
  consoleLogFormatted.error(ERRORS.onTestBegin.failedToReportTest(title, id));
18608
18645
  }
18609
18646
  };
18610
- this.onTestEnd = async ({ id, title }, { status, duration, errors, retry, attachments }) => {
18647
+ this.onTestEnd = async (testCase, { status, duration, errors, retry, attachments }) => {
18648
+ const completedAt = new Date();
18649
+ const { id, title, expectedStatus } = testCase;
18611
18650
  try {
18612
18651
  const testResult = {
18652
+ outcome: testCase.outcome(),
18653
+ expected_status: expectedStatus,
18613
18654
  status,
18614
18655
  duration,
18615
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(),
18616
18661
  };
18617
18662
  consoleLogFormatted.underline(title);
18618
- const formData = new FormData();
18619
- attachments.map(({ name, path, body, contentType }) => {
18663
+ await Promise.all(attachments.map(async ({ name, path, body, contentType, }) => {
18620
18664
  consoleLogFormatted.dim(`${name}: ${path}`);
18621
18665
  if (["screenshot", "video", "trace"].includes(name)) {
18622
18666
  const buffer = path ? require$$6.readFileSync(path) : body;
18623
- 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);
18624
18675
  }
18625
- });
18626
- Object.entries(testResult).map(([resultKey, resultValue]) => {
18627
- formData.append(`attempt[${resultKey}]`, resultValue.toString());
18628
- });
18629
- retry === 0
18630
- ? await attemptsApi.update(this.ciBuildId, id, this.attempts[id], formData)
18631
- : 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));
18632
18680
  consoleLogFormatted.invertBackground(MESSAGES.onTestEnd.reportedTest(title));
18633
18681
  }
18634
18682
  catch (error) {
18635
18683
  consoleLogFormatted.error(error.message);
18636
18684
  consoleLogFormatted.error(ERRORS.onTestBegin.failedToReportTest(title, id));
18637
18685
  }
18686
+ finally {
18687
+ retry === 0 && this.reportedTestCount++;
18688
+ }
18638
18689
  };
18639
18690
  this.onEnd = async ({ status, duration }) => {
18640
18691
  try {
18692
+ await Promise.allSettled(this.testResultCalls);
18693
+ while (this.totalTestCount !== this.reportedTestCount)
18694
+ await waitUntilTimeout(100);
18641
18695
  await runsApi.update(this.ciBuildId, {
18642
18696
  shards: createShardObject({
18643
18697
  currentShard: this.currentShard,
@@ -18654,6 +18708,10 @@ class MyReporter {
18654
18708
  initializeAxios(options);
18655
18709
  this.attempts = {};
18656
18710
  this.ciBuildId = options.ciBuildId;
18711
+ this.retryAttemptStartedAt = new Date();
18712
+ this.testResultCalls = [];
18713
+ this.totalTestCount = 0;
18714
+ this.reportedTestCount = 0;
18657
18715
  }
18658
18716
  }
18659
18717