@testomatio/reporter 0.8.0-beta.20 → 0.8.0-beta.30

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/Changelog.md CHANGED
@@ -1,3 +1,15 @@
1
+ # 0.7.6
2
+
3
+ * Updated to use AWS S3 3.0 SDK for uploading
4
+
5
+ # 0.7.5
6
+
7
+ * Fixed reporting skipped tests in mocha
8
+
9
+ # 0.7.4
10
+
11
+ * Fixed parsing source code in JUnit files
12
+
1
13
  # 0.7.3
2
14
 
3
15
  * CodeceptJS: Upload all traces and videos from artifacts
package/README.md CHANGED
@@ -20,6 +20,19 @@ For testcafe use testcafe reporter:
20
20
  npm i testcafe-reporter-testomatio
21
21
  ```
22
22
 
23
+ For newman use:
24
+
25
+ ```bash
26
+ npm i newman-reporter-testomatio --save-dev
27
+ ```
28
+
29
+ >`newman` and `newman-reporter-testomatio` should be installed in the same directory.
30
+ \
31
+ If you run your tests using globally installed newman (`newman run ...`), intall `newman-reporter-testomatio` globally too (`npm i newman-reporter-testomatio -g`).
32
+ \
33
+ If you use locally installed newman (within the project) (`npx newman run ...`), install `newman-reporter-testomatio` locally (`npm i newman-reporter-testomatio`).
34
+ You can verify installed packages via `npm list` or `npm list -g`.
35
+
23
36
  ## Usage
24
37
 
25
38
  ### CodeceptJS
@@ -121,6 +134,15 @@ Run the following command from you project folder:
121
134
  TESTOMATIO={API_KEY} npx testcafe chrome -r testomatio
122
135
  ```
123
136
 
137
+ ### Newman (Postman)
138
+
139
+ Run collection and specify `testomatio` as reporter:
140
+
141
+ `TESTOMATIO={API_KEY} npx newman run {collection_name.json} -r testomatio`
142
+
143
+ > _`check-test` not supported for newman for now, tests will be created on testomatio by default_
144
+
145
+
124
146
  ### Cypress
125
147
 
126
148
  Load the test using using `check-test`.
@@ -212,13 +234,16 @@ TESTOMATIO={API_KEY} npx start-test-run -c 'npx wdio wdio.conf.js'
212
234
  Pipes allow you to get report inside different systems (e.g. Pull request comment, database etc)
213
235
  For now next pipes available:
214
236
 
215
- ### Github
237
+ ### GitHub
216
238
  This pipe adds comment with run report to GitHub Pull Request.
217
239
 
218
240
  To use it:
219
241
  1. run your tests using github actions in Pull Request
220
242
  2. pass `GH_PAT` (GitHub Personal Access Token) as environment variable.
221
243
 
244
+ > Last report (comment) will be replaced with the new one.
245
+ To leave previous report pass `GITHUB_KEEP_OUTDATED_REPORTS=1` env variable.
246
+
222
247
  ### GitLab
223
248
  This pipe adds comment with run report to GitLab Merge Request.
224
249
 
@@ -226,6 +251,9 @@ To use it:
226
251
  1. run your tests in Merge Request (pipeline trigger should be `merge_request`)
227
252
  2. pass `GITLAB_PAT` (GitLab Personal Access Token) as environment variable.
228
253
 
254
+ > Last report (comment) will be replaced with the new one.
255
+ To leave previous report pass `GITLAB_KEEP_OUTDATED_REPORTS=1` env variable.
256
+
229
257
  ## JUnit Reports
230
258
 
231
259
  > **Notice** JUnit reports are supported since 0.6.0
@@ -67,7 +67,7 @@ function CodeceptReporter(config) {
67
67
  });
68
68
 
