@testomatio/reporter 0.8.0-beta.3 → 0.8.0-beta.31
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 +12 -0
- package/README.md +77 -7
- package/lib/ArtifactStorage.js +132 -0
- package/lib/adapter/codecept.js +1 -6
- package/lib/adapter/cucumber/current.js +1 -7
- package/lib/adapter/jasmine.js +1 -8
- package/lib/adapter/jest.js +1 -7
- package/lib/adapter/mocha.js +66 -16
- package/lib/adapter/playwright.js +2 -8
- package/lib/adapter/webdriver.js +1 -4
- package/lib/bin/reportXml.js +6 -2
- package/lib/client.js +52 -25
- package/lib/constants.js +11 -0
- package/lib/fileUploader.js +86 -49
- package/lib/pipe/csv.js +121 -0
- package/lib/pipe/github.js +135 -63
- package/lib/pipe/gitlab.js +225 -0
- package/lib/pipe/index.js +29 -13
- package/lib/pipe/testomatio.js +35 -33
- package/lib/reporter.js +2 -0
- package/lib/util.js +34 -3
- package/lib/xmlReader.js +34 -18
- package/package.json +10 -4
- package/testcafe/index.js +0 -61
- package/testcafe/package-lock.json +0 -863
- package/testcafe/package.json +0 -14
package/lib/client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const debug = require('debug')('@testomatio/reporter:client');
|
|
2
2
|
const createCallsiteRecord = require('callsite-record');
|
|
3
3
|
const { sep, join } = require('path');
|
|
4
4
|
const fs = require('fs');
|
|
@@ -6,8 +6,8 @@ const chalk = require('chalk');
|
|
|
6
6
|
const upload = require('./fileUploader');
|
|
7
7
|
const { PASSED, FAILED, FINISHED, APP_PREFIX } = require('./constants');
|
|
8
8
|
const pipesFactory = require('./pipe');
|
|
9
|
-
const { TESTOMATIO_ENV } = process.env;
|
|
10
9
|
|
|
10
|
+
const { TESTOMATIO_ENV } = process.env;
|
|
11
11
|
|
|
12
12
|
class TestomatClient {
|
|
13
13
|
/**
|
|
@@ -15,17 +15,18 @@ class TestomatClient {
|
|
|
15
15
|
*
|
|
16
16
|
* @param {*} params
|
|
17
17
|
*/
|
|
18
|
-
constructor(params) {
|
|
19
|
-
this.apiKey = params.apiKey || process.env.TESTOMATIO;
|
|
18
|
+
constructor(params = {}) {
|
|
20
19
|
this.title = params.title || process.env.TESTOMATIO_TITLE;
|
|
21
|
-
this.
|
|
20
|
+
this.createNewTests = params.createNewTests ?? !!process.env.TESTOMATIO_CREATE;
|
|
21
|
+
this.proceed = process.env.TESTOMATIO_PROCEED;
|
|
22
|
+
this.env = TESTOMATIO_ENV;
|
|
22
23
|
this.parallel = params.parallel;
|
|
23
|
-
const store = {}
|
|
24
|
+
const store = {};
|
|
24
25
|
this.pipes = pipesFactory(params, store);
|
|
25
26
|
this.queue = Promise.resolve();
|
|
26
|
-
this.axios = axios.create();
|
|
27
27
|
this.totalUploaded = 0;
|
|
28
28
|
this.version = JSON.parse(fs.readFileSync(join(__dirname, '..', 'package.json')).toString()).version;
|
|
29
|
+
console.log(APP_PREFIX, `Testomatio Reporter v${this.version}`);
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -34,7 +35,9 @@ class TestomatClient {
|
|
|
34
35
|
* @returns {Promise} - resolves to Run id which should be used to update / add test
|
|
35
36
|
*/
|
|
36
37
|
createRun() {
|
|
37
|
-
|
|
38
|
+
// all pipes disabled, skipping
|
|
39
|
+
if (!this.pipes.filter(p => p.isEnabled).length) return;
|
|
40
|
+
|
|
38
41
|
const runParams = {
|
|
39
42
|
title: this.title,
|
|
40
43
|
parallel: this.parallel,
|
|
@@ -43,8 +46,10 @@ class TestomatClient {
|
|
|
43
46
|
|
|
44
47
|
global.testomatioArtifacts = [];
|
|
45
48
|
|
|
46
|
-
this.queue = this.queue
|
|
47
|
-
|
|
49
|
+
this.queue = this.queue
|
|
50
|
+
.then(() => Promise.all(this.pipes.map(p => p.createRun(runParams))))
|
|
51
|
+
.catch(err => console.log(APP_PREFIX, err));
|
|
52
|
+
debug('Run', this.queue);
|
|
48
53
|
return this.queue;
|
|
49
54
|
}
|
|
50
55
|
|
|
@@ -53,7 +58,10 @@ class TestomatClient {
|
|
|
53
58
|
*
|
|
54
59
|
* @returns {Promise}
|
|
55
60
|
*/
|
|
56
|
-
async addTestRun(testId, status, testData = {}) {
|
|
61
|
+
async addTestRun(testId, status, testData = {}, storeArtifacts = []) {
|
|
62
|
+
// all pipes disabled, skipping
|
|
63
|
+
if (!this.pipes.filter(p => p.isEnabled).length) return;
|
|
64
|
+
|
|
57
65
|
const {
|
|
58
66
|
error = '',
|
|
59
67
|
time = '',
|
|
@@ -61,6 +69,7 @@ class TestomatClient {
|
|
|
61
69
|
files = [],
|
|
62
70
|
filesBuffers = [],
|
|
63
71
|
steps,
|
|
72
|
+
code = null,
|
|
64
73
|
title,
|
|
65
74
|
suite_title,
|
|
66
75
|
suite_id,
|
|
@@ -82,7 +91,13 @@ class TestomatClient {
|
|
|
82
91
|
stack = this.formatSteps(stack, steps);
|
|
83
92
|
}
|
|
84
93
|
|
|
94
|
+
if (Array.isArray(storeArtifacts) && storeArtifacts.length) {
|
|
95
|
+
debug("CLIENT storeArtefact", storeArtifacts);
|
|
96
|
+
files.push(...storeArtifacts);
|
|
97
|
+
}
|
|
98
|
+
|
|
85
99
|
if (Array.isArray(global.testomatioArtifacts)) {
|
|
100
|
+
debug("CLIENT global[testomatioArtifacts]", global.testomatioArtifacts);
|
|
86
101
|
files.push(...global.testomatioArtifacts);
|
|
87
102
|
global.testomatioArtifacts = [];
|
|
88
103
|
}
|
|
@@ -96,7 +111,7 @@ class TestomatClient {
|
|
|
96
111
|
uploadedFiles.push(upload.uploadFileAsBuffer(buffer, fileName, this.runId));
|
|
97
112
|
}
|
|
98
113
|
|
|
99
|
-
const artifacts = await Promise.all(uploadedFiles)
|
|
114
|
+
const artifacts = await Promise.all(uploadedFiles);
|
|
100
115
|
|
|
101
116
|
global.testomatioArtifacts = [];
|
|
102
117
|
|
|
@@ -108,7 +123,8 @@ class TestomatClient {
|
|
|
108
123
|
status,
|
|
109
124
|
stack,
|
|
110
125
|
example,
|
|
111
|
-
|
|
126
|
+
code,
|
|
127
|
+
title,
|
|
112
128
|
suite_title,
|
|
113
129
|
suite_id,
|
|
114
130
|
test_id,
|
|
@@ -117,7 +133,9 @@ class TestomatClient {
|
|
|
117
133
|
artifacts,
|
|
118
134
|
};
|
|
119
135
|
|
|
120
|
-
this.queue = this.queue
|
|
136
|
+
this.queue = this.queue
|
|
137
|
+
.then(() => Promise.all(this.pipes.map(p => p.addTest(data))))
|
|
138
|
+
.catch(err => console.log(APP_PREFIX, err));
|
|
121
139
|
return this.queue;
|
|
122
140
|
}
|
|
123
141
|
|
|
@@ -127,23 +145,32 @@ class TestomatClient {
|
|
|
127
145
|
* @returns {Promise}
|
|
128
146
|
*/
|
|
129
147
|
updateRunStatus(status, isParallel) {
|
|
148
|
+
// all pipes disabled, skipping
|
|
149
|
+
if (!this.pipes.filter(p => p.isEnabled).length) return;
|
|
150
|
+
|
|
130
151
|
let statusEvent;
|
|
131
152
|
if (status === FINISHED) statusEvent = 'finish';
|
|
132
153
|
if (status === PASSED) statusEvent = 'pass';
|
|
133
154
|
if (status === FAILED) statusEvent = 'fail';
|
|
134
155
|
if (isParallel) statusEvent += '_parallel';
|
|
135
|
-
const runParams = { status, statusEvent }
|
|
156
|
+
const runParams = { status, statusEvent };
|
|
157
|
+
|
|
158
|
+
this.queue = this.queue
|
|
159
|
+
.then(() => Promise.all(this.pipes.map(p => p.finishRun(runParams))))
|
|
160
|
+
.then(() => {
|
|
161
|
+
debug("TOTAL uploaded files", this.totalUploaded);
|
|
162
|
+
|
|
163
|
+
if (upload.isArtifactsEnabled() && this.totalUploaded > 0) {
|
|
164
|
+
console.log(
|
|
165
|
+
APP_PREFIX,
|
|
166
|
+
`🗄️ Total ${this.totalUploaded} artifacts ${
|
|
167
|
+
process.env.TESTOMATIO_PRIVATE_ARTIFACTS ? 'privately' : chalk.bold('publicly')
|
|
168
|
+
} uploaded to S3 bucket `,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
.catch(err => console.log(APP_PREFIX, err));
|
|
136
173
|
|
|
137
|
-
this.queue = this.queue.then(() => Promise.all(this.pipes.map(p => p.finishRun(runParams))));
|
|
138
|
-
|
|
139
|
-
if (upload.isArtifactsEnabled && this.totalUploaded > 0) {
|
|
140
|
-
console.log(
|
|
141
|
-
APP_PREFIX,
|
|
142
|
-
`🗄️ Total ${this.totalUploaded} artifacts ${
|
|
143
|
-
process.env.TESTOMATIO_PRIVATE_ARTIFACTS ? 'privately' : chalk.bold('publicly')
|
|
144
|
-
} uploaded to S3 bucket `,
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
174
|
return this.queue;
|
|
148
175
|
}
|
|
149
176
|
|
package/lib/constants.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
|
|
3
3
|
const APP_PREFIX = chalk.gray('[TESTOMATIO]');
|
|
4
|
+
const TESTOMAT_ARTIFACT_SUFFIX = "testomatio_artifact_";
|
|
5
|
+
|
|
6
|
+
const CSV_HEADERS = [
|
|
7
|
+
{ id: 'suite_title', title: 'Suite_title' },
|
|
8
|
+
{ id: 'title', title: 'Title' },
|
|
9
|
+
{ id: 'status', title: 'Status' },
|
|
10
|
+
{ id: 'message', title: 'Message' },
|
|
11
|
+
{ id: 'stack', title: 'Stack' },
|
|
12
|
+
];
|
|
4
13
|
|
|
5
14
|
module.exports = Object.freeze({
|
|
6
15
|
PASSED: 'passed',
|
|
@@ -8,4 +17,6 @@ module.exports = Object.freeze({
|
|
|
8
17
|
SKIPPED: 'skipped',
|
|
9
18
|
FINISHED: 'finished',
|
|
10
19
|
APP_PREFIX,
|
|
20
|
+
CSV_HEADERS,
|
|
21
|
+
TESTOMAT_ARTIFACT_SUFFIX
|
|
11
22
|
});
|
package/lib/fileUploader.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
const
|
|
1
|
+
const debug = require('debug')('@testomatio/reporter:file-uploader');
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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,39 @@ 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 {
|
|
92
|
+
S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT, TESTOMATIO_PRIVATE_ARTIFACTS, S3_BUCKET
|
|
93
|
+
} = getConfig();
|
|
61
94
|
|
|
62
95
|
const file = fs.readFileSync(filePath);
|
|
63
96
|
|
|
64
97
|
Key = `${runId}/${randomUUID()}-${Key || path.basename(filePath)}`;
|
|
65
98
|
const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
|
|
66
99
|
|
|
100
|
+
const s3 = new S3(_getS3Config());
|
|
101
|
+
|
|
67
102
|
try {
|
|
68
|
-
const out =
|
|
69
|
-
|
|
103
|
+
const out = new Upload({
|
|
104
|
+
client: s3,
|
|
105
|
+
|
|
106
|
+
params: {
|
|
70
107
|
Bucket: S3_BUCKET,
|
|
71
108
|
Key,
|
|
72
109
|
Body: file,
|
|
73
110
|
ContentType,
|
|
74
111
|
ACL,
|
|
75
|
-
}
|
|
76
|
-
|
|
112
|
+
}
|
|
113
|
+
});
|
|
77
114
|
|
|
78
|
-
|
|
115
|
+
await out.done();
|
|
116
|
+
debug('Uploaded', out.singleUploadResult.Location)
|
|
117
|
+
|
|
118
|
+
return out.singleUploadResult.Location;
|
|
79
119
|
} catch (e) {
|
|
80
120
|
console.log(APP_PREFIX, chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`), {
|
|
81
121
|
accessKeyId: S3_ACCESS_KEY_ID,
|
|
@@ -100,35 +140,32 @@ const uploadUsingS3 = async (filePath, runId) => {
|
|
|
100
140
|
};
|
|
101
141
|
|
|
102
142
|
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
143
|
|
|
114
|
-
const
|
|
144
|
+
const {
|
|
145
|
+
S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT, TESTOMATIO_PRIVATE_ARTIFACTS, S3_BUCKET
|
|
146
|
+
} = getConfig();
|
|
115
147
|
|
|
116
148
|
const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
|
|
117
149
|
|
|
118
150
|
const fileExtension = _getFileExtBase64(buffer.toString('base64'));
|
|
119
151
|
const Key = `${runId}/${fileName}${fileExtension}`;
|
|
120
152
|
|
|
153
|
+
const s3 = new S3(_getS3Config());
|
|
154
|
+
|
|
121
155
|
try {
|
|
122
|
-
const out =
|
|
123
|
-
|
|
156
|
+
const out = new Upload({
|
|
157
|
+
client: s3,
|
|
158
|
+
|
|
159
|
+
params: {
|
|
124
160
|
Bucket: S3_BUCKET,
|
|
125
161
|
Key,
|
|
126
162
|
Body: buffer,
|
|
127
163
|
ACL,
|
|
128
|
-
}
|
|
129
|
-
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
await out.done();
|
|
130
167
|
|
|
131
|
-
return out.Location;
|
|
168
|
+
return out.singleUploadResult.Location;
|
|
132
169
|
} catch (e) {
|
|
133
170
|
console.log(APP_PREFIX, chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`), {
|
|
134
171
|
accessKeyId: S3_ACCESS_KEY_ID,
|
|
@@ -154,7 +191,7 @@ const uploadUsingS3AsBuffer = async (buffer, fileName, runId) => {
|
|
|
154
191
|
|
|
155
192
|
const uploadFileByPath = async (filePath, runId) => {
|
|
156
193
|
try {
|
|
157
|
-
if (isArtifactsEnabled) {
|
|
194
|
+
if (isArtifactsEnabled()) {
|
|
158
195
|
return uploadUsingS3(filePath, runId);
|
|
159
196
|
}
|
|
160
197
|
} catch (e) {
|
|
@@ -164,7 +201,7 @@ const uploadFileByPath = async (filePath, runId) => {
|
|
|
164
201
|
|
|
165
202
|
const uploadFileAsBuffer = async (buffer, fileName, runId) => {
|
|
166
203
|
try {
|
|
167
|
-
if (isArtifactsEnabled) {
|
|
204
|
+
if (isArtifactsEnabled()) {
|
|
168
205
|
return uploadUsingS3AsBuffer(buffer, fileName, runId);
|
|
169
206
|
}
|
|
170
207
|
} catch (e) {
|
|
@@ -175,5 +212,5 @@ const uploadFileAsBuffer = async (buffer, fileName, runId) => {
|
|
|
175
212
|
module.exports = {
|
|
176
213
|
uploadFileByPath: memoize(uploadFileByPath),
|
|
177
214
|
uploadFileAsBuffer: memoize(uploadFileAsBuffer),
|
|
178
|
-
isArtifactsEnabled,
|
|
215
|
+
isArtifactsEnabled: memoize(isArtifactsEnabled),
|
|
179
216
|
};
|
package/lib/pipe/csv.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const debug = require('debug')('@testomatio/reporter:pipe:csv');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const csvWriter = require('csv-writer');
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const merge = require('lodash.merge');
|
|
7
|
+
const { isSameTest, getCurrentDateTime } = require('../util');
|
|
8
|
+
const { CSV_HEADERS } = require('../constants');
|
|
9
|
+
|
|
10
|
+
class CsvPipe {
|
|
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
|
+
} else {
|
|
27
|
+
this.outputFile = path.resolve(
|
|
28
|
+
process.cwd(),
|
|
29
|
+
this.outputDir,
|
|
30
|
+
`${getCurrentDateTime()}_${this.csvFilename.split('.')[0]}.csv`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async createRun() {
|
|
37
|
+
// empty
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
updateRun() {}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create a folder that will contain the exported files
|
|
44
|
+
*/
|
|
45
|
+
checkExportDir() {
|
|
46
|
+
if (!fs.existsSync(this.outputDir)) {
|
|
47
|
+
return fs.mkdirSync(this.outputDir);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Save data to the csv file.
|
|
53
|
+
* @param {Object} data - data that will be added to the CSV file.
|
|
54
|
+
* Example: [{suite_title: "Suite #1", test: "Test-case-1", message: "Test msg"}]
|
|
55
|
+
* @param {Object} headers - csv file headers. Example: [{ id: 'suite_title', title: 'Suite_title' }]
|
|
56
|
+
*/
|
|
57
|
+
async saveToCsv(data, headers) {
|
|
58
|
+
debug('Data', data);
|
|
59
|
+
// First, we check whether the export directory exists: if yes - OK, no - create it.
|
|
60
|
+
this.checkExportDir();
|
|
61
|
+
|
|
62
|
+
console.log(chalk.yellow(`The test results will be added to the csv. It will take some time...`));
|
|
63
|
+
// Create csv writer object
|
|
64
|
+
const writer = csvWriter.createObjectCsvWriter({
|
|
65
|
+
path: this.outputFile,
|
|
66
|
+
header: headers,
|
|
67
|
+
});
|
|
68
|
+
// Save csv file based on the current data
|
|
69
|
+
try {
|
|
70
|
+
await writer.writeRecords(data);
|
|
71
|
+
console.log(chalk.green(`Recording completed! You can check the result in file = ${this.outputFile}`));
|
|
72
|
+
} catch (e) {
|
|
73
|
+
console.log('Unknown error: ', e);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Add test data to the result array for saving. As a result of this function, we get a result object to save.
|
|
79
|
+
* @param {Object} test - object which includes each test entry.
|
|
80
|
+
*/
|
|
81
|
+
addTest(test) {
|
|
82
|
+
if (!this.isEnabled) return;
|
|
83
|
+
|
|
84
|
+
const index = this.results.findIndex(t => isSameTest(t, test));
|
|
85
|
+
// update if they were already added
|
|
86
|
+
if (index >= 0) {
|
|
87
|
+
this.results[index] = merge(this.results[index], test);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const { suite_title, title, status, message, stack } = test;
|
|
92
|
+
|
|
93
|
+
this.results.push({
|
|
94
|
+
suite_title,
|
|
95
|
+
title,
|
|
96
|
+
status,
|
|
97
|
+
message,
|
|
98
|
+
stack,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Save short tests data to the csv file.
|
|
104
|
+
* @param {Object} runParams - run params.
|
|
105
|
+
*/
|
|
106
|
+
async finishRun(runParams) {
|
|
107
|
+
if (!this.isEnabled) return;
|
|
108
|
+
|
|
109
|
+
if (runParams.tests) runParams.tests.forEach(t => this.addTest(t));
|
|
110
|
+
// Save results based on the default headers
|
|
111
|
+
if (this.isCsvSave) {
|
|
112
|
+
this.saveToCsv(this.results, CSV_HEADERS);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
toString() {
|
|
117
|
+
return 'csv exporter';
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = CsvPipe;
|