@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.cjs.js CHANGED
@@ -13,6 +13,7 @@ var require$$0$2 = require('os');
13
13
  var zlib = require('zlib');
14
14
  var EventEmitter = require('events');
15
15
  var childProcess = require('child_process');
16
+ var crypto = require('crypto');
16
17
 
17
18
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
18
19
 
@@ -29,6 +30,7 @@ var require$$0__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$0$2);
29
30
  var zlib__default = /*#__PURE__*/_interopDefaultLegacy(zlib);
30
31
  var EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
31
32
  var childProcess__default = /*#__PURE__*/_interopDefaultLegacy(childProcess);
33
+ var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
32
34
 
33
35
  function bind(fn, thisArg) {
34
36
  return function wrap() {
@@ -18457,13 +18459,19 @@ const HEADERS_KEYS = {
18457
18459
  };
18458
18460
  const API_BASE_URL = "/api/v1";
18459
18461
 
18460
- 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" } });
18461
- 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" } });
18462
+ const create$2 = (ciBuildId, history_id, payload) => axios.post(`${API_BASE_URL}/reporter/runs/${ciBuildId}/test_entities/${history_id}/attempts`, payload);
18463
+ const update$1 = (ciBuildId, history_id, id, payload) => axios.put(`${API_BASE_URL}/reporter/runs/${ciBuildId}/test_entities/${history_id}/attempts/${id}`, payload);
18462
18464
  const attemptsApi = { create: create$2, update: update$1 };
18463
18465
 
18466
+ const getDirectUploadURL = (payload) => axios.post(`${API_BASE_URL}/reporter/direct_uploads`, {
18467
+ blob: payload,
18468
+ });
18469
+ const uploadToS3 = (data, { url, headers }) => axios.put(url, data, { headers });
18470
+
18464
18471
  const ERRORS = {
18465
18472
  onBegin: {
18466
18473
  failedToGetCommitSha: "Failed to get current commit SHA.",
18474
+ failedToGetBranch: "Failed to get current branch.",
18467
18475
  failedToGetCommitMessage: "Failed to get current commit message.",
18468
18476
  failedToInitializeRun: "Failed to initialize run in reporter",
18469
18477
  },
@@ -18519,7 +18527,13 @@ const executeCommandLine = ({ command, messageOnError, shouldThrowError = false,
18519
18527
  const createShardObject = ({ currentShard = 0, status = "running", duration = null, }) => ({
18520
18528
  [currentShard]: { status, duration },
18521
18529
  });
18522
- const convertBufferToBlob = (buffer, contentType) => new Blob([buffer], { type: contentType });
18530
+ const waitUntilTimeout = (timeout) => new Promise(resolve => setTimeout(resolve, timeout));
18531
+
18532
+ const getFileData = (file, contentType, filename) => {
18533
+ const byte_size = file.byteLength;
18534
+ const checksum = crypto__default["default"].createHash("md5").update(file).digest("base64");
18535
+ return { file, filename, checksum, byte_size, content_type: contentType };
18536
+ };
18523
18537
 
18524
18538
  const create$1 = (payload) => axios.post(`${API_BASE_URL}/reporter/runs`, {
18525
18539
  run: payload,
@@ -18539,6 +18553,10 @@ const getCurrentCommitMessage = () => executeCommandLine({
18539
18553
  command: "git show-branch --no-name HEAD",
18540
18554
  messageOnError: ERRORS.onBegin.failedToGetCommitMessage,
18541
18555
  });
18556
+ const getCurrentBranch = () => executeCommandLine({
18557
+ command: "git branch --show-current",
18558
+ messageOnError: ERRORS.onBegin.failedToGetBranch,
18559
+ });
18542
18560
  const getInitializerData = ({ rootDir }, rootSuite) => rootSuite.allTests().map(test => {
18543
18561
  var _a;
18544
18562
  const { title, parent, id: history_id, location: { file }, } = test;
@@ -18583,10 +18601,12 @@ class MyReporter {
18583
18601
  this.onBegin = async (config, rootSuite) => {
18584
18602
  const shard = config.shard;
18585
18603
  let attempts;
18604
+ this.totalTestCount = rootSuite.allTests().length;
18586
18605
  try {
18587
18606
  const runDetails = {
18588
18607
  commit_id: getCurrentCommitSha(),
18589
18608
  commit_name: getCurrentCommitMessage(),
18609
+ branch: getCurrentBranch(),
18590
18610
  ci_build_id: this.ciBuildId,
18591
18611
  configuration: config,
18592
18612
  shards: createShardObject({ currentShard: shard === null || shard === void 0 ? void 0 : shard.current }),
@@ -18615,47 +18635,82 @@ class MyReporter {
18615
18635
  this.onTestBegin = async ({ id, title }, { retry }) => {
18616
18636
  consoleLogFormatted.invertBackground(MESSAGES.onTestBegin.startingTest(title));
18617
18637
  try {
18618
- const formData = new FormData();
18619
- formData.append("attempt[status]", "running");
18620
- retry === 0 &&
18621
- (await attemptsApi.update(this.ciBuildId, id, this.attempts[id], formData));
18638
+ this.retryAttemptStartedAt = new Date();
18639
+ while (!this.attempts[id]["0"])
18640
+ await waitUntilTimeout(100); // Poll every 100 milliseconds
18641
+ if (retry === 0) {
18642
+ await attemptsApi.update(this.ciBuildId, id, this.attempts[id]["0"], {
18643
+ status: "running",
18644
+ started_at: new Date().toString(),
18645
+ });
18646
+ }
18647
+ else {
18648
+ const { data: { history_id, attempt_id }, } = await attemptsApi.create(this.ciBuildId, id, {
18649
+ status: "running",
18650
+ started_at: new Date().toString(),
18651
+ });
18652
+ this.attempts = {
18653
+ ...this.attempts,
18654
+ [history_id]: {
18655
+ ...this.attempts[history_id],
18656
+ [String(retry)]: attempt_id,
18657
+ },
18658
+ };
18659
+ }
18622
18660
  }
18623
18661
  catch (error) {
18624
18662
  consoleLogFormatted.error(error.message);
18625
18663
  consoleLogFormatted.error(ERRORS.onTestBegin.failedToReportTest(title, id));
18626
18664
  }
18627
18665
  };
18628
- this.onTestEnd = async ({ id, title }, { status, duration, errors, retry, attachments }) => {
18666
+ this.onTestEnd = async (testCase, { status, duration, errors, retry, attachments }) => {
18667
+ const completedAt = new Date();
18668
+ const { id, title, expectedStatus } = testCase;
18629
18669
  try {
18630
18670
  const testResult = {
18671
+ outcome: testCase.outcome(),
18672
+ expected_status: expectedStatus,
18631
18673
  status,
18632
18674
  duration,
18633
18675
  log: errors.map(error => { var _a; return (_a = error.message) !== null && _a !== void 0 ? _a : ""; }).join("\n"),
18676
+ screenshots: [],
18677
+ videos: [],
18678
+ traces: [],
18679
+ completed_at: completedAt.toString(),
18634
18680
  };
18635
18681
  consoleLogFormatted.underline(title);
18636
- const formData = new FormData();
18637
- attachments.map(({ name, path, body, contentType }) => {
18682
+ await Promise.all(attachments.map(async ({ name, path, body, contentType, }) => {
18638
18683
  consoleLogFormatted.dim(`${name}: ${path}`);
18639
18684
  if (["screenshot", "video", "trace"].includes(name)) {
18640
18685
  const buffer = path ? require$$6__default["default"].readFileSync(path) : body;
18641
- formData.append(`attempt[${name}s][]`, convertBufferToBlob(buffer, contentType));
18686
+ const fileName = path
18687
+ ? path.split("/").slice(-1)[0]
18688
+ : `${name}.${contentType.split("/").slice(-1)[0]}`;
18689
+ const { file, ...metadata } = getFileData(buffer, contentType, fileName);
18690
+ const { data: { signed_id, direct_upload }, } = await getDirectUploadURL(metadata);
18691
+ const pluralizedAsset = `${name}s`;
18692
+ testResult[pluralizedAsset].push(signed_id);
18693
+ return uploadToS3(file, direct_upload);
18642
18694
  }
18643
- });
18644
- Object.entries(testResult).map(([resultKey, resultValue]) => {
18645
- formData.append(`attempt[${resultKey}]`, resultValue.toString());
18646
- });
18647
- retry === 0
18648
- ? await attemptsApi.update(this.ciBuildId, id, this.attempts[id], formData)
18649
- : await attemptsApi.create(this.ciBuildId, id, formData);
18695
+ }));
18696
+ while (!this.attempts[id][retry])
18697
+ await waitUntilTimeout(100);
18698
+ this.testResultCalls.push(attemptsApi.update(this.ciBuildId, id, this.attempts[id][retry], testResult));
18650
18699
  consoleLogFormatted.invertBackground(MESSAGES.onTestEnd.reportedTest(title));
18651
18700
  }
18652
18701
  catch (error) {
18653
18702
  consoleLogFormatted.error(error.message);
18654
18703
  consoleLogFormatted.error(ERRORS.onTestBegin.failedToReportTest(title, id));
18655
18704
  }
18705
+ finally {
18706
+ retry === 0 && this.reportedTestCount++;
18707
+ }
18656
18708
  };
18657
18709
  this.onEnd = async ({ status, duration }) => {
18658
18710
  try {
18711
+ await Promise.allSettled(this.testResultCalls);
18712
+ while (this.totalTestCount !== this.reportedTestCount)
18713
+ await waitUntilTimeout(100);
18659
18714
  await runsApi.update(this.ciBuildId, {
18660
18715
  shards: createShardObject({
18661
18716
  currentShard: this.currentShard,
@@ -18672,6 +18727,10 @@ class MyReporter {
18672
18727
  initializeAxios(options);
18673
18728
  this.attempts = {};
18674
18729
  this.ciBuildId = options.ciBuildId;
18730
+ this.retryAttemptStartedAt = new Date();
18731
+ this.testResultCalls = [];
18732
+ this.totalTestCount = 0;
18733
+ this.reportedTestCount = 0;
18675
18734
  }
18676
18735
  }
18677
18736