@testomatio/reporter 1.0.17 → 1.0.18-beta-cypress-artifacts.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.
@@ -1,7 +1,7 @@
1
1
  const debug = require('debug')('@testomatio/reporter:adapter:codeceptjs');
2
2
  const chalk = require('chalk');
3
3
  const TestomatClient = require('../client');
4
- const { STATUS, APP_PREFIX, TESTOMAT_TMP_STORAGE } = require('../constants');
4
+ const { STATUS, APP_PREFIX, TESTOMAT_TMP_STORAGE_DIR } = require('../constants');
5
5
  const upload = require('../fileUploader');
6
6
  const { parseTest: getIdFromTestTitle, fileSystem } = require('../utils/utils');
7
7
 
@@ -56,7 +56,7 @@ function CodeceptReporter(config) {
56
56
  // Listening to events
57
57
  event.dispatcher.on(event.all.before, () => {
58
58
  // clear tmp dir
59
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
59
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
60
60
 
61
61
  recorder.add('Creating new run', () => client.createRun());
62
62
  videos = [];
@@ -2,9 +2,9 @@
2
2
  const { Formatter, formatterHelpers } = require('@cucumber/cucumber');
3
3
  const chalk = require('chalk');
4
4
  const fs = require('fs');
5
- const { STATUS, TESTOMAT_TMP_STORAGE } = require('../../constants');
5
+ const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../../constants');
6
6
  const TestomatClient = require('../../client');
7
- const logger = require('../../logger');
7
+ const logger = require('../../storages/logger');
8
8
  const { parseTest, fileSystem } = require('../../utils/utils');
9
9
 
10
10
  const { GherkinDocumentParser, PickleParser } = formatterHelpers;
@@ -37,7 +37,7 @@ class CucumberReporter extends Formatter {
37
37
 
38
38
  parseEnvelope(envelope) {
39
39
  if (envelope.testRunStarted) {
40
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
40
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
41
41
  }
42
42
  if (envelope.testCaseStarted && this.client) {
43
43
  this.client.createRun();
@@ -2,7 +2,7 @@
2
2
  const { Formatter } = require('cucumber');
3
3
  const chalk = require('chalk');
4
4
  const { parseTest, fileSystem } = require('../../utils/utils');
5
- const { STATUS, TESTOMAT_TMP_STORAGE } = require('../../constants');
5
+ const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../../constants');
6
6
  const TestomatClient = require('../../client');
7
7
 
8
8
  const createTestomatFormatter = apiKey => {
@@ -97,7 +97,7 @@ const createTestomatFormatter = apiKey => {
97
97
 
98
98
  options.eventBroadcaster.on('gherkin-document', addDocument);
99
99
  options.eventBroadcaster.on('test-run-started', () => {
100
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
100
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
101
101
  this?.client?.createRun();
102
102
  });
103
103
  options.eventBroadcaster.on('test-case-finished', this.onTestCaseFinished.bind(this));
@@ -10,6 +10,7 @@ const testomatioReporter = on => {
10
10
  const client = new TestomatClient({ apiKey: process.env.TESTOMATIO });
11
11
 
12
12
  on('before:run', async (run) => {
13
+ // TODO: looks like client.env does not exist
13
14
  if (!client.env) {
14
15
  client.env = `${run.browser.displayName},${run.system.osName}`
15
16
  }
@@ -48,10 +49,16 @@ const testomatioReporter = on => {
48
49
  }
49
50
  }
50
51
 
51
- const screenshots = results.screenshots
52
- .filter(screenshot => screenshot.path.includes(title))
53
- .filter(screenshot => screenshot.testAttemptIndex === lastAttemptIndex)
54
- .map(screenshot => screenshot.path);
52
+ const screenshots = Array.isArray(results.screenshots)
53
+ ? results.screenshots
54
+ .filter(
55
+ screenshot =>
56
+ screenshot?.path &&
57
+ screenshot?.path.includes(title) &&
58
+ screenshot?.takenAt
59
+ )
60
+ .map(screenshot => screenshot.path)
61
+ : [];
55
62
 
56
63
  const files = [...videos, ...screenshots];
57
64
 
@@ -1,5 +1,5 @@
1
1
  const TestomatClient = require('../client');
2
- const { STATUS, TESTOMAT_TMP_STORAGE } = require('../constants');
2
+ const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../constants');
3
3
  const { parseTest, ansiRegExp, fileSystem } = require('../utils/utils');
4
4
 
5
5
  class JestReporter {
@@ -11,20 +11,9 @@ class JestReporter {
11
11
  this.client.createRun();
12
12
  }
13
13
 
14
- static getIdOfCurrentlyRunningTest() {
15
- if (!process.env.JEST_WORKER_ID) return null;
16
- try {
17
- // @ts-expect-error "expect" could only be defined inside Jest environement (forbidden to import it outside)
18
- // eslint-disable-next-line no-undef
19
- if (expect && expect?.getState()?.currentTestName) return parseTest(expect?.getState()?.currentTestName);
20
- } catch (e) {
21
- return null;
22
- }
23
- }
24
-
25
14
  onRunStart() {
26
15
  // clear tmp dir
27
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
16
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
28
17
  }
29
18
 
30
19
  onTestResult(test, testResult) {
@@ -72,9 +61,6 @@ class JestReporter {
72
61
  const { numFailedTests } = results;
73
62
  const status = numFailedTests === 0 ? STATUS.PASSED : STATUS.FAILED;
74
63
  this.client.updateRunStatus(status);
75
-
76
- // clear tmp dir
77
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
78
64
  }
79
65
  }
80
66
 
@@ -1,11 +1,9 @@
1
1
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
2
2
  const Mocha = require('mocha');
3
- const debug = require('debug')('@testomatio/reporter:adapter:mocha');
4
3
  const chalk = require('chalk');
5
4
  const TestomatClient = require('../client');
6
- const { STATUS, TESTOMAT_TMP_STORAGE } = require('../constants');
7
- const { parseTest, specificTestInfo, fileSystem } = require('../utils/utils');
8
- const ArtifactStorage = require('../_ArtifactStorageOld');
5
+ const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../constants');
6
+ const { parseTest, fileSystem } = require('../utils/utils');
9
7
 
10
8
  const { EVENT_RUN_BEGIN, EVENT_RUN_END, EVENT_TEST_FAIL, EVENT_TEST_PASS, EVENT_TEST_PENDING } =
11
9
  Mocha.Runner.constants;
@@ -15,7 +13,7 @@ function MochaReporter(runner, opts) {
15
13
  let passes = 0;
16
14
  let failures = 0;
17
15
  let skipped = 0;
18
- let artifactStore;
16
+ // let artifactStore;
19
17
 
20
18
  const apiKey = opts?.reporterOptions?.apiKey || process.env.TESTOMATIO;
21
19
 
@@ -24,13 +22,7 @@ function MochaReporter(runner, opts) {
24
22
  runner.on(EVENT_RUN_BEGIN, () => {
25
23
  client.createRun();
26
24
 
27
- const params = {
28
- toFile: true,
29
- };
30
-
31
- artifactStore = runner._workerReporter !== undefined ? new ArtifactStorage(params) : new ArtifactStorage();
32
-
33
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
25
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
34
26
  });
35
27
 
36
28
  runner.on(EVENT_TEST_PASS, async test => {
@@ -38,20 +30,11 @@ function MochaReporter(runner, opts) {
38
30
  console.log(chalk.bold.green('✔'), test.fullTitle());
39
31
  const testId = parseTest(test.title);
40
32
 
41
- const specificTest = specificTestInfo(test);
42
- const content = await artifactStore.artifactByTestName(specificTest);
43
-
44
- debug(`test=${specificTest} content = `, content);
45
-
46
- client.addTestRun(
47
- STATUS.PASSED,
48
- {
49
- test_id: testId,
50
- title: test.title,
51
- time: test.duration,
52
- },
53
- content,
54
- );
33
+ client.addTestRun(STATUS.PASSED, {
34
+ test_id: testId,
35
+ title: test.title,
36
+ time: test.duration,
37
+ });
55
38
  });
56
39
 
57
40
  runner.on(EVENT_TEST_PENDING, test => {
@@ -70,29 +53,18 @@ function MochaReporter(runner, opts) {
70
53
  console.log(chalk.bold.red('✖'), test.fullTitle(), chalk.gray(err.message));
71
54
  const testId = parseTest(test.title);
72
55
 
73
- const specificTest = specificTestInfo(test);
74
- const content = await artifactStore.artifactByTestName(specificTest);
75
-
76
- debug(`fail test=${specificTest} content = `, content);
77
-
78
- client.addTestRun(
79
- STATUS.FAILED,
80
- {
81
- error: err,
82
- test_id: testId,
83
- title: test.title,
84
- time: test.duration,
85
- },
86
- content,
87
- );
56
+ client.addTestRun(STATUS.FAILED, {
57
+ error: err,
58
+ test_id: testId,
59
+ title: test.title,
60
+ time: test.duration,
61
+ });
88
62
  });
89
63
 
90
64
  runner.on(EVENT_RUN_END, () => {
91
65
  const status = failures === 0 ? STATUS.PASSED : STATUS.FAILED;
92
66
  console.log(chalk.bold(status), `${passes} passed, ${failures} failed, ${skipped} skipped`);
93
67
  client.updateRunStatus(status);
94
-
95
- artifactStore.cleanup();
96
68
  });
97
69
  }
98
70
 
@@ -3,7 +3,7 @@ const crypto = require('crypto');
3
3
  const os = require('os');
4
4
  const path = require('path');
5
5
  const fs = require('fs');
6
- const { APP_PREFIX, STATUS: Status, TESTOMAT_TMP_STORAGE } = require('../constants');
6
+ const { APP_PREFIX, STATUS: Status, TESTOMAT_TMP_STORAGE_DIR } = require('../constants');
7
7
  const TestomatioClient = require('../client');
8
8
  const { isArtifactsEnabled } = require('../fileUploader');
9
9
  const { parseTest, fileSystem } = require('../utils/utils');
@@ -19,15 +19,17 @@ class PlaywrightReporter {
19
19
 
20
20
  onBegin(_config, suite) {
21
21
  // clean data storage
22
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
22
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
23
23
  if (!this.client) return;
24
24
  this.suite = suite;
25
25
  this.client.createRun();
26
26
  }
27
27
 
28
- // onTestBegin(test) {
29
- // const testId = parseTest(test.title);
30
- // }
28
+ /*
29
+ onTestBegin(test) {
30
+ // does not work; value is not to the storage context
31
+ global.testTitle = test.title;
32
+ } */
31
33
 
32
34
  onTestEnd(test, result) {
33
35
  if (!this.client) return;
@@ -44,23 +46,33 @@ class PlaywrightReporter {
44
46
  appendStep(step, steps);
45
47
  }
46
48
 
47
- const logs = `\n\n${chalk.bold('Logs:')}\n${chalk.red(result.stderr.join(''))}\n${result.stdout.join('')}`;
48
-
49
- const reportTestPromise = this.client.addTestRun(checkStatus(result.status), {
50
- error,
51
- test_id: testId,
52
- suite_title,
53
- title,
54
- steps: steps.join('\n'),
55
- time: duration,
56
- stack: logs,
57
- }).then(pipes => {
58
- testId = pipes?.filter(p => p.pipe.includes('Testomatio'))[0]?.result?.data?.test_id;
59
-
60
- this.uploads.push({
61
- testId, title, suite_title, files: result.attachments.filter((a) => a.body || a.path)
49
+ let logs = '';
50
+ if (result.stderr.length || result.stdout.length) {
51
+ logs = `\n\n${chalk.bold('Logs:')}\n${chalk.red(result.stderr.join(''))}\n${result.stdout.join('')}`;
52
+ }
53
+
54
+ const reportTestPromise = this.client
55
+ .addTestRun(checkStatus(result.status), {
56
+ error,
57
+ test_id: testId,
58
+ suite_title,
59
+ title,
60
+ steps: steps.join('\n'),
61
+ time: duration,
62
+ stack: logs,
63
+ })
64
+ .then(pipes => {
65
+ testId = pipes?.filter(p => p.pipe.includes('Testomatio'))[0]?.result?.data?.test_id;
66
+
67
+ this.uploads.push({
68
+ testId,
69
+ title,
70
+ suite_title,
71
+ files: result.attachments.filter(a => a.body || a.path),
72
+ });
73
+ // remove empty uploads
74
+ this.uploads = this.uploads.filter(upload => upload.files.length);
62
75
  });
63
- });
64
76
 
65
77
  reportTestPromises.push(reportTestPromise);
66
78
  }
@@ -53,6 +53,12 @@ program
53
53
 
54
54
  let exitCode = 0;
55
55
 
56
+ if (!command.split) {
57
+ process.exitCode = 255;
58
+ console.log(APP_PREFIX, `No command provided. Use -c option to launch a test runner.`);
59
+ return;
60
+ }
61
+
56
62
  const client = new TestomatClient({ apiKey, title, parallel: true });
57
63
 
58
64
  if(filter) {
@@ -74,12 +80,6 @@ program
74
80
  }
75
81
  }
76
82
 
77
- if (!command.split) {
78
- process.exitCode = 255;
79
- console.log(APP_PREFIX, `No command provided. Use -c option to launch a test runner.`);
80
- return;
81
- }
82
-
83
83
  const testCmds = command.split(' ');
84
84
  console.log(APP_PREFIX, `🚀 Running`, chalk.green(command));
85
85
 
package/lib/client.js CHANGED
@@ -8,6 +8,7 @@ const { randomUUID } = require('crypto');
8
8
  const upload = require('./fileUploader');
9
9
  const { APP_PREFIX } = require('./constants');
10
10
  const pipesFactory = require('./pipe');
11
+ const artifactStorage = require('./storages/artifact-storage');
11
12
 
12
13
  /**
13
14
  * @typedef {import('../types').TestData} TestData
@@ -96,9 +97,6 @@ class Client {
96
97
  // all pipes disabled, skipping
97
98
  if (!this.pipes?.filter(p => p.isEnabled).length) return Promise.resolve();
98
99
 
99
- global.testomatioArtifacts = [];
100
- if (!global.testomatioDataStore) global.testomatioDataStore = {};
101
-
102
100
  this.queue = this.queue
103
101
  .then(() => Promise.all(this.pipes.map(p => p.createRun())))
104
102
  .catch(err => console.log(APP_PREFIX, err))
@@ -112,11 +110,9 @@ class Client {
112
110
  *
113
111
  * @param {string|undefined} status
114
112
  * @param {TestData} [testData]
115
- * @param {string[]} [storeArtifacts]
116
113
  * @returns {Promise<PipeResult[]>}
117
114
  */
118
- async addTestRun(status, testData, storeArtifacts = []) {
119
- debug('Adding test run for test', testData?.test_id || 'unknown test');
115
+ async addTestRun(status, testData) {
120
116
  // all pipes disabled, skipping
121
117
  if (!this.pipes?.filter(p => p.isEnabled).length) return [];
122
118
 
@@ -155,23 +151,21 @@ class Client {
155
151
 
156
152
  stack += testData.stack || '';
157
153
 
154
+ // ATTACH LOGS from storage
158
155
  // in some cases (e.g. using cucumber) logger instance becomes empty object, if import at the top of the file
159
- const logger = require('./logger');
156
+ const logger = require('./storages/logger');
160
157
  const testLogs = logger.getLogs(test_id);
161
158
  // debug(`Test logs for ${test_id}:\n`, testLogs);
162
159
  if (stack) stack += '\n\n';
163
160
  stack += testLogs ? `${chalk.bold('Logs:')}\n${testLogs}` : '';
164
161
 
165
- if (Array.isArray(storeArtifacts) && storeArtifacts.length) {
166
- debug('CLIENT storeArtifact', storeArtifacts);
167
- files.push(...storeArtifacts);
168
- }
162
+ // GET ARTIFACTS from storage
163
+ const artifactFiles = artifactStorage.get(test_id);
164
+ if (artifactFiles) files.push(...artifactFiles);
169
165
 
170
- if (Array.isArray(global.testomatioArtifacts)) {
171
- debug('CLIENT global[testomatioArtifacts]', global.testomatioArtifacts);
172
- files.push(...global.testomatioArtifacts);
173
- global.testomatioArtifacts = [];
174
- }
166
+ // GET KEY-VALUEs from storage
167
+ const keyValueStorage = require('./storages/key-value-storage');
168
+ const keyValues = keyValueStorage.get(test_id);
175
169
 
176
170
  for (const file of files) {
177
171
  uploadedFiles.push(upload.uploadFileByPath(file, this.uuid));
@@ -184,7 +178,7 @@ class Client {
184
178
 
185
179
  const artifacts = await Promise.all(uploadedFiles);
186
180
 
187
- global.testomatioArtifacts = [];
181
+ // global.testomatioArtifacts = [];
188
182
 
189
183
  this.totalUploaded += uploadedFiles.filter(n => n).length;
190
184
 
@@ -202,6 +196,7 @@ class Client {
202
196
  message,
203
197
  run_time: parseFloat(time),
204
198
  artifacts,
199
+ meta: keyValues,
205
200
  };
206
201
 
207
202
  this.queue = this.queue.then(() =>
@@ -237,14 +232,16 @@ class Client {
237
232
  this.queue = this.queue
238
233
  .then(() => Promise.all(this.pipes.map(p => p.finishRun(runParams))))
239
234
  .then(() => {
240
- debug('TOTAL uploaded files', this.totalUploaded);
235
+ debug('TOTAL artifacts', this.totalUploaded);
236
+ if (this.totalUploaded && !upload.isArtifactsEnabled())
237
+ debug(`${this.totalUploaded} artifacts are not uploaded, because artifacts uploading is not enabled`);
241
238
 
242
- if (upload.isArtifactsEnabled() && this.totalUploaded > 0) {
239
+ if (this.totalUploaded && upload.isArtifactsEnabled()) {
243
240
  console.log(
244
241
  APP_PREFIX,
245
- `🗄️ Total ${this.totalUploaded} artifacts ${
242
+ `🗄️ ${this.totalUploaded} artifacts ${
246
243
  process.env.TESTOMATIO_PRIVATE_ARTIFACTS ? 'privately' : chalk.bold('publicly')
247
- } uploaded to S3 bucket `,
244
+ } uploaded to S3 bucket`,
248
245
  );
249
246
  }
250
247
  })
package/lib/config.js ADDED
@@ -0,0 +1,24 @@
1
+ // This file is used to read environment variables from .env file and process.env
2
+
3
+ // ! uncommenting next line leads ro reading vars from .env file
4
+ // require('dotenv').config();
5
+ const debug = require('debug')('@testomatio/reporter:config');
6
+
7
+ /* for possibility to use multiple env files (reading different paths)
8
+ const dotenv = require('dotenv');
9
+ const envFileVars = dotenv.config({ path: '.env' }).parsed; */
10
+
11
+ // select only TESTOMATIO related variables (only to print them in debug)
12
+ const testomatioEnvVars =
13
+ Object.keys(process.env)
14
+ .filter(key => key.startsWith('TESTOMATIO') || key.startsWith('S3_'))
15
+ .reduce((obj, key) => {
16
+ obj[key] = process.env[key];
17
+ return obj;
18
+ }, {}) || {};
19
+ debug('TESTOMATIO variables:', testomatioEnvVars);
20
+
21
+ // includes variables from .env file and process.env
22
+ const config = process.env;
23
+
24
+ module.exports = config;
package/lib/constants.js CHANGED
@@ -1,11 +1,10 @@
1
1
  const chalk = require('chalk');
2
+ const os = require('os');
3
+ const path = require('path');
2
4
 
3
5
  const APP_PREFIX = chalk.gray('[TESTOMATIO]');
4
- const TESTOMAT_ARTIFACT_SUFFIX = "testomatio_artifact_";
5
6
 
6
- const TESTOMAT_TMP_STORAGE = {
7
- mainDir: "testomatio_tmp",
8
- }
7
+ const TESTOMAT_TMP_STORAGE_DIR = path.join(os.tmpdir(), 'testomatio_tmp');
9
8
 
10
9
  const CSV_HEADERS = [
11
10
  { id: 'suite_title', title: 'Suite_title' },
@@ -21,11 +20,17 @@ const STATUS = {
21
20
  SKIPPED: 'skipped',
22
21
  FINISHED: 'finished',
23
22
  };
23
+ // html pipe var
24
+ const HTML_REPORT = {
25
+ FOLDER: "html-report",
26
+ REPORT_DEFAULT_NAME: "testomatio-report.html",
27
+ TEMPLATE_NAME: 'testomatio.hbs'
28
+ };
24
29
 
25
30
  module.exports = {
26
31
  APP_PREFIX,
27
- TESTOMAT_ARTIFACT_SUFFIX,
28
- TESTOMAT_TMP_STORAGE,
32
+ TESTOMAT_TMP_STORAGE_DIR,
29
33
  CSV_HEADERS,
30
34
  STATUS,
35
+ HTML_REPORT
31
36
  }