@testomatio/reporter 1.6.0-beta-2-artifacts → 1.6.0-beta-3-artifacts

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.
@@ -301,9 +301,11 @@ function CodeceptReporter(config) {
301
301
  }
302
302
 
303
303
  async function uploadAttachments(client, attachments, messagePrefix, attachmentType) {
304
- if (!attachments?.length) return;
304
+ if (!attachments?.length) return;
305
305
 
306
- if (client.uploader.isEnabled) console.log(APP_PREFIX, `Attachments: ${messagePrefix} ${attachments.length} ${attachmentType} ...`);
306
+ if (client.uploader.isEnabled) {
307
+ console.log(APP_PREFIX, `Attachments: ${messagePrefix} ${attachments.length} ${attachmentType} ...`);
308
+ }
307
309
 
308
310
  const promises = attachments.map(async attachment => {
309
311
  const { rid, title, path, type } = attachment;
@@ -106,7 +106,7 @@ class PlaywrightReporter {
106
106
  await Promise.all(reportTestPromises);
107
107
 
108
108
  if (!this.uploads.length) return;
109
-
109
+
110
110
  if (this.client.uploader.isEnabled) console.log(APP_PREFIX, `🎞️ Uploading ${this.uploads.length} files...`);
111
111
 
112
112
  const promises = [];
@@ -135,7 +135,6 @@ class PlaywrightReporter {
135
135
  );
136
136
  }
137
137
  await Promise.all(promises);
138
-
139
138
 
140
139
  await this.client.updateRunStatus(checkStatus(result.status));
141
140
  }
package/lib/bin/cli.js CHANGED
@@ -9,13 +9,14 @@ const XmlReader = require('../xmlReader');
9
9
  const { APP_PREFIX, STATUS } = require('../constants');
10
10
  const { version } = require('../../package.json');
11
11
  const config = require('../config');
12
+ const { readLatestRunId } = require('../utils/utils');
12
13
 
13
14
  console.log(chalk.cyan.bold(` 🤩 Testomat.io Reporter v${version}`));
14
15
 
15
16
  program
16
17
  .version(version)
17
18
  .option('--env-file <envfile>', 'Load environment variables from env file')
18
- .hook('preAction', (thisCommand) => {
19
+ .hook('preAction', thisCommand => {
19
20
  const opts = thisCommand.opts();
20
21
  if (opts.envFile) {
21
22
  require('dotenv').config({ path: opts.envFile });
@@ -42,8 +43,10 @@ program
42
43
  .command('finish')
43
44
  .description('Finish Run by its ID')
44
45
  .action(async () => {
46
+ process.env.TESTOMATIO_RUN ||= readLatestRunId();
47
+
45
48
  if (!process.env.TESTOMATIO_RUN) {
46
- console.log('TESTOMATIO_RUN environment variable must be set.');
49
+ console.log('TESTOMATIO_RUN environment variable must be set or restored from a previous run.');
47
50
  return process.exit(1);
48
51
  }
49
52
 
@@ -140,10 +143,15 @@ program
140
143
 
141
144
  let timeoutTimer;
142
145
  if (opts.timelimit) {
143
- timeoutTimer = setTimeout(() => {
144
- console.log(`⚠️ Reached timeout of ${opts.timelimit}s. Exiting... (Exit code is 0 to not fail the pipeline)`);
145
- process.exit(0);
146
- }, parseInt(opts.timelimit, 10) * 1000);
146
+ timeoutTimer = setTimeout(
147
+ () => {
148
+ console.log(
149
+ `⚠️ Reached timeout of ${opts.timelimit}s. Exiting... (Exit code is 0 to not fail the pipeline)`,
150
+ );
151
+ process.exit(0);
152
+ },
153
+ parseInt(opts.timelimit, 10) * 1000,
154
+ );
147
155
  }
148
156
 
149
157
  try {
@@ -160,10 +168,16 @@ program
160
168
  .command('upload-artifacts')
161
169
  .description('Upload artifacts to Testomat.io')
162
170
  .option('--force', 'Re-upload artifacts even if they were uploaded before')
163
- .action(async (opts) => {
171
+ .action(async opts => {
164
172
  const apiKey = config.TESTOMATIO;
165
173
 
166
174
  process.env.TESTOMATIO_DISABLE_ARTIFACTS = '';
175
+ process.env.TESTOMATIO_RUN ||= readLatestRunId();
176
+
177
+ if (!process.env.TESTOMATIO_RUN) {
178
+ console.log('TESTOMATIO_RUN environment variable must be set or restored from a previous run.');
179
+ return process.exit(1);
180
+ }
167
181
 
168
182
  const client = new TestomatClient({
169
183
  apiKey,
@@ -203,9 +217,9 @@ program
203
217
  await client.addTestRun(undefined, { rid, files });
204
218
  }
205
219
 
206
- console.log(APP_PREFIX, client.uploader.totalUploaded, 'artifacts uploaded');
207
- if (client.uploader.failedUpload) {
208
- console.log(APP_PREFIX, client.uploader.failedUpload, 'artifacts failed to upload');
220
+ console.log(APP_PREFIX, client.uploader.totalUploadsCount, 'artifacts uploaded');
221
+ if (client.uploader.failedUploadsCount) {
222
+ console.log(APP_PREFIX, client.uploader.failedUploadsCount, 'artifacts failed to upload');
209
223
  }
210
224
  });
211
225
 
@@ -44,10 +44,15 @@ program
44
44
 
45
45
  let timeoutTimer;
46
46
  if (opts.timelimit) {
47
- timeoutTimer = setTimeout(() => {
48
- console.log(`⚠️ Reached timeout of ${opts.timelimit}s. Exiting... (Exit code is 0 to not fail the pipeline)`);
49
- process.exit(0);
50
- }, parseInt(opts.timelimit, 10) * 1000);
47
+ timeoutTimer = setTimeout(
48
+ () => {
49
+ console.log(
50
+ `⚠️ Reached timeout of ${opts.timelimit}s. Exiting... (Exit code is 0 to not fail the pipeline)`,
51
+ );
52
+ process.exit(0);
53
+ },
54
+ parseInt(opts.timelimit, 10) * 1000,
55
+ );
51
56
  }
52
57
 
53
58
  try {
@@ -13,7 +13,6 @@ program
13
13
  .option('--env-file <envfile>', 'Load environment variables from env file')
14
14
  .option('--force', 'Re-upload artifacts even if they were uploaded before')
15
15
  .action(async opts => {
16
-
17
16
  if (opts.envFile) {
18
17
  require('dotenv').config(opts.envFile); // eslint-disable-line
19
18
  } else {
@@ -29,7 +28,7 @@ program
29
28
  const client = new TestomatClient({
30
29
  apiKey,
31
30
  isBatchEnabled: false,
32
- });
31
+ });
33
32
 
34
33
  let testruns = client.uploader.readUploadedFiles(process.env.TESTOMATIO_RUN);
35
34
 
@@ -56,8 +55,6 @@ program
56
55
  return acc;
57
56
  }, {});
58
57
 
59
- let numArtifacts = 0;
60
-
61
58
  // we need to obtain S3 credentials
62
59
  await client.createRun();
63
60
 
@@ -66,16 +63,15 @@ program
66
63
 
67
64
  for (const rid in testrunsByRid) {
68
65
  const files = testrunsByRid[rid];
69
- numArtifacts += files.length;
70
66
  await client.addTestRun(undefined, {
71
67
  rid,
72
68
  files,
73
69
  });
74
70
  }
75
71
 
76
- console.log(APP_PREFIX, client.uploader.totalUploaded, 'artifacts uploaded');
77
- if (client.uploader.failedUpload) {
78
- console.log(APP_PREFIX, client.uploader.failedUpload, 'artifacts failed to upload');
72
+ console.log(APP_PREFIX, client.uploader.totalUploadsCount, 'artifacts uploaded');
73
+ if (client.uploader.failedUploadsCount) {
74
+ console.log(APP_PREFIX, client.uploader.failedUploadsCount, 'artifacts failed to upload');
79
75
  }
80
76
  });
81
77
 
package/lib/client.js CHANGED
@@ -10,6 +10,7 @@ const { APP_PREFIX, STATUS } = require('./constants');
10
10
  const pipesFactory = require('./pipe');
11
11
  const { glob } = require('glob');
12
12
  const path = require('path');
13
+ const { storeRunId } = require('./utils/utils');
13
14
 
14
15
  let listOfTestFilesToExcludeFromReport = null;
15
16
 
@@ -107,6 +108,8 @@ class Client {
107
108
  .then(() => {
108
109
  const runId = this.pipeStore?.runId;
109
110
  if (runId) this.runId = runId;
111
+ storeRunId(this.runId);
112
+
110
113
  this.uploader.checkEnabled();
111
114
  })
112
115
  .then(() => undefined); // fixes return type
@@ -182,12 +185,7 @@ class Client {
182
185
  f = f.path;
183
186
  }
184
187
 
185
- uploadedFiles.push(this.uploader.uploadFileByPath(f, [
186
- this.runId,
187
- rid,
188
- path.basename(f)
189
- ]));
190
-
188
+ uploadedFiles.push(this.uploader.uploadFileByPath(f, [this.runId, rid, path.basename(f)]));
191
189
  }
192
190
 
193
191
  for (const [idx, buffer] of filesBuffers.entries()) {
@@ -252,30 +250,33 @@ class Client {
252
250
  this.queue = this.queue
253
251
  .then(() => Promise.all(this.pipes.map(p => p.finishRun(runParams))))
254
252
  .then(() => {
255
- debug('TOTAL artifacts', this.uploader.totalUploaded);
256
- debug(`${this.uploader.skippedUpload} artifacts skipped`);
253
+ debug('TOTAL artifacts', this.uploader.totalUploadsCount);
254
+ debug(`${this.uploader.skippedUploadsCount} artifacts skipped`);
257
255
 
258
- if (this.uploader.totalUploaded && this.uploader.isEnabled) {
256
+ if (this.uploader.totalUploadsCount && this.uploader.isEnabled) {
259
257
  console.log(
260
258
  APP_PREFIX,
261
- `🗄️ ${this.uploader.totalUploaded} artifacts ${
259
+ `🗄️ ${this.uploader.totalUploadsCount} artifacts ${
262
260
  process.env.TESTOMATIO_PRIVATE_ARTIFACTS ? 'privately' : chalk.bold('publicly')
263
261
  } uploaded to S3 bucket`,
264
- );
262
+ );
265
263
  }
266
264
 
267
- if (this.uploader.failedUpload) {
268
- console.log(APP_PREFIX, `${this.uploader.failedUpload} artifacts failed to upload`);
265
+ if (this.uploader.failedUploadsCount) {
266
+ console.log(APP_PREFIX, `${this.uploader.failedUploadsCount} artifacts failed to upload`);
269
267
  }
270
268
 
271
- if (this.uploader.isEnabled && this.uploader.skippedUpload) {
272
- console.log(APP_PREFIX, `${chalk.bold(this.uploader.skippedUpload)} artifacts skipped to upload`);
269
+ if (this.uploader.isEnabled && this.uploader.skippedUploadsCount) {
270
+ console.log(APP_PREFIX, `${chalk.bold(this.uploader.skippedUploadsCount)} artifacts skipped to upload`);
273
271
  }
274
272
 
275
- if (this.uploader.skippedUpload || this.uploader.failedUpload) {
276
- console.log(APP_PREFIX, `Run "${chalk.magenta(`TESTOMATIO_RUN=${this.runId} npx upload-artifacts`)}" with valid S3 credentials to upload skipped & failed artifacts`);
273
+ if (this.uploader.skippedUploadsCount || this.uploader.failedUploadsCount) {
274
+ const command = `TESTOMATIO_RUN=${this.runId} npx upload-artifacts`;
275
+ console.log(
276
+ APP_PREFIX,
277
+ `Run "${chalk.magenta(command)}" with valid S3 credentials to upload skipped & failed artifacts`,
278
+ );
277
279
  }
278
-
279
280
  })
280
281
  .catch(err => console.log(APP_PREFIX, err));
281
282
 
@@ -79,13 +79,13 @@ class GitLabPipe {
79
79
  let summary = `${this.hiddenCommentData}
80
80
 
81
81
  | [![Testomat.io Report](${testomatLogoURL})](https://testomat.io) | ${statusEmoji(
82
- runParams.status,
83
- )} ${runParams.status.toUpperCase()} ${statusEmoji(runParams.status)} |
82
+ runParams.status,
83
+ )} ${runParams.status.toUpperCase()} ${statusEmoji(runParams.status)} |
84
84
  | --- | --- |
85
85
  | Tests | ✔️ **${this.tests.length}** tests run |
86
86
  | Summary | ${statusEmoji('failed')} **${failedCount}** failed; ${statusEmoji(
87
- 'passed',
88
- )} **${passedCount}** passed; **${statusEmoji('skipped')}** ${skippedCount} skipped |
87
+ 'passed',
88
+ )} **${passedCount}** passed; **${statusEmoji('skipped')}** ${skippedCount} skipped |
89
89
  | Duration | 🕐 **${humanizeDuration(
90
90
  parseInt(
91
91
  this.tests.reduce((a, t) => a + (t.run_time || 0), 0),
@@ -214,7 +214,7 @@ class TestomatioPipe {
214
214
  this.store.runPublicUrl = this.runPublicUrl;
215
215
  this.store.runId = this.runId;
216
216
  console.log(APP_PREFIX, '📊 Report created. Report ID:', this.runId);
217
- process.env.runId = this.runId;
217
+ process.env.runId = this.runId;
218
218
  debug('Run created', this.runId);
219
219
  } catch (err) {
220
220
  console.error(
package/lib/uploader.js CHANGED
@@ -15,9 +15,9 @@ class S3Uploader {
15
15
  this.config = undefined;
16
16
 
17
17
  // counters
18
- this.skippedUpload = 0;
19
- this.failedUpload = 0;
20
- this.totalUploaded = 0;
18
+ this.skippedUploadsCount = 0;
19
+ this.failedUploadsCount = 0;
20
+ this.totalUploadsCount = 0;
21
21
 
22
22
  this.succesfulUploads = {};
23
23
 
@@ -31,7 +31,7 @@ class S3Uploader {
31
31
  'S3_FORCE_PATH_STYLE',
32
32
  'TESTOMATIO_DISABLE_ARTIFACTS',
33
33
  'TESTOMATIO_PRIVATE_ARTIFACTS',
34
- 'TESTOMATIO_ARTIFACTS_SIZE'
34
+ 'TESTOMATIO_ARTIFACT_MAX_SIZE_MB',
35
35
  ];
36
36
  }
37
37
 
@@ -84,7 +84,11 @@ class S3Uploader {
84
84
  const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
85
85
 
86
86
  if (!S3_BUCKET || !Body) {
87
- console.log(APP_PREFIX, chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`), this.getMaskedConfig());
87
+ console.log(
88
+ APP_PREFIX,
89
+ chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`),
90
+ this.getMaskedConfig(),
91
+ );
88
92
  return;
89
93
  }
90
94
 
@@ -104,17 +108,17 @@ class S3Uploader {
104
108
  });
105
109
 
106
110
  const link = await this.getS3LocationLink(upload);
107
- this.totalUploaded++;
111
+ this.totalUploadsCount++;
108
112
  this.succesfulUploads[Key] = link;
109
113
  return link;
110
114
  } catch (e) {
111
- this.failedUpload++;
115
+ this.failedUploadsCount++;
112
116
  debug('S3 uploading error:', e);
113
- console.log(APP_PREFIX, "Upload failed:", e.message, this.getMaskedConfig());
117
+ console.log(APP_PREFIX, 'Upload failed:', e.message, this.getMaskedConfig());
114
118
  }
115
119
  }
116
120
 
117
- readUploadedFiles(runId = null) {
121
+ readUploadedFiles(runId) {
118
122
  const tempFilePath = this.#getUploadFilePath(runId);
119
123
 
120
124
  debug('Reading file', tempFilePath);
@@ -125,10 +129,10 @@ class S3Uploader {
125
129
  }
126
130
 
127
131
  const stats = fs.statSync(tempFilePath);
128
- const diff = (+new Date()) - (+stats.mtime);
132
+ const diff = +new Date() - +stats.mtime;
129
133
  const diffHours = diff / 1000 / 60 / 60;
130
134
  if (diffHours > 3) {
131
- console.log(APP_PREFIX, 'Artifacts file is too old, can\'t process artifacts. Please re-run the tests.');
135
+ console.log(APP_PREFIX, "Artifacts file is too old, can't process artifacts. Please re-run the tests.");
132
136
  return [];
133
137
  }
134
138
 
@@ -137,22 +141,11 @@ class S3Uploader {
137
141
  return lines.map(line => JSON.parse(line));
138
142
  }
139
143
 
140
- #getUploadFilePath(runId = null, forceCreate = false) {
141
- if (!runId && !forceCreate) {
142
- return path.join(os.tmpdir(), 'testomatio.run.latest.jsonl');
143
- }
144
-
144
+ #getUploadFilePath(runId, forceCreate = false) {
145
145
  const tempFilePath = path.join(os.tmpdir(), `testomatio.run.${runId}.jsonl`);
146
146
  if (!fs.existsSync(tempFilePath) || forceCreate) {
147
147
  debug('Creating artifacts file:', tempFilePath);
148
148
  fs.writeFileSync(tempFilePath, '');
149
- // make symlink to 'testomatio.run.latest.jsonl' file
150
- const latestFilePath = path.join(os.tmpdir(), 'testomatio.run.latest.jsonl');
151
- if (fs.existsSync(latestFilePath)) {
152
- fs.unlinkSync(latestFilePath);
153
- }
154
- fs.symlinkSync(tempFilePath, latestFilePath);
155
-
156
149
  }
157
150
  return tempFilePath;
158
151
  }
@@ -160,18 +153,18 @@ class S3Uploader {
160
153
  storeUploadedFile(filePath, runId, rid, uploaded = false) {
161
154
  if (!this.storeEnabled) return;
162
155
 
163
- if (!filePath || !runId || !rid ) return;
156
+ if (!filePath || !runId || !rid) return;
164
157
 
165
158
  const tempFilePath = this.#getUploadFilePath(runId);
166
159
 
167
160
  const data = { rid, file: filePath, uploaded };
168
- const jsonLine = JSON.stringify(data) + '\n';
161
+ const jsonLine = `${JSON.stringify(data)}\n`;
169
162
 
170
163
  fs.appendFileSync(tempFilePath, jsonLine);
171
164
  }
172
165
 
173
166
  getskippedUpload() {
174
- return this.skippedUpload;
167
+ return this.skippedUploadsCount;
175
168
  }
176
169
 
177
170
  async uploadFileByPath(filePath, pathInS3) {
@@ -179,21 +172,18 @@ class S3Uploader {
179
172
 
180
173
  if (!this.isEnabled) {
181
174
  this.storeUploadedFile(filePath, runId, rid, false);
182
- this.skippedUpload++;
175
+ this.skippedUploadsCount++;
183
176
  return;
184
177
  }
185
178
 
186
- const {
187
- S3_BUCKET,
188
- TESTOMATIO_ARTIFACTS_SIZE,
189
- } = this.getConfig();
179
+ const { S3_BUCKET, TESTOMATIO_ARTIFACT_MAX_SIZE_MB } = this.getConfig();
190
180
 
191
181
  debug('Started upload', filePath, 'to', S3_BUCKET);
192
182
 
193
183
  const isFileExist = await this.checkFileExists(filePath, 20, 500);
194
184
 
195
185
  if (!isFileExist) {
196
- this.failedUpload++;
186
+ this.failedUploadsCount++;
197
187
  console.error(chalk.yellow(`Artifacts file ${filePath} does not exist. Skipping...`));
198
188
  return;
199
189
  }
@@ -201,8 +191,8 @@ class S3Uploader {
201
191
  const fileSize = fs.statSync(filePath).size;
202
192
  const fileSizeInMb = fileSize / (1024 * 1024);
203
193
 
204
- if (TESTOMATIO_ARTIFACTS_SIZE && fileSizeInMb > parseInt(TESTOMATIO_ARTIFACTS_SIZE)) {
205
- this.skippedUpload++;
194
+ if (TESTOMATIO_ARTIFACT_MAX_SIZE_MB && fileSizeInMb > parseInt(TESTOMATIO_ARTIFACT_MAX_SIZE_MB, 10)) {
195
+ this.skippedUploadsCount++;
206
196
  console.error(chalk.yellow(`Artifacts file ${filePath} exceeds the maximum allowed size. Skipping...`));
207
197
  return;
208
198
  }
@@ -242,7 +232,9 @@ class S3Uploader {
242
232
  return false;
243
233
  }
244
234
  debug(`File not found, retrying (attempt ${number}/${attempts})`);
245
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
235
+ await new Promise(resolve => {
236
+ setTimeout(resolve, intervalMs);
237
+ });
246
238
  retry(err);
247
239
  }
248
240
  },
@@ -250,7 +242,7 @@ class S3Uploader {
250
242
  retries: attempts,
251
243
  minTimeout: intervalMs,
252
244
  maxTimeout: intervalMs,
253
- }
245
+ },
254
246
  );
255
247
  }
256
248
 
@@ -3,6 +3,8 @@ const { sep, basename } = require('path');
3
3
  const chalk = require('chalk');
4
4
  const fs = require('fs');
5
5
  const isValid = require('is-valid-path');
6
+ const path = require('path');
7
+ const os = require('os');
6
8
  const debug = require('debug')('@testomatio/reporter:util');
7
9
 
8
10
  /**
@@ -318,7 +320,28 @@ const testRunnerHelper = {
318
320
  },
319
321
  };
320
322
 
323
+ function storeRunId(runId) {
324
+ const filePath = path.join(os.tmpdir(), `testomatio.latest.run`);
325
+ fs.writeFileSync(filePath, runId);
326
+ }
327
+
328
+ function readLatestRunId() {
329
+ try {
330
+ const filePath = path.join(os.tmpdir(), `testomatio.latest.run`);
331
+ const stats = fs.statSync(filePath);
332
+ const diff = +new Date() - +stats.mtime;
333
+ const diffHours = diff / 1000 / 60 / 60;
334
+ if (diffHours > 1) return;
335
+
336
+ return fs.readFileSync(filePath)?.toString()?.trim();
337
+ } catch (e) {
338
+ return null;
339
+ }
340
+ }
341
+
321
342
  module.exports = {
343
+ storeRunId,
344
+ readLatestRunId,
322
345
  isSameTest,
323
346
  fetchSourceCode,
324
347
  fetchSourceCodeFromStackTrace,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "1.6.0-beta-2-artifacts",
3
+ "version": "1.6.0-beta-3-artifacts",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "main": "./lib/reporter.js",
6
6
  "typings": "typings/index.d.ts",