@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 +12 -0
- package/README.md +29 -1
- package/lib/adapter/codecept.js +1 -1
- package/lib/adapter/mocha.js +19 -4
- package/lib/adapter/playwright.js +1 -1
- package/lib/bin/reportXml.js +6 -2
- package/lib/client.js +17 -10
- package/lib/fileUploader.js +82 -49
- package/lib/pipe/csv.js +100 -92
- package/lib/pipe/github.js +117 -63
- package/lib/pipe/gitlab.js +75 -38
- package/lib/pipe/index.js +20 -12
- package/lib/pipe/testomatio.js +7 -5
- package/lib/util.js +9 -9
- package/lib/xmlReader.js +26 -16
- package/package.json +3 -2
- package/testcafe/index.js +0 -61
- package/testcafe/package-lock.json +0 -863
- package/testcafe/package.json +0 -14
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
|
-
###
|
|
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
|
package/lib/adapter/codecept.js
CHANGED
|
@@ -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 = [];
|
package/lib/adapter/mocha.js
CHANGED
|
@@ -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
|
|
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 = [];
|
package/lib/bin/reportXml.js
CHANGED
|
@@ -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)
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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 ${
|
package/lib/fileUploader.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
const
|
|
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
|
-
|
|
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,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 =
|
|
69
|
-
|
|
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
|
-
|
|
110
|
+
}
|
|
111
|
+
});
|
|
77
112
|
|
|
78
|
-
|
|
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
|
|
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 =
|
|
123
|
-
|
|
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
|
-
|
|
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(
|
|
2
|
-
const fs = require(
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
this.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
35
|
+
async createRun() {
|
|
36
|
+
// empty
|
|
37
|
+
}
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
updateRun() {}
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
107
|
-
|
|
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;
|