69
69
  event.dispatcher.on(event.all.result, async () => {
70
- if (videos.length && upload.isArtifactsEnabled) {
70
+ if (videos.length && upload.isArtifactsEnabled()) {
71
71
  console.log(TRConstants.APP_PREFIX, `🎞️ Uploading ${videos.length} videos...`);
72
72
 
73
73
  const promises = [];
@@ -5,14 +5,19 @@ const TestomatClient = require('../client');
5
5
  const TRConstants = require('../constants');
6
6
  const { parseTest } = require('../util');
7
7
 
8
- const { EVENT_RUN_BEGIN, EVENT_RUN_END, EVENT_TEST_FAIL, EVENT_TEST_PASS } = Mocha.Runner.constants;
8
+ const { EVENT_RUN_BEGIN, EVENT_RUN_END, EVENT_TEST_FAIL, EVENT_TEST_PASS, EVENT_TEST_PENDING } = Mocha.Runner.constants;
9
9
 
10
10
  function MochaReporter(runner, opts) {
11
11
  Mocha.reporters.Base.call(this, runner);
12
- let passes = 0;
13
- let failures = 0;
12
+ let passes = 0; let failures = 0; let skipped = 0; // eslint-disable-line no-unused-vars
14
13
 
15
- const client = new TestomatClient({ apiKey: opts?.reporterOptions?.apiKey });
14
+ const apiKey = opts?.reporterOptions?.apiKey || process.env.TESTOMATIO;
15
+
16
+ if (!apiKey) {
17
+ console.log('TESTOMATIO key is empty, ignoring reports');
18
+ return;
19
+ }
20
+ const client = new TestomatClient({ apiKey });
16
21
 
17
22
  runner.on(EVENT_RUN_BEGIN, () => {
18
23
  client.createRun();
@@ -28,6 +33,16 @@ function MochaReporter(runner, opts) {
28
33
  });
29
34
  });
30
35
 
36
+ runner.on(EVENT_TEST_PENDING, test => {
37
+ skipped += 1;
38
+ console.log('skip: %s', test.fullTitle());
39
+ const testId = parseTest(test.title);
40
+ client.addTestRun(testId, TRConstants.SKIPPED, {
41
+ title: test.title,
42
+ time: test.duration,
43
+ });
44
+ });
45
+
31
46
  runner.on(EVENT_TEST_FAIL, (test, err) => {
32
47
  failures += 1;
33
48
  console.log(chalk.bold.red('✖'), test.fullTitle(), chalk.gray(err.message));
@@ -69,7 +69,7 @@ class TestomatioReporter {
69
69
  async onEnd(result) {
70
70
  if (!this.client) return;
71
71
 
72
- if (this.videos.length && upload.isArtifactsEnabled) {
72
+ if (this.videos.length && upload.isArtifactsEnabled()) {
73
73
  console.log(Status.APP_PREFIX, `🎞️ Uploading ${this.videos.length} videos...`);
74
74
 
75
75
  const promises = [];
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
+
2
3
  const program = require("commander");
3
4
  const chalk = require("chalk");
4
5
  const glob = require('glob');
5
-
6
+ const debug = require('debug')('@testomatio/reporter:xml-cli');
6
7
  const { APP_PREFIX } = require('../constants');
7
8
  const XmlReader = require("../xmlReader");
8
9
 
@@ -22,7 +23,10 @@ program
22
23
  pattern += '.xml';
23
24
  }
24
25
  let { javaTests, lang } = opts;
25
- if (opts.envFile) require('dotenv').config(opts.envFile); // eslint-disable-line
26
+ if (opts.envFile) {
27
+ debug('Loading env file: %s', opts.envFile)
28
+ require('dotenv').config({ path: opts.envFile }); // eslint-disable-line
29
+ }
26
30
  if (javaTests === true) javaTests = 'src/test/java';
27
31
  lang = lang?.toLowerCase();
28
32
  const runReader = new XmlReader({ javaTests, lang });
package/lib/client.js CHANGED
@@ -8,7 +8,6 @@ const pipesFactory = require('./pipe');
8
8
 
9
9
  const { TESTOMATIO_ENV } = process.env;
10
10
 
11
-
12
11
  class TestomatClient {
13
12
  /**
14
13
  * Create a Testomat client instance
@@ -17,9 +16,11 @@ class TestomatClient {
17
16
  */
18
17
  constructor(params = {}) {
19
18
  this.title = params.title || process.env.TESTOMATIO_TITLE;
20
- this.env = TESTOMATIO_ENV;
19
+ this.createNewTests = params.createNewTests ?? !!process.env.TESTOMATIO_CREATE;
20
+ this.proceed = process.env.TESTOMATIO_PROCEED;
21
+ this.env = TESTOMATIO_ENV;
21
22
  this.parallel = params.parallel;
22
- const store = {}
23
+ const store = {};
23
24
  this.pipes = pipesFactory(params, store);
24
25
  this.queue = Promise.resolve();
25
26
  this.totalUploaded = 0;
@@ -44,7 +45,9 @@ class TestomatClient {
44
45
 
45
46
  global.testomatioArtifacts = [];
46
47
 
47
- this.queue = this.queue.then(() => Promise.all(this.pipes.map(p => p.createRun(runParams)))).catch(err => console.log(APP_PREFIX, err));;
48
+ this.queue = this.queue
49
+ .then(() => Promise.all(this.pipes.map(p => p.createRun(runParams))))
50
+ .catch(err => console.log(APP_PREFIX, err));
48
51
 
49
52
  return this.queue;
50
53
  }
@@ -100,7 +103,7 @@ class TestomatClient {
100
103
  uploadedFiles.push(upload.uploadFileAsBuffer(buffer, fileName, this.runId));
101
104
  }
102
105
 
103
- const artifacts = await Promise.all(uploadedFiles)
106
+ const artifacts = await Promise.all(uploadedFiles);
104
107
 
105
108
  global.testomatioArtifacts = [];
106
109
 
@@ -112,7 +115,7 @@ class TestomatClient {
112
115
  status,
113
116
  stack,
114
117
  example,
115
- title,
118
+ title,
116
119
  suite_title,
117
120
  suite_id,
118
121
  test_id,
@@ -121,7 +124,9 @@ class TestomatClient {
121
124
  artifacts,
122
125
  };
123
126
 
124
- this.queue = this.queue.then(() => Promise.all(this.pipes.map(p => p.addTest(data)))).catch(err => console.log(APP_PREFIX, err));;
127
+ this.queue = this.queue
128
+ .then(() => Promise.all(this.pipes.map(p => p.addTest(data))))
129
+ .catch(err => console.log(APP_PREFIX, err));
125
130
  return this.queue;
126
131
  }
127
132
 
@@ -139,11 +144,13 @@ class TestomatClient {
139
144
  if (status === PASSED) statusEvent = 'pass';
140
145
  if (status === FAILED) statusEvent = 'fail';
141
146
  if (isParallel) statusEvent += '_parallel';
142
- const runParams = { status, statusEvent }
147
+ const runParams = { status, statusEvent };
143
148
 
144
- this.queue = this.queue.then(() => Promise.all(this.pipes.map(p => p.finishRun(runParams)))).catch(err => console.log(APP_PREFIX, err));;
149
+ this.queue = this.queue
150
+ .then(() => Promise.all(this.pipes.map(p => p.finishRun(runParams))))
151
+ .catch(err => console.log(APP_PREFIX, err));
145
152
 
146
- if (upload.isArtifactsEnabled && this.totalUploaded > 0) {
153
+ if (upload.isArtifactsEnabled() && this.totalUploaded > 0) {
147
154
  console.log(
148
155
  APP_PREFIX,
149
156
  `🗄️ Total ${this.totalUploaded} artifacts ${
@@ -1,4 +1,6 @@
1
- const AWS = require('aws-sdk');
1
+ const debug = require('debug')('@testomatio/reporter:upload');
2
+ const { S3 } = require('@aws-sdk/client-s3');
3
+ const { Upload } = require("@aws-sdk/lib-storage");
2
4
  const fs = require('fs');
3
5
  const path = require('path');
4
6
  const chalk = require('chalk');
@@ -6,18 +8,38 @@ const { randomUUID } = require('crypto');
6
8
  const memoize = require('lodash.memoize');
7
9
  const { APP_PREFIX } = require('./constants');
8
10
 
9
- const {
10
- S3_ENDPOINT,
11
- S3_REGION,
12
- S3_BUCKET,
13
- S3_ACCESS_KEY_ID,
14
- S3_SECRET_ACCESS_KEY,
15
- TESTOMATIO_DISABLE_ARTIFACTS,
16
- TESTOMATIO_PRIVATE_ARTIFACTS,
17
- S3_FORCE_PATH_STYLE,
18
- } = process.env;
19
-
20
- const isArtifactsEnabled = S3_BUCKET && !TESTOMATIO_DISABLE_ARTIFACTS;
11
+ const keys = [
12
+ 'S3_ENDPOINT',
13
+ 'S3_REGION',
14
+ 'S3_BUCKET',
15
+ 'S3_ACCESS_KEY_ID',
16
+ 'S3_SECRET_ACCESS_KEY',
17
+ 'TESTOMATIO_DISABLE_ARTIFACTS',
18
+ 'TESTOMATIO_PRIVATE_ARTIFACTS',
19
+ 'S3_FORCE_PATH_STYLE',
20
+ ];
21
+
22
+ let config;
23
+
24
+ function getConfig() {
25
+ if (config) return config;
26
+ config = keys.reduce((acc, key) => {
27
+ acc[key] = process.env[key];
28
+ return acc;
29
+ }, {});
30
+ debug('Config', config);
31
+ return config;
32
+ }
33
+
34
+ let isEnabled;
35
+
36
+ const isArtifactsEnabled = () => {
37
+ if (isEnabled !== undefined) return isEnabled;
38
+ const { S3_BUCKET, TESTOMATIO_DISABLE_ARTIFACTS } = getConfig();
39
+ isEnabled = !!(S3_BUCKET && !TESTOMATIO_DISABLE_ARTIFACTS);
40
+ debug(`Upload is ${isEnabled ? 'enabled' : 'disabled'}`);
41
+ return isEnabled;
42
+ };
21
43
 
22
44
  const _getFileExtBase64 = str => {
23
45
  const type = str.charAt(0);
@@ -32,6 +54,25 @@ const _getFileExtBase64 = str => {
32
54
  );
33
55
  };
34
56
 
57
+ const _getS3Config = () => {
58
+ const { S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_FORCE_PATH_STYLE, S3_ENDPOINT } = getConfig();
59
+
60
+ const cfg = {
61
+ region: S3_REGION,
62
+ credentials: {
63
+ accessKeyId: S3_ACCESS_KEY_ID,
64
+ secretAccessKey: S3_SECRET_ACCESS_KEY,
65
+ s3ForcePathStyle: S3_FORCE_PATH_STYLE,
66
+ }
67
+ };
68
+
69
+ if (S3_ENDPOINT) {
70
+ cfg.endpoint = S3_ENDPOINT;
71
+ }
72
+
73
+ return cfg;
74
+ }
75
+
35
76
  const uploadUsingS3 = async (filePath, runId) => {
36
77
  let ContentType;
37
78
  let Key;
@@ -42,40 +83,37 @@ const uploadUsingS3 = async (filePath, runId) => {
42
83
  Key = filePath.name;
43
84
  }
44
85
 
45
- const config = {
46
- region: S3_REGION,
47
- accessKeyId: S3_ACCESS_KEY_ID,
48
- secretAccessKey: S3_SECRET_ACCESS_KEY,
49
- s3ForcePathStyle: S3_FORCE_PATH_STYLE,
50
- };
51
-
52
- if (S3_ENDPOINT) {
53
- config.endpoint = new AWS.Endpoint(S3_ENDPOINT);
54
- }
55
-
56
- const s3 = new AWS.S3(config);
57
86
  if (!fs.existsSync(filePath)) {
58
87
  console.error(chalk.yellow(`Artifacts file ${filePath} does not exist. Skipping...`));
59
88
  return;
60
89
  }
90
+
91
+ const { S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT, TESTOMATIO_PRIVATE_ARTIFACTS, S3_BUCKET } = getConfig();
61
92
 
62
93
  const file = fs.readFileSync(filePath);
63
94
 
64
95
  Key = `${runId}/${randomUUID()}-${Key || path.basename(filePath)}`;
65
96
  const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
66
97
 
98
+ const s3 = new S3(_getS3Config());
99
+
67
100
  try {
68
- const out = await s3
69
- .upload({
101
+ const out = new Upload({
102
+ client: s3,
103
+
104
+ params: {
70
105
  Bucket: S3_BUCKET,
71
106
  Key,
72
107
  Body: file,
73
108
  ContentType,
74
109
  ACL,
75
- })
76
- .promise();
110
+ }
111
+ });
77
112
 
78
- return out.Location;
113
+ await out.done();
114
+ debug('Uploaded', out.singleUploadResult.Location)
115
+
116
+ return out.singleUploadResult.Location;
79
117
  } catch (e) {
80
118
  console.log(APP_PREFIX, chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`), {
81
119
  accessKeyId: S3_ACCESS_KEY_ID,
@@ -100,35 +138,30 @@ const uploadUsingS3 = async (filePath, runId) => {
100
138
  };
101
139
 
102
140
  const uploadUsingS3AsBuffer = async (buffer, fileName, runId) => {
103
- const config = {
104
- region: S3_REGION,
105
- accessKeyId: S3_ACCESS_KEY_ID,
106
- secretAccessKey: S3_SECRET_ACCESS_KEY,
107
- s3ForcePathStyle: S3_FORCE_PATH_STYLE,
108
- };
109
-
110
- if (S3_ENDPOINT) {
111
- config.endpoint = new AWS.Endpoint(S3_ENDPOINT);
112
- }
113
141
 
114
- const s3 = new AWS.S3(config);
142
+ const { S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT, TESTOMATIO_PRIVATE_ARTIFACTS, S3_BUCKET } = getConfig();
115
143
 
116
144
  const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
117
145
 
118
146
  const fileExtension = _getFileExtBase64(buffer.toString('base64'));
119
147
  const Key = `${runId}/${fileName}${fileExtension}`;
120
148
 
149
+ const s3 = new S3(_getS3Config());
150
+
121
151
  try {
122
- const out = await s3
123
- .upload({
152
+ const out = new Upload({
153
+ client: s3,
154
+
155
+ params: {
124
156
  Bucket: S3_BUCKET,
125
157
  Key,
126
158
  Body: buffer,
127
159
  ACL,
128
- })
129
- .promise();
160
+ }
161
+ });
162
+ await out.done();
130
163
 
131
- return out.Location;
164
+ return out.singleUploadResult.Location;
132
165
  } catch (e) {
133
166
  console.log(APP_PREFIX, chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`), {
134
167
  accessKeyId: S3_ACCESS_KEY_ID,
@@ -154,7 +187,7 @@ const uploadUsingS3AsBuffer = async (buffer, fileName, runId) => {
154
187
 
155
188
  const uploadFileByPath = async (filePath, runId) => {
156
189
  try {
157
- if (isArtifactsEnabled) {
190
+ if (isArtifactsEnabled()) {
158
191
  return uploadUsingS3(filePath, runId);
159
192
  }
160
193
  } catch (e) {
@@ -164,7 +197,7 @@ const uploadFileByPath = async (filePath, runId) => {
164
197
 
165
198
  const uploadFileAsBuffer = async (buffer, fileName, runId) => {
166
199
  try {
167
- if (isArtifactsEnabled) {
200
+ if (isArtifactsEnabled()) {
168
201
  return uploadUsingS3AsBuffer(buffer, fileName, runId);
169
202
  }
170
203
  } catch (e) {
@@ -175,5 +208,5 @@ const uploadFileAsBuffer = async (buffer, fileName, runId) => {
175
208
  module.exports = {
176
209
  uploadFileByPath: memoize(uploadFileByPath),
177
210
  uploadFileAsBuffer: memoize(uploadFileAsBuffer),
178
- isArtifactsEnabled,
211
+ isArtifactsEnabled: memoize(isArtifactsEnabled),
179
212
  };
package/lib/pipe/csv.js CHANGED
@@ -1,5 +1,5 @@
1
- const path = require("path");
2
- const fs = require("fs");
1
+ const path = require('path');
2
+ const fs = require('fs');
3
3
  const csvWriter = require('csv-writer');
4
4
  const chalk = require('chalk');
5
5
  const merge = require('lodash.merge');
@@ -7,105 +7,113 @@ const { isSameTest, getCurrentDateTime } = require('../util');
7
7
  const { CSV_HEADERS } = require('../constants');
8
8
 
9
9
  class CsvPipe {
10
+ constructor(params, store = {}) {
11
+ this.store = store;
12
+ this.title = params.title || process.env.TESTOMATIO_TITLE;
13
+ this.isEnabled = true;
14
+ this.results = [];
10
15
 
11
- constructor(params, store = {}) {
12
- this.store = store;
13
- this.title = params.title || process.env.TESTOMATIO_TITLE;
14
- this.isEnabled = true;
15
- this.results = [];
16
-
17
- this.outputDir = "export";
18
- this.csvFilename = process.env.TESTOMATIO_CSV_FILENAME;
19
- this.isCsvSave = false;
20
-
21
- if (this.csvFilename !== undefined && this.csvFilename.split(".").length > 0 ) {
22
- this.isCsvSave = true;
23
-
24
- if(this.csvFilename.split(".")[0] === "report") {
25
- this.outputFile = path.resolve(process.cwd(), this.outputDir, "report.csv");
26
- }
27
- else {
28
- this.outputFile = path.resolve(process.cwd(), this.outputDir, getCurrentDateTime() + "_" + this.csvFilename.split(".")[0] + ".csv");
29
- }
30
- }
16
+ this.outputDir = 'export';
17
+ this.csvFilename = process.env.TESTOMATIO_CSV_FILENAME;
18
+ this.isCsvSave = false;
19
+
20
+ if (this.csvFilename !== undefined && this.csvFilename.split('.').length > 0) {
21
+ this.isCsvSave = true;
22
+
23
+ if (this.csvFilename.split('.')[0] === 'report') {
24
+ this.outputFile = path.resolve(process.cwd(), this.outputDir, 'report.csv');
25
+ } else {
26
+ this.outputFile = path.resolve(
27
+ process.cwd(),
28
+ this.outputDir,
29
+ `${getCurrentDateTime()}_${this.csvFilename.split('.')[0]}.csv`,
30
+ );
31
+ }
31
32
  }
33
+ }
32
34
 
33
- async createRun() {}
35
+ async createRun() {
36
+ // empty
37
+ }
34
38
 
35
- updateRun() {}
39
+ updateRun() {}
36
40
 
37
- /**
38
- * Create a folder that will contain the exported files
39
- */
40
- checkExportDir() {
41
- if (!fs.existsSync(this.outputDir)) {
42
- return fs.mkdirSync(this.outputDir);
43
- }
44
- }
45
- /**
46
- * Save data to the csv file.
47
- * @param {Object} data - data that will be added to the CSV file. Example: [{suite_title: "Suite #1", test: "Test-case-1", message: "Test msg"}]
48
- * @param {Object} headers - csv file headers. Example: [{ id: 'suite_title', title: 'Suite_title' }]
49
- */
50
- async saveToCsv(data, headers) {
51
- // First, we check whether the export directory exists: if yes - OK, no - create it.
52
- this.checkExportDir();
53
-
54
- console.log(chalk.yellow(`The test results will be added to the csv. It will take some time...`));
55
- //Create csv writer object
56
- const writer = csvWriter.createObjectCsvWriter({
57
- path: this.outputFile,
58
- header: headers
59
- });
60
- //Save csv file based on the current data
61
- try {
62
- await writer.writeRecords(data);
63
- console.log(chalk.green(`Recording completed! You can check the result in file = ${this.outputFile}`));
64
- } catch(e) {
65
- console.log('Unknown error: ', e);
66
- }
41
+ /**
42
+ * Create a folder that will contain the exported files
43
+ */
44
+ checkExportDir() {
45
+ if (!fs.existsSync(this.outputDir)) {
46
+ return fs.mkdirSync(this.outputDir);
67
47
  }
68
- /**
69
- * Add test data to the result array for saving. As a result of this function, we get a result object to save.
70
- * @param {Object} test - object which includes each test entry.
71
- */
72
- addTest(test) {
73
- if (!this.isEnabled) return;
74
-
75
- const index = this.results.findIndex(t => isSameTest(t, test));
76
- // update if they were already added
77
- if (index >= 0) {
78
- this.results[index] = merge(this.results[index], test);
79
- return;
80
- }
81
-
82
- const {suite_title, title, status, message, stack} = test;
83
-
84
- this.results.push({
85
- suite_title,
86
- title,
87
- status,
88
- message,
89
- stack
90
- });
48
+ }
49
+
50
+ /**
51
+ * Save data to the csv file.
52
+ * @param {Object} data - data that will be added to the CSV file.
53
+ * Example: [{suite_title: "Suite #1", test: "Test-case-1", message: "Test msg"}]
54
+ * @param {Object} headers - csv file headers. Example: [{ id: 'suite_title', title: 'Suite_title' }]
55
+ */
56
+ async saveToCsv(data, headers) {
57
+ // First, we check whether the export directory exists: if yes - OK, no - create it.
58
+ this.checkExportDir();
59
+
60
+ console.log(chalk.yellow(`The test results will be added to the csv. It will take some time...`));
61
+ // Create csv writer object
62
+ const writer = csvWriter.createObjectCsvWriter({
63
+ path: this.outputFile,
64
+ header: headers,
65
+ });
66
+ // Save csv file based on the current data
67
+ try {
68
+ await writer.writeRecords(data);
69
+ console.log(chalk.green(`Recording completed! You can check the result in file = ${this.outputFile}`));
70
+ } catch (e) {
71
+ console.log('Unknown error: ', e);
91
72
  }
92
- /**
93
- * Save short tests data to the csv file.
94
- * @param {Object} runParams - run params.
95
- */
96
- async finishRun(runParams) {
97
- if (!this.isEnabled) return;
98
-
99
- if (runParams.tests) runParams.tests.forEach(t => this.addTest(t));
100
- //Save results based on the default headers
101
- if(this.isCsvSave) {
102
- this.saveToCsv(this.results, CSV_HEADERS);
103
- }
73
+ }
74
+
75
+ /**
76
+ * Add test data to the result array for saving. As a result of this function, we get a result object to save.
77
+ * @param {Object} test - object which includes each test entry.
78
+ */
79
+ addTest(test) {
80
+ if (!this.isEnabled) return;
81
+
82
+ const index = this.results.findIndex(t => isSameTest(t, test));
83
+ // update if they were already added
84
+ if (index >= 0) {
85
+ this.results[index] = merge(this.results[index], test);
86
+ return;
104
87
  }
105
88
 
106
- toString() {
107
- return 'csv exporter';
89
+ const { suite_title, title, status, message, stack } = test;
90
+
91
+ this.results.push({
92
+ suite_title,
93
+ title,
94
+ status,
95
+ message,
96
+ stack,
97
+ });
98
+ }
99
+
100
+ /**
101
+ * Save short tests data to the csv file.
102
+ * @param {Object} runParams - run params.
103
+ */
104
+ async finishRun(runParams) {
105
+ if (!this.isEnabled) return;
106
+
107
+ if (runParams.tests) runParams.tests.forEach(t => this.addTest(t));
108
+ // Save results based on the default headers
109
+ if (this.isCsvSave) {
110
+ this.saveToCsv(this.results, CSV_HEADERS);
108
111
  }
112
+ }
113
+
114
+ toString() {
115
+ return 'csv exporter';
116
+ }
109
117
  }
110
118
 
111
- module.exports = CsvPipe;
119
+ module.exports = CsvPipe;