@testomatio/reporter 1.2.0 β 1.2.1-beta.codecept-id
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/README.md +45 -51
- package/lib/adapter/codecept.js +1 -14
- package/lib/adapter/cucumber/legacy.js +1 -1
- package/lib/adapter/cucumber.js +2 -2
- package/lib/adapter/jest.js +1 -1
- package/lib/adapter/mocha.js +4 -6
- package/lib/adapter/playwright.js +1 -1
- package/lib/bin/reportXml.js +13 -13
- package/lib/bin/startTest.js +10 -11
- package/lib/constants.js +8 -5
- package/lib/fileUploader.js +29 -33
- package/lib/junit-adapter/adapter.js +0 -2
- package/lib/junit-adapter/csharp.js +3 -4
- package/lib/junit-adapter/index.js +2 -3
- package/lib/junit-adapter/java.js +11 -11
- package/lib/junit-adapter/javascript.js +1 -2
- package/lib/junit-adapter/python.js +12 -14
- package/lib/junit-adapter/ruby.js +1 -2
- package/lib/pipe/csv.js +2 -3
- package/lib/pipe/github.js +4 -3
- package/lib/pipe/gitlab.js +14 -7
- package/lib/pipe/html.js +0 -1
- package/lib/pipe/index.js +1 -1
- package/lib/template/testomatio.hbs +362 -724
- package/lib/utils/pipe_utils.js +70 -77
- package/lib/utils/utils.js +33 -32
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# Testomatio Reporter
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
π Hey, do you need some test reporting?
|
|
5
4
|
|
|
6
5
|
Testomat.io Reporter is a library that integrates with popular **JavaScript and TypeScript** test frameworks to provide a common interface for test reporting. By default, Testomat.io Reporter works with our reporting cloud service [Testomat.io App](https://testomat.io), however it is not locked to it. Reporter can be used as a standalone tool.
|
|
@@ -9,18 +8,17 @@ Testomat.io Reporter is a library that integrates with popular **JavaScript and
|
|
|
9
8
|
|
|
10
9
|
Testomat.io Reporter (this npm package) supports:
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
- π Integarion with all popular [JavaScript/TypeScript frameworks](./docs/frameworks.md)
|
|
12
|
+
- ποΈ Screenshots, videos, traces [uploaded into S3 bucket](./docs/artifacts.md)
|
|
13
|
+
- π [Stack traces](./docs/stacktrace.md) and error messages
|
|
14
|
+
- π [GitHub](./docs/pipes/github.md) & [GitLab](./docs/pipes/gitlab.md) integration
|
|
15
|
+
- π
Realtime reports
|
|
16
|
+
- ποΈ Other test frameworks supported via [JUNit XML](./docs/junit.md)
|
|
17
|
+
- πΆββοΈ Steps _(work in progress)_
|
|
18
|
+
- π [Logger](./docs/logger.md) _(work in progress, supports Jest for now)_
|
|
19
|
+
- βοΈ Custom properties and metadata _(work in progress)_
|
|
20
|
+
- π― Free & open-source.
|
|
21
|
+
- π Public and private Run reports on cloud via [Testomat.io App](https://testomat.io) π
|
|
24
22
|
|
|
25
23
|

|
|
26
24
|
|
|
@@ -29,12 +27,12 @@ Testomat.io Reporter (this npm package) supports:
|
|
|
29
27
|
Testomat.io Reporter provides common API to store and organize test reports.
|
|
30
28
|
It can receive test result data from any [test framework](./docs/frameworks.md) and send it to different services via [pipes](./docs/pipes.md).
|
|
31
29
|
|
|
32
|
-
| π Input
|
|
33
|
-
|
|
34
|
-
| Playwright
|
|
35
|
-
| Cypress
|
|
36
|
-
| Jest
|
|
37
|
-
| ...
|
|
30
|
+
| π Input | π Output |
|
|
31
|
+
| ---------- | -------------------------------------------- |
|
|
32
|
+
| Playwright | Report to GitHub |
|
|
33
|
+
| Cypress | Report to GitLab |
|
|
34
|
+
| Jest | Report to [Testomat.io](https://testomat.io) |
|
|
35
|
+
| ... | ... your custom report |
|
|
38
36
|
|
|
39
37
|
If you use multiple test frameworks and you need to use one customizable reporter, check Testomat.io Reporter, as you can adjust it once and attach it to all your projects.
|
|
40
38
|
|
|
@@ -46,7 +44,6 @@ Artifacts like screenshots, videos, traces, are **uploaded to your own cloud sto
|
|
|
46
44
|
|
|
47
45
|
To enable Testomat.io Reporter install `@testomatio/reporter` package
|
|
48
46
|
|
|
49
|
-
|
|
50
47
|
Use one of your favorite package managers:
|
|
51
48
|
|
|
52
49
|
```
|
|
@@ -65,24 +62,22 @@ yarn add @testomatio/reporter --dev
|
|
|
65
62
|
|
|
66
63
|
### 1οΈβ£ Attach Reporter to the Test Runner
|
|
67
64
|
|
|
68
|
-
|
|
|
69
|
-
|
|
70
|
-
| [Playwright](./docs/frameworks.md#playwright)
|
|
71
|
-
| [Jest](./docs/frameworks.md#Jest)
|
|
72
|
-
| [TestCafe](./docs/frameworks.md#TestCafe)
|
|
73
|
-
| [Newman (Postman)](./docs/frameworks.md#Newman) | [JUnit](./docs/junit.md#junit)
|
|
74
|
-
| [PyTest](./docs/junit.md#pytest)
|
|
75
|
-
|
|
65
|
+
| | | |
|
|
66
|
+
| ----------------------------------------------- | --------------------------------------------- | --------------------------------------------------------- |
|
|
67
|
+
| [Playwright](./docs/frameworks.md#playwright) | [CodeceptJS](./docs/frameworks.md#CodeceptJS) | [Cypress](./docs/frameworks.md#Cypress) |
|
|
68
|
+
| [Jest](./docs/frameworks.md#Jest) | [Mocha](./docs/frameworks.md#Mocha) | [WebDriverIO](./docs/frameworks.md#WebDriverIO) |
|
|
69
|
+
| [TestCafe](./docs/frameworks.md#TestCafe) | [Detox](./docs/frameworks.md#Detox) | [Codeception](https://github.com/testomatio/php-reporter) |
|
|
70
|
+
| [Newman (Postman)](./docs/frameworks.md#Newman) | [JUnit](./docs/junit.md#junit) | [NUnit](./docs/junit.md#nunit) |
|
|
71
|
+
| [PyTest](./docs/junit.md#pytest) | [PHPUnit](./docs/junit.md#phpunit) | [Protractor](./docs/frameworks.md#protractor) |
|
|
76
72
|
|
|
77
73
|
or **any [other via JUnit](./docs/junit.md)** report....
|
|
78
74
|
|
|
79
75
|
### 2οΈβ£ Configure Reports
|
|
80
76
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
77
|
+
- [Create report on Testomat.io](./docs/pipes/testomatio.md).
|
|
78
|
+
- [Create brief summary report for GitHub Pull Request](./docs/pipes/github.md) π
|
|
79
|
+
- [Create brief summary report for GitLab Merge Request](./docs/pipes/gitlab.md).
|
|
80
|
+
- [Configure other pipes](./docs/pipes/md) for other ways to process test results output.
|
|
86
81
|
|
|
87
82
|

|
|
88
83
|
|
|
@@ -90,7 +85,7 @@ GitHub report published as a comment to Pull Request:
|
|
|
90
85
|
|
|
91
86
|
### 3οΈβ£ Enable Artifacts Storage
|
|
92
87
|
|
|
93
|
-
1. Create bucket on AWS, Google Cloud, or any other cloud storage provider supporting S3 protocol.
|
|
88
|
+
1. Create bucket on AWS, Google Cloud, or any other cloud storage provider supporting S3 protocol.
|
|
94
89
|
2. [Pass S3 credentials](./docs/artifacts.md) to reporter to enable artifacts uploading.
|
|
95
90
|
|
|
96
91
|
### 4οΈβ£ Use Logger
|
|
@@ -104,8 +99,9 @@ Testomatio now features a custom reporting tool that allows you to generate a st
|
|
|
104
99
|
With our reporter, you can:
|
|
105
100
|
|
|
106
101
|
- Easily analyze the results of your test runs in a convenient HTML format.
|
|
107
|
-
|
|
108
|
-
|
|
102
|
+
|
|
103
|
+
* Visualize data on successful and failed tests, including statistics and error details.
|
|
104
|
+
* Quickly share reports with your team members or stakeholders.
|
|
109
105
|
|
|
110
106
|

|
|
111
107
|
|
|
@@ -123,25 +119,23 @@ After you tested reporter locally add it to your CI pipeline.
|
|
|
123
119
|
|
|
124
120
|
Bring this reporter on CI and never lose test results again!
|
|
125
121
|
|
|
126
|
-
|
|
127
122
|
## Documentation
|
|
128
123
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
124
|
+
- π οΈ [Frameworks](./docs/frameworks.md)
|
|
125
|
+
- β² [Pipes](./docs/pipes.md)
|
|
126
|
+
- [Testomat.io](./docs/pipes/testomatio.md)
|
|
127
|
+
- [GitHub](./docs/pipes/github.md)
|
|
128
|
+
- [Gitlab](./docs/pipes/gitlab.md)
|
|
129
|
+
- [CSV](./docs/pipes/csv.md)
|
|
130
|
+
- [HTML report](./docs/pipes/html.md)
|
|
131
|
+
- π [JUnit](./docs/junit.md)
|
|
132
|
+
- ποΈ [Artifacts](./docs/artifacts.md)
|
|
133
|
+
- π [Workflows](./docs/workflows.md)
|
|
134
|
+
- ποΈ [Logger](./docs/logger.md)
|
|
140
135
|
|
|
141
136
|
## Development
|
|
142
137
|
|
|
143
|
-
|
|
144
|
-
### REST API
|
|
138
|
+
### REST API
|
|
145
139
|
|
|
146
140
|
Testomat.io App uses REST API to collect data from the reporter.
|
|
147
141
|
|
|
@@ -156,9 +150,9 @@ To print all reporter logs:
|
|
|
156
150
|
```
|
|
157
151
|
DEBUG=@testomatio/reporter:*
|
|
158
152
|
```
|
|
153
|
+
|
|
159
154
|
To print all reporter logs of a specific pipe:
|
|
160
155
|
|
|
161
156
|
```
|
|
162
157
|
DEBUG=@testomatio/reporter:pipe:github
|
|
163
158
|
```
|
|
164
|
-
|
package/lib/adapter/codecept.js
CHANGED
|
@@ -3,7 +3,7 @@ const chalk = require('chalk');
|
|
|
3
3
|
const TestomatClient = require('../client');
|
|
4
4
|
const { STATUS, APP_PREFIX, TESTOMAT_TMP_STORAGE_DIR } = require('../constants');
|
|
5
5
|
const upload = require('../fileUploader');
|
|
6
|
-
const { parseTest
|
|
6
|
+
const { parseTest, fileSystem } = require('../utils/utils');
|
|
7
7
|
const { services } = require('../services');
|
|
8
8
|
|
|
9
9
|
if (!global.codeceptjs) {
|
|
@@ -120,7 +120,6 @@ function CodeceptReporter(config) {
|
|
|
120
120
|
services.setContext(test.fullTitle());
|
|
121
121
|
|
|
122
122
|
testTimeMap[test.id] = Date.now();
|
|
123
|
-
if (global.testomatioDataStore) global.testomatioDataStore.currentlyRunningTestId = getIdFromTestTitle(test.title);
|
|
124
123
|
// start logging
|
|
125
124
|
});
|
|
126
125
|
|
|
@@ -327,18 +326,6 @@ async function uploadAttachments(client, attachments, messagePrefix, attachmentT
|
|
|
327
326
|
}
|
|
328
327
|
}
|
|
329
328
|
|
|
330
|
-
function parseTest(tags) {
|
|
331
|
-
if (tags) {
|
|
332
|
-
for (const tag of tags) {
|
|
333
|
-
if (tag.startsWith('@T')) {
|
|
334
|
-
return tag.substring(2, tag.length);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return null;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
329
|
function getTestAndMessage(title) {
|
|
343
330
|
const testObj = { message: '' };
|
|
344
331
|
const testArr = title.split(/\s(\|\s\{.*?\})/);
|
|
@@ -111,7 +111,7 @@ const createTestomatFormatter = apiKey => {
|
|
|
111
111
|
onTestCaseStarted(event) {
|
|
112
112
|
const scenario = getScenario(event.sourceLocation);
|
|
113
113
|
const testId = getTestId(scenario);
|
|
114
|
-
|
|
114
|
+
|
|
115
115
|
if (!global.testomatioDataStore) global.testomatioDataStore = {};
|
|
116
116
|
global.testomatioDataStore.currentlyRunningTestId = testId;
|
|
117
117
|
}
|
package/lib/adapter/cucumber.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
try {
|
|
2
2
|
// eslint-disable-next-line import/no-unresolved
|
|
3
|
-
require.resolve(
|
|
3
|
+
require.resolve('@cucumber/cucumber');
|
|
4
4
|
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
|
|
5
5
|
module.exports = require('./cucumber/current');
|
|
6
6
|
} catch (_e) {
|
|
@@ -11,6 +11,6 @@ try {
|
|
|
11
11
|
module.exports = require('./cucumber/legacy');
|
|
12
12
|
} catch (_err) {
|
|
13
13
|
console.error('Cucumber packages: "@cucumber/cucumber" or "cucumber" were not detected. Report won\'t be sent');
|
|
14
|
-
module.exports = {}
|
|
14
|
+
module.exports = {};
|
|
15
15
|
}
|
|
16
16
|
}
|
package/lib/adapter/jest.js
CHANGED
|
@@ -48,7 +48,7 @@ class JestReporter {
|
|
|
48
48
|
steps = failureMessages[0];
|
|
49
49
|
}
|
|
50
50
|
const testId = parseTest(title);
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
// suite titles from most outer to most inner, separated by space
|
|
53
53
|
let fullSuiteTitle = testResult.ancestorTitles?.join(' ');
|
|
54
54
|
// if no suite titles, use file name
|
package/lib/adapter/mocha.js
CHANGED
|
@@ -54,7 +54,7 @@ function MochaReporter(runner, opts) {
|
|
|
54
54
|
|
|
55
55
|
runner.on(EVENT_TEST_PASS, async test => {
|
|
56
56
|
passes += 1;
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
console.log(chalk.bold.green('β'), test.fullTitle());
|
|
59
59
|
const testId = parseTest(test.title);
|
|
60
60
|
|
|
@@ -116,7 +116,6 @@ function MochaReporter(runner, opts) {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
function getTestLogs(test) {
|
|
119
|
-
|
|
120
119
|
const suiteLogsArr = services.logger.getLogs(test.parent.fullTitle());
|
|
121
120
|
const suiteLogs = suiteLogsArr ? suiteLogsArr.join('\n').trim() : '';
|
|
122
121
|
const testLogsArr = services.logger.getLogs(test.fullTitle());
|
|
@@ -138,11 +137,10 @@ Mocha.utils.inherits(MochaReporter, Mocha.reporters.Spec);
|
|
|
138
137
|
module.exports = MochaReporter;
|
|
139
138
|
|
|
140
139
|
function getSuiteTitle(test, pathArr = []) {
|
|
141
|
-
|
|
142
|
-
if (test.parent.parent) getSuiteTitle(test.parent, pathArr);
|
|
140
|
+
if (test.parent.parent) getSuiteTitle(test.parent, pathArr);
|
|
143
141
|
|
|
144
142
|
pathArr.push(test.parent.title);
|
|
145
|
-
|
|
143
|
+
|
|
146
144
|
return pathArr.filter(t => !!t)[0];
|
|
147
145
|
}
|
|
148
146
|
|
|
@@ -153,4 +151,4 @@ function getFile(test) {
|
|
|
153
151
|
function getTestName(test) {
|
|
154
152
|
if (process.env.TESTOMATIO_CREATE === 'fulltitle') return test.fullTitle();
|
|
155
153
|
return test.title;
|
|
156
|
-
}
|
|
154
|
+
}
|
package/lib/bin/reportXml.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const program = require(
|
|
3
|
-
const chalk = require(
|
|
2
|
+
const program = require('commander');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
4
|
const glob = require('glob');
|
|
5
5
|
const debug = require('debug')('@testomatio/reporter:xml-cli');
|
|
6
6
|
const { APP_PREFIX } = require('../constants');
|
|
7
|
-
const XmlReader = require(
|
|
7
|
+
const XmlReader = require('../xmlReader');
|
|
8
8
|
|
|
9
9
|
const { version } = require('../../package.json');
|
|
10
10
|
|
|
11
11
|
console.log(chalk.cyan.bold(` π€© Testomat.io XML Reporter v${version}`));
|
|
12
12
|
|
|
13
13
|
program
|
|
14
|
-
.arguments(
|
|
15
|
-
.option(
|
|
16
|
-
.option(
|
|
17
|
-
.option(
|
|
18
|
-
.option(
|
|
19
|
-
.option(
|
|
14
|
+
.arguments('<pattern>')
|
|
15
|
+
.option('-d, --dir <dir>', 'Project directory')
|
|
16
|
+
.option('--java-tests [java-path]', 'Load Java tests from path, by default: src/test/java')
|
|
17
|
+
.option('--lang <lang>', 'Language used (python, ruby, java)')
|
|
18
|
+
.option('--timelimit <time>', 'default time limit in seconds to kill a stuck process')
|
|
19
|
+
.option('--env-file <envfile>', 'Load environment variables from env file')
|
|
20
20
|
.action(async (pattern, opts) => {
|
|
21
21
|
if (!pattern.endsWith('.xml')) {
|
|
22
22
|
pattern += '.xml';
|
|
@@ -24,7 +24,7 @@ program
|
|
|
24
24
|
let { javaTests, lang } = opts;
|
|
25
25
|
if (opts.envFile) {
|
|
26
26
|
console.log(APP_PREFIX, 'Loading env file:', opts.envFile);
|
|
27
|
-
debug('Loading env file: %s', opts.envFile)
|
|
27
|
+
debug('Loading env file: %s', opts.envFile);
|
|
28
28
|
require('dotenv').config({ path: opts.envFile }); // eslint-disable-line
|
|
29
29
|
}
|
|
30
30
|
if (javaTests === true) javaTests = 'src/test/java';
|
|
@@ -38,7 +38,7 @@ program
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
for (const file of files) {
|
|
41
|
-
console.log(APP_PREFIX
|
|
41
|
+
console.log(APP_PREFIX, `Parsed ${file}`);
|
|
42
42
|
runReader.parse(file);
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -47,7 +47,7 @@ program
|
|
|
47
47
|
timeoutTimer = setTimeout(() => {
|
|
48
48
|
console.log(`β οΈ Reached timeout of ${opts.timelimit}s. Exiting... (Exit code is 0 to not fail the pipeline)`);
|
|
49
49
|
process.exit(0);
|
|
50
|
-
}, parseInt(opts.timelimit, 10) * 1000)
|
|
50
|
+
}, parseInt(opts.timelimit, 10) * 1000);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
try {
|
|
@@ -57,7 +57,7 @@ program
|
|
|
57
57
|
console.log(APP_PREFIX, 'Error updating status, skipping...', err);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
if (timeoutTimer) clearTimeout(timeoutTimer)
|
|
60
|
+
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
if (process.argv.length < 3) {
|
package/lib/bin/startTest.js
CHANGED
|
@@ -13,9 +13,9 @@ program
|
|
|
13
13
|
.option('-c, --command <cmd>', 'Test runner command')
|
|
14
14
|
.option('--launch', 'Start a new run and return its ID')
|
|
15
15
|
.option('--finish', 'Finish Run by its ID')
|
|
16
|
-
.option(
|
|
17
|
-
.option(
|
|
18
|
-
.action(async
|
|
16
|
+
.option('--env-file <envfile>', 'Load environment variables from env file')
|
|
17
|
+
.option('--filter <filter>', 'Additional execution filter')
|
|
18
|
+
.action(async opts => {
|
|
19
19
|
const { launch, finish, filter } = opts;
|
|
20
20
|
let { command } = opts;
|
|
21
21
|
|
|
@@ -62,21 +62,20 @@ program
|
|
|
62
62
|
|
|
63
63
|
const client = new TestomatClient({ apiKey, title, parallel: true });
|
|
64
64
|
|
|
65
|
-
if(filter) {
|
|
66
|
-
const [pipe, ...optsArray] = filter.split(
|
|
67
|
-
const pipeOptions = optsArray.join(
|
|
65
|
+
if (filter) {
|
|
66
|
+
const [pipe, ...optsArray] = filter.split(':');
|
|
67
|
+
const pipeOptions = optsArray.join(':');
|
|
68
68
|
|
|
69
|
-
try {
|
|
70
|
-
const tests = await client.prepareRun({pipe, pipeOptions});
|
|
69
|
+
try {
|
|
70
|
+
const tests = await client.prepareRun({ pipe, pipeOptions });
|
|
71
71
|
|
|
72
|
-
if(!tests || tests.length === 0) {
|
|
72
|
+
if (!tests || tests.length === 0) {
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
const grep = ` --grep (${tests.join('|')})`;
|
|
77
77
|
command += grep;
|
|
78
|
-
}
|
|
79
|
-
catch(err) {
|
|
78
|
+
} catch (err) {
|
|
80
79
|
console.log(APP_PREFIX, err);
|
|
81
80
|
}
|
|
82
81
|
}
|
package/lib/constants.js
CHANGED
|
@@ -24,11 +24,13 @@ const STATUS = {
|
|
|
24
24
|
};
|
|
25
25
|
// html pipe var
|
|
26
26
|
const HTML_REPORT = {
|
|
27
|
-
FOLDER:
|
|
28
|
-
REPORT_DEFAULT_NAME:
|
|
29
|
-
TEMPLATE_NAME: 'testomatio.hbs'
|
|
27
|
+
FOLDER: 'html-report',
|
|
28
|
+
REPORT_DEFAULT_NAME: 'testomatio-report.html',
|
|
29
|
+
TEMPLATE_NAME: 'testomatio.hbs',
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
+
const testomatLogoURL = 'https://avatars.githubusercontent.com/u/59105116?s=36&v=4';
|
|
33
|
+
|
|
32
34
|
module.exports = {
|
|
33
35
|
APP_PREFIX,
|
|
34
36
|
TESTOMAT_TMP_STORAGE_DIR,
|
|
@@ -36,5 +38,6 @@ module.exports = {
|
|
|
36
38
|
STATUS,
|
|
37
39
|
HTML_REPORT,
|
|
38
40
|
AXIOS_TIMEOUT,
|
|
39
|
-
AXIOS_RETRY_TIMEOUT
|
|
40
|
-
|
|
41
|
+
AXIOS_RETRY_TIMEOUT,
|
|
42
|
+
testomatLogoURL,
|
|
43
|
+
};
|
package/lib/fileUploader.js
CHANGED
|
@@ -42,8 +42,12 @@ function getConfig() {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
function getMaskedConfig() {
|
|
45
|
-
return Object.fromEntries(
|
|
46
|
-
.map(([key, value]) => [
|
|
45
|
+
return Object.fromEntries(
|
|
46
|
+
Object.entries(getConfig()).map(([key, value]) => [
|
|
47
|
+
key,
|
|
48
|
+
key === 'S3_SECRET_ACCESS_KEY' || key === 'S3_ACCESS_KEY_ID' ? '***' : value,
|
|
49
|
+
]),
|
|
50
|
+
);
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
let isEnabled;
|
|
@@ -78,7 +82,7 @@ const _getS3Config = () => {
|
|
|
78
82
|
accessKeyId: S3_ACCESS_KEY_ID,
|
|
79
83
|
secretAccessKey: S3_SECRET_ACCESS_KEY,
|
|
80
84
|
s3ForcePathStyle: S3_FORCE_PATH_STYLE,
|
|
81
|
-
}
|
|
85
|
+
},
|
|
82
86
|
};
|
|
83
87
|
|
|
84
88
|
if (S3_ENDPOINT) {
|
|
@@ -86,7 +90,7 @@ const _getS3Config = () => {
|
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
return cfg;
|
|
89
|
-
}
|
|
93
|
+
};
|
|
90
94
|
|
|
91
95
|
const uploadUsingS3 = async (filePath, runId) => {
|
|
92
96
|
let ContentType;
|
|
@@ -98,10 +102,7 @@ const uploadUsingS3 = async (filePath, runId) => {
|
|
|
98
102
|
Key = filePath.name;
|
|
99
103
|
}
|
|
100
104
|
|
|
101
|
-
const {
|
|
102
|
-
TESTOMATIO_PRIVATE_ARTIFACTS,
|
|
103
|
-
S3_BUCKET
|
|
104
|
-
} = getConfig();
|
|
105
|
+
const { TESTOMATIO_PRIVATE_ARTIFACTS, S3_BUCKET } = getConfig();
|
|
105
106
|
|
|
106
107
|
try {
|
|
107
108
|
debug('S3 config', getMaskedConfig());
|
|
@@ -116,7 +117,7 @@ const uploadUsingS3 = async (filePath, runId) => {
|
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
debug('File: ', filePath, ' exists');
|
|
119
|
-
|
|
120
|
+
|
|
120
121
|
const fileData = await readFile(filePath);
|
|
121
122
|
|
|
122
123
|
Key = `${runId}/${randomUUID()}-${Key || path.basename(filePath)}`;
|
|
@@ -126,7 +127,9 @@ const uploadUsingS3 = async (filePath, runId) => {
|
|
|
126
127
|
if (!S3_BUCKET || !fileData) {
|
|
127
128
|
console.log(
|
|
128
129
|
APP_PREFIX,
|
|
129
|
-
chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`),
|
|
130
|
+
chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`),
|
|
131
|
+
getMaskedConfig(),
|
|
132
|
+
);
|
|
130
133
|
return;
|
|
131
134
|
}
|
|
132
135
|
|
|
@@ -139,41 +142,37 @@ const uploadUsingS3 = async (filePath, runId) => {
|
|
|
139
142
|
ContentType,
|
|
140
143
|
ACL,
|
|
141
144
|
};
|
|
142
|
-
|
|
145
|
+
|
|
143
146
|
const out = new Upload({
|
|
144
147
|
client: s3,
|
|
145
|
-
params
|
|
148
|
+
params,
|
|
146
149
|
});
|
|
147
150
|
|
|
148
|
-
|
|
149
151
|
const link = await getS3LocationLink(out);
|
|
150
|
-
|
|
152
|
+
|
|
151
153
|
debug(`Succesfully uploaded ${filePath} => ${S3_BUCKET}/${Key} | URL: ${link}`);
|
|
152
154
|
|
|
153
155
|
return link;
|
|
154
|
-
}
|
|
155
|
-
catch (e) {
|
|
156
|
+
} catch (e) {
|
|
156
157
|
debug('S3 file uploading error: ', e);
|
|
157
|
-
|
|
158
|
+
|
|
158
159
|
console.log(APP_PREFIX, `To ${chalk.bold('disable')} artifact uploads set: TESTOMATIO_DISABLE_ARTIFACTS=1`);
|
|
159
160
|
|
|
160
161
|
if (!TESTOMATIO_PRIVATE_ARTIFACTS) {
|
|
161
162
|
console.log(APP_PREFIX, `To enable ${chalk.bold('PRIVATE')} uploads set: TESTOMATIO_PRIVATE_ARTIFACTS=1`);
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
163
|
+
} else {
|
|
164
164
|
console.log(
|
|
165
165
|
APP_PREFIX,
|
|
166
166
|
`To enable ${chalk.bold('PUBLIC')} uploads remove TESTOMATIO_PRIVATE_ARTIFACTS env variable`,
|
|
167
167
|
);
|
|
168
168
|
}
|
|
169
169
|
console.log(APP_PREFIX, '---------------');
|
|
170
|
-
}
|
|
170
|
+
}
|
|
171
171
|
};
|
|
172
172
|
|
|
173
173
|
const uploadUsingS3AsBuffer = async (buffer, fileName, runId) => {
|
|
174
|
-
const {
|
|
175
|
-
|
|
176
|
-
} = getConfig();
|
|
174
|
+
const { S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT, TESTOMATIO_PRIVATE_ARTIFACTS, S3_BUCKET } =
|
|
175
|
+
getConfig();
|
|
177
176
|
|
|
178
177
|
const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
|
|
179
178
|
|
|
@@ -203,12 +202,11 @@ const uploadUsingS3AsBuffer = async (buffer, fileName, runId) => {
|
|
|
203
202
|
Key,
|
|
204
203
|
Body: buffer,
|
|
205
204
|
ACL,
|
|
206
|
-
}
|
|
205
|
+
},
|
|
207
206
|
});
|
|
208
207
|
|
|
209
208
|
return await getS3LocationLink(out);
|
|
210
|
-
}
|
|
211
|
-
catch (e) {
|
|
209
|
+
} catch (e) {
|
|
212
210
|
debug('S3 buffer uploading error: ', e);
|
|
213
211
|
|
|
214
212
|
console.log(APP_PREFIX, `To ${chalk.bold('disable')} artifact uploads set: TESTOMATIO_DISABLE_ARTIFACTS=1`);
|
|
@@ -261,24 +259,22 @@ const checkFileExists = async (filePath, attempts = 5, intervalMs = 500) => {
|
|
|
261
259
|
|
|
262
260
|
try {
|
|
263
261
|
await promiseRetry(
|
|
264
|
-
{
|
|
262
|
+
{
|
|
265
263
|
retries: attempts,
|
|
266
|
-
minTimeout: intervalMs
|
|
264
|
+
minTimeout: intervalMs,
|
|
267
265
|
},
|
|
268
|
-
checkFile
|
|
266
|
+
checkFile,
|
|
269
267
|
);
|
|
270
268
|
|
|
271
269
|
return true;
|
|
272
270
|
} catch (err) {
|
|
273
|
-
console.error(
|
|
274
|
-
chalk.yellow(`File ${filePath} was not found or did not have time to be generated...`)
|
|
275
|
-
);
|
|
271
|
+
console.error(chalk.yellow(`File ${filePath} was not found or did not have time to be generated...`));
|
|
276
272
|
|
|
277
273
|
return false;
|
|
278
274
|
}
|
|
279
275
|
};
|
|
280
276
|
|
|
281
|
-
const getS3LocationLink = async
|
|
277
|
+
const getS3LocationLink = async out => {
|
|
282
278
|
const response = await out.done();
|
|
283
279
|
|
|
284
280
|
let s3Location = response?.Location;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
const Adapter = require('./adapter');
|
|
2
2
|
|
|
3
3
|
class CSharpAdapter extends Adapter {
|
|
4
|
-
|
|
5
4
|
formatTest(t) {
|
|
6
5
|
const title = t.title.replace(/\(.*?\)/, '').trim();
|
|
7
6
|
const example = t.title.match(/\((.*?)\)/);
|
|
8
|
-
if (example) t.example = { ...example[1].split(',')};
|
|
9
|
-
const suite = t.suite_title.split('.')
|
|
7
|
+
if (example) t.example = { ...example[1].split(',') };
|
|
8
|
+
const suite = t.suite_title.split('.');
|
|
10
9
|
t.suite_title = suite.pop();
|
|
11
10
|
t.file = suite.join('/');
|
|
12
11
|
t.title = title.trim();
|
|
@@ -14,4 +13,4 @@ class CSharpAdapter extends Adapter {
|
|
|
14
13
|
}
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
module.exports = CSharpAdapter;
|
|
16
|
+
module.exports = CSharpAdapter;
|
|
@@ -6,7 +6,6 @@ const RubyAdapter = require('./ruby');
|
|
|
6
6
|
const CSharpAdapter = require('./csharp');
|
|
7
7
|
|
|
8
8
|
function AdapterFactory(lang, opts) {
|
|
9
|
-
|
|
10
9
|
if (lang === 'java') {
|
|
11
10
|
return new JavaAdapter(opts);
|
|
12
11
|
}
|
|
@@ -22,8 +21,8 @@ function AdapterFactory(lang, opts) {
|
|
|
22
21
|
if (lang === 'c#' || lang === 'csharp') {
|
|
23
22
|
return new CSharpAdapter(opts);
|
|
24
23
|
}
|
|
25
|
-
|
|
24
|
+
|
|
26
25
|
return new Adapter(opts);
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
module.exports = AdapterFactory;
|
|
28
|
+
module.exports = AdapterFactory;
|