@testomatio/reporter 0.8.0-beta.9 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -7
- package/lib/ArtifactStorage.js +131 -0
- package/lib/adapter/codecept.js +25 -24
- package/lib/adapter/cucumber/current.js +16 -12
- package/lib/adapter/cucumber/legacy.js +14 -10
- package/lib/adapter/cypress-plugin/index.js +7 -7
- package/lib/adapter/jasmine.js +5 -4
- package/lib/adapter/jest.js +7 -11
- package/lib/adapter/mocha.js +69 -18
- package/lib/adapter/playwright.js +8 -5
- package/lib/adapter/webdriver.js +2 -1
- package/lib/bin/reportXml.js +5 -2
- package/lib/bin/startTest.js +2 -2
- package/lib/client.js +73 -49
- package/lib/constants.js +17 -2
- package/lib/fileUploader.js +86 -49
- package/lib/junit-adapter/csharp.js +0 -1
- package/lib/junit-adapter/index.js +3 -2
- package/lib/pipe/csv.js +133 -0
- package/lib/pipe/github.js +137 -73
- package/lib/pipe/gitlab.js +229 -0
- package/lib/pipe/index.js +27 -12
- package/lib/pipe/testomatio.js +71 -44
- package/lib/reporter.js +2 -0
- package/lib/util.js +46 -13
- package/lib/xmlReader.js +47 -31
- package/package.json +12 -3
- package/testcafe/index.js +0 -61
- package/testcafe/package.json +0 -14
package/README.md
CHANGED
|
@@ -20,11 +20,24 @@ 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
|
|
26
39
|
|
|
27
|
-
Make sure you load all your tests using [check-
|
|
40
|
+
Make sure you load all your tests using [check-tests](https://github.com/testomatio/check-tests#cli).
|
|
28
41
|
|
|
29
42
|
Add plugin to [codecept conf](https://github.com/testomatio/reporter/blob/master/example/codecept/codecept.conf.js#L23):
|
|
30
43
|
|
|
@@ -81,7 +94,7 @@ TESTOMATIO={API_KEY} npx playwright test
|
|
|
81
94
|
|
|
82
95
|
### Mocha
|
|
83
96
|
|
|
84
|
-
Load the test using using `check-
|
|
97
|
+
Load the test using using `check-tests` if not done already. Get the test id from testomat account and add it to your mocha test like in this [example](https://github.com/testomatio/reporter/blob/master/example/mocha/test/index.test.js#L4).
|
|
85
98
|
|
|
86
99
|
Run the following command from you project folder:
|
|
87
100
|
|
|
@@ -91,7 +104,7 @@ mocha --reporter ./node_modules/testomat-reporter/lib/adapter/mocha.js --reporte
|
|
|
91
104
|
|
|
92
105
|
### Jest
|
|
93
106
|
|
|
94
|
-
Load the test using using `check-
|
|
107
|
+
Load the test using using `check-tests`. Add the test id to your tests like in this [example](https://github.com/testomatio/reporter/blob/master/example/jest/index.test.js#L1).
|
|
95
108
|
|
|
96
109
|
Add the following line to [jest.config.js](https://github.com/testomatio/reporter/blob/master/example/jest/jest.config.js#L100):
|
|
97
110
|
|
|
@@ -113,7 +126,7 @@ TESTOMATIO={API_KEY} ./node_modules/.bin/cucumber-js --format ./node_modules/@te
|
|
|
113
126
|
|
|
114
127
|
### TestCafe
|
|
115
128
|
|
|
116
|
-
Load the test using using `check-
|
|
129
|
+
Load the test using using `check-tests`.
|
|
117
130
|
|
|
118
131
|
Run the following command from you project folder:
|
|
119
132
|
|
|
@@ -121,9 +134,20 @@ 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
|
+
```bash
|
|
142
|
+
TESTOMATIO={API_KEY} npx newman run {collection_name.json} -r testomatio
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
> _`check-tests` not supported for newman for now, tests will be created on testomatio by default_
|
|
146
|
+
|
|
147
|
+
|
|
124
148
|
### Cypress
|
|
125
149
|
|
|
126
|
-
Load the test using using `check-
|
|
150
|
+
Load the test using using `check-tests`.
|
|
127
151
|
|
|
128
152
|
Register our `cypress-plugin` in `cypress/plugins/index.js`:
|
|
129
153
|
|
|
@@ -151,7 +175,7 @@ TESTOMATIO={API_KEY} npx cypress run
|
|
|
151
175
|
|
|
152
176
|
### Protractor
|
|
153
177
|
|
|
154
|
-
Load the test using using `check-
|
|
178
|
+
Load the test using using `check-tests`.
|
|
155
179
|
|
|
156
180
|
Add the following lines to [conf.js](https://github.com/angular/protractor/blob/5.4.1/example/conf.js):
|
|
157
181
|
|
|
@@ -173,7 +197,7 @@ TESTOMATIO={API_KEY} npx start-test-run -c 'npx protractor conf.js'
|
|
|
173
197
|
|
|
174
198
|
### WebdriverIO
|
|
175
199
|
|
|
176
|
-
Load the test using using `check-
|
|
200
|
+
Load the test using using `check-tests`.
|
|
177
201
|
|
|
178
202
|
Add the following lines to [wdio.conf.js](https://webdriver.io/docs/configurationfile/):
|
|
179
203
|
|
|
@@ -208,6 +232,30 @@ Run the following command from you project folder:
|
|
|
208
232
|
TESTOMATIO={API_KEY} npx start-test-run -c 'npx wdio wdio.conf.js'
|
|
209
233
|
```
|
|
210
234
|
|
|
235
|
+
## Pipes
|
|
236
|
+
Pipes allow you to get report inside different systems (e.g. Pull request comment, database etc)
|
|
237
|
+
For now next pipes available:
|
|
238
|
+
|
|
239
|
+
### GitHub
|
|
240
|
+
This pipe adds comment with run report to GitHub Pull Request.
|
|
241
|
+
|
|
242
|
+
To use it:
|
|
243
|
+
1. run your tests using github actions in Pull Request
|
|
244
|
+
2. pass `GH_PAT` (GitHub Personal Access Token) as environment variable.
|
|
245
|
+
|
|
246
|
+
> Last report (comment) will be replaced with the new one.
|
|
247
|
+
To leave previous report pass `GITHUB_KEEP_OUTDATED_REPORTS=1` env variable.
|
|
248
|
+
|
|
249
|
+
### GitLab
|
|
250
|
+
This pipe adds comment with run report to GitLab Merge Request.
|
|
251
|
+
|
|
252
|
+
To use it:
|
|
253
|
+
1. run your tests in Merge Request (pipeline trigger should be `merge_request`)
|
|
254
|
+
2. pass `GITLAB_PAT` (GitLab Personal Access Token) as environment variable.
|
|
255
|
+
|
|
256
|
+
> Last report (comment) will be replaced with the new one.
|
|
257
|
+
To leave previous report pass `GITLAB_KEEP_OUTDATED_REPORTS=1` env variable.
|
|
258
|
+
|
|
211
259
|
## JUnit Reports
|
|
212
260
|
|
|
213
261
|
> **Notice** JUnit reports are supported since 0.6.0
|
|
@@ -408,6 +456,23 @@ Add environments to run by providing `TESTOMATIO_ENV` as comma seperated values:
|
|
|
408
456
|
TESTOMATIO={API_KEY} TESTOMATIO_ENV="Windows, Chrome" <actual run command>
|
|
409
457
|
```
|
|
410
458
|
|
|
459
|
+
### Save test results to .csv file
|
|
460
|
+
Add an env to run by specifying the `TESTOMATIO_CSV_FILENAME` variable.
|
|
461
|
+
|
|
462
|
+
1) using default report name:
|
|
463
|
+
|
|
464
|
+
```bash
|
|
465
|
+
TESTOMATIO={API_KEY} TESTOMATIO_CSV_FILENAME="report.csv" <actual run command>
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
2) using unique report name:
|
|
469
|
+
|
|
470
|
+
```bash
|
|
471
|
+
TESTOMATIO={API_KEY} TESTOMATIO_CSV_FILENAME="test.csv" <actual run command>
|
|
472
|
+
```
|
|
473
|
+
_It's create a new /export folder with csv files_
|
|
474
|
+
|
|
475
|
+
|
|
411
476
|
### Attaching Test Artifacts
|
|
412
477
|
|
|
413
478
|
To save a test artifacts (screenshots and videos) of a failed test use S3 storage.
|
|
@@ -520,3 +585,8 @@ If you want to finish a run started by `--launch` use `--finish` option. `TESTOM
|
|
|
520
585
|
```bash
|
|
521
586
|
TESTOMATIO={API_KEY} TESTOMATIO_RUN={RUN_ID} npx start-test-run --finish
|
|
522
587
|
```
|
|
588
|
+
|
|
589
|
+
### Debug logs
|
|
590
|
+
Pass `DEBUG` variable with module name e.g. `DEBUG=@testomatio/reporter:pipe:github`.
|
|
591
|
+
(Module name could be taken directly from the required module code).
|
|
592
|
+
To log all debug info pass `DEBUG=*`.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const debug = require('debug')('@testomatio/reporter:storage');
|
|
2
|
+
const { join, resolve } = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const uuid = require('uuid');
|
|
6
|
+
const { TESTOMAT_ARTIFACT_SUFFIX } = require('./constants');
|
|
7
|
+
const { specificTestInfo } = require('./util');
|
|
8
|
+
|
|
9
|
+
class ArtifactStorage {
|
|
10
|
+
|
|
11
|
+
constructor(params) {
|
|
12
|
+
this._tmpPrefix = "tsmt_reporter";
|
|
13
|
+
this.isFile = false;
|
|
14
|
+
this.isMemory = true;
|
|
15
|
+
this.storage = params?.toFile;
|
|
16
|
+
|
|
17
|
+
if (this.storage) {
|
|
18
|
+
this.isFile = true;
|
|
19
|
+
this.isMemory = false;
|
|
20
|
+
this.tmpDirFullpath = this.createTestomatTmpDir(this._tmpPrefix);
|
|
21
|
+
debug('SAVE to tmp folder mode enabled!');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static async storeToFile(tmpDirName, artifact, testSuffix = "test") {
|
|
26
|
+
const suffix = TESTOMAT_ARTIFACT_SUFFIX + uuid.v4() + testSuffix;
|
|
27
|
+
const dirpath = join(os.tmpdir(), tmpDirName);
|
|
28
|
+
const filepath = resolve(dirpath, `${suffix}.json`);
|
|
29
|
+
|
|
30
|
+
return fs.promises.appendFile(filepath, JSON.stringify(artifact));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static async artifact(artifact, context) {
|
|
34
|
+
// TODO: mode for different pre-hooks. As variant - "all-tests" || "only_fail"
|
|
35
|
+
// const mode = process.env.TESTOMAT_ARTIFACTS || "only_fail";
|
|
36
|
+
|
|
37
|
+
if (Array.isArray(global.testomatioArtifacts)) {
|
|
38
|
+
debug("Saving artifacts to global storage");
|
|
39
|
+
|
|
40
|
+
global.testomatioArtifacts.push(artifact);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (global?.testomatioArtifacts === undefined) {
|
|
44
|
+
const tmpDirNames = ArtifactStorage.tmpTestomatDirNames();
|
|
45
|
+
|
|
46
|
+
const testSuffix = specificTestInfo(context.test);
|
|
47
|
+
|
|
48
|
+
if (Array.isArray(tmpDirNames) && tmpDirNames.length) {
|
|
49
|
+
debug("Saving artifacts to memory tmp folder");
|
|
50
|
+
|
|
51
|
+
return ArtifactStorage.storeToFile(tmpDirNames[tmpDirNames.length - 1], artifact, testSuffix);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async artifactByTestName(test) {
|
|
57
|
+
const list = [];
|
|
58
|
+
|
|
59
|
+
if (this.isFile && this.tmpDirFullpath) {
|
|
60
|
+
const files = fs.readdirSync(this.tmpDirFullpath);
|
|
61
|
+
|
|
62
|
+
for (const file of files) {
|
|
63
|
+
if (file.includes(test)) {
|
|
64
|
+
const buff = await fs.promises.readFile(`${this.tmpDirFullpath }/${ file}`);
|
|
65
|
+
|
|
66
|
+
list.push(JSON.parse(buff.toString()));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return list;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async tmpContents() {
|
|
75
|
+
const contents = [];
|
|
76
|
+
|
|
77
|
+
if (this.isFile && this.tmpDirFullpath) {
|
|
78
|
+
const files = fs.readdirSync(this.tmpDirFullpath);
|
|
79
|
+
|
|
80
|
+
for (const file of files) {
|
|
81
|
+
const buff = await fs.promises.readFile(`${this.tmpDirFullpath }/${ file}`);
|
|
82
|
+
const content = buff.toString();
|
|
83
|
+
|
|
84
|
+
contents.push(content);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return contents;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
createTestomatTmpDir(clientPrefix) {
|
|
92
|
+
return fs.mkdtempSync(join(os.tmpdir(), clientPrefix));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
clearTmpDirByName(name) {
|
|
96
|
+
const tmpDirPath = join(os.tmpdir(), name);
|
|
97
|
+
|
|
98
|
+
if (fs.existsSync(tmpDirPath)) {
|
|
99
|
+
fs.rmSync(tmpDirPath, { recursive: true });
|
|
100
|
+
debug(` Testomat tmpDir = ${tmpDirPath} was deleted successfully!`);
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static tmpTestomatDirNames() {
|
|
107
|
+
const subname = this._tmpPrefix || "tsmt_reporter";
|
|
108
|
+
|
|
109
|
+
return fs.readdirSync(os.tmpdir(), { withFileTypes: true })
|
|
110
|
+
.filter((item) => item.isDirectory())
|
|
111
|
+
.map((item) => item.name)
|
|
112
|
+
.filter((name) => name.includes(subname));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
cleanup() {
|
|
116
|
+
if (this.isFile && this.tmpDirFullpath) {
|
|
117
|
+
const tmpDirNames = ArtifactStorage.tmpTestomatDirNames();
|
|
118
|
+
|
|
119
|
+
if (Array.isArray(tmpDirNames) && tmpDirNames.length) {
|
|
120
|
+
for (const name of tmpDirNames) {
|
|
121
|
+
this.clearTmpDirByName(name);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
debug("The tmp folder has not been created! Nothing to delete");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = ArtifactStorage;
|
package/lib/adapter/codecept.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const TestomatClient = require('../client');
|
|
3
|
+
const { STATUS, APP_PREFIX } = require('../constants');
|
|
4
|
+
const upload = require('../fileUploader');
|
|
5
|
+
const Output = require('../output');
|
|
6
|
+
|
|
1
7
|
if (!global.codeceptjs) {
|
|
2
8
|
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
|
|
3
9
|
global.codeceptjs = require('codeceptjs');
|
|
4
10
|
}
|
|
5
11
|
|
|
6
12
|
const { event, recorder, codecept } = global.codeceptjs;
|
|
7
|
-
const chalk = require('chalk');
|
|
8
|
-
const TestomatClient = require('../client');
|
|
9
|
-
const { FAILED } = require('../constants');
|
|
10
|
-
const TRConstants = require('../constants');
|
|
11
|
-
const upload = require('../fileUploader');
|
|
12
|
-
const Output = require('../output');
|
|
13
13
|
|
|
14
14
|
let currentMetaStep = [];
|
|
15
15
|
let error;
|
|
@@ -35,11 +35,6 @@ function CodeceptReporter(config) {
|
|
|
35
35
|
const testTimeMap = {};
|
|
36
36
|
const { apiKey } = config;
|
|
37
37
|
|
|
38
|
-
if (!apiKey) {
|
|
39
|
-
console.log('TESTOMATIO key is empty, ignoring reports');
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
38
|
const getDuration = test => {
|
|
44
39
|
if (testTimeMap[test.id]) {
|
|
45
40
|
return Date.now() - testTimeMap[test.id];
|
|
@@ -72,16 +67,17 @@ function CodeceptReporter(config) {
|
|
|
72
67
|
});
|
|
73
68
|
|
|
74
69
|
event.dispatcher.on(event.all.result, async () => {
|
|
75
|
-
if (videos.length && upload.isArtifactsEnabled) {
|
|
76
|
-
console.log(
|
|
70
|
+
if (videos.length && upload.isArtifactsEnabled()) {
|
|
71
|
+
console.log(APP_PREFIX, `🎞️ Uploading ${videos.length} videos...`);
|
|
77
72
|
|
|
78
73
|
const promises = [];
|
|
79
74
|
for (const video of videos) {
|
|
80
75
|
const { testId, title, path, type } = video;
|
|
81
76
|
const file = { path, type, title };
|
|
82
77
|
promises.push(
|
|
83
|
-
client.addTestRun(
|
|
78
|
+
client.addTestRun(undefined, {
|
|
84
79
|
...stripExampleFromTitle(title),
|
|
80
|
+
test_id: testId,
|
|
85
81
|
files: [file],
|
|
86
82
|
}),
|
|
87
83
|
);
|
|
@@ -89,7 +85,7 @@ function CodeceptReporter(config) {
|
|
|
89
85
|
await Promise.all(promises);
|
|
90
86
|
}
|
|
91
87
|
|
|
92
|
-
const status = failedTests.length === 0 ?
|
|
88
|
+
const status = failedTests.length === 0 ? STATUS.PASSED : STATUS.FAILED;
|
|
93
89
|
client.updateRunStatus(status);
|
|
94
90
|
});
|
|
95
91
|
|
|
@@ -100,12 +96,13 @@ function CodeceptReporter(config) {
|
|
|
100
96
|
}
|
|
101
97
|
const testId = parseTest(tags);
|
|
102
98
|
const testObj = getTestAndMessage(title);
|
|
103
|
-
client.addTestRun(
|
|
99
|
+
client.addTestRun(STATUS.PASSED, {
|
|
104
100
|
...stripExampleFromTitle(title),
|
|
105
101
|
suite_title: test.parent && test.parent.title,
|
|
106
102
|
message: testObj.message,
|
|
107
103
|
time: getDuration(test),
|
|
108
104
|
steps: output.text(),
|
|
105
|
+
test_id: testId,
|
|
109
106
|
});
|
|
110
107
|
output.stop();
|
|
111
108
|
});
|
|
@@ -124,9 +121,10 @@ function CodeceptReporter(config) {
|
|
|
124
121
|
failedTests.push(id || title);
|
|
125
122
|
const testId = parseTest(tags);
|
|
126
123
|
|
|
127
|
-
client.addTestRun(
|
|
124
|
+
client.addTestRun(STATUS.FAILED, {
|
|
128
125
|
...stripExampleFromTitle(title),
|
|
129
126
|
suite_title: suite.title,
|
|
127
|
+
test_id: testId,
|
|
130
128
|
error,
|
|
131
129
|
time: 0,
|
|
132
130
|
});
|
|
@@ -135,7 +133,7 @@ function CodeceptReporter(config) {
|
|
|
135
133
|
});
|
|
136
134
|
|
|
137
135
|
event.dispatcher.on(event.test.after, test => {
|
|
138
|
-
if (test.state && test.state !== FAILED) return;
|
|
136
|
+
if (test.state && test.state !== STATUS.FAILED) return;
|
|
139
137
|
if (test.err) error = test.err;
|
|
140
138
|
const { id, tags, title, artifacts } = test;
|
|
141
139
|
failedTests.push(id || title);
|
|
@@ -154,8 +152,9 @@ function CodeceptReporter(config) {
|
|
|
154
152
|
if (aid.startsWith('trace')) files.push({ testId: id, title, path: artifacts[aid], type: 'application/zip' });
|
|
155
153
|
}
|
|
156
154
|
|
|
157
|
-
client.addTestRun(
|
|
155
|
+
client.addTestRun(STATUS.FAILED, {
|
|
158
156
|
...stripExampleFromTitle(title),
|
|
157
|
+
test_id: testId,
|
|
159
158
|
suite_title: test.parent && test.parent.title,
|
|
160
159
|
error,
|
|
161
160
|
message: testObj.message,
|
|
@@ -172,8 +171,9 @@ function CodeceptReporter(config) {
|
|
|
172
171
|
|
|
173
172
|
const testId = parseTest(tags);
|
|
174
173
|
const testObj = getTestAndMessage(title);
|
|
175
|
-
client.addTestRun(
|
|
174
|
+
client.addTestRun(STATUS.SKIPPED, {
|
|
176
175
|
...stripExampleFromTitle(title),
|
|
176
|
+
test_id: testId,
|
|
177
177
|
suite_title: test.parent && test.parent.title,
|
|
178
178
|
message: testObj.message,
|
|
179
179
|
time: getDuration(test),
|
|
@@ -212,12 +212,13 @@ function CodeceptReporter(config) {
|
|
|
212
212
|
currentMetaStep = metaSteps;
|
|
213
213
|
stepShift = 2 * shift;
|
|
214
214
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
215
|
+
const durationMs = (+new Date() - (+stepStart));
|
|
216
|
+
let duration = '';
|
|
217
|
+
if (durationMs) {
|
|
218
|
+
duration = repeat(1) + chalk.grey(`(${durationMs}ms)`);
|
|
218
219
|
}
|
|
219
220
|
|
|
220
|
-
if (step.status ===
|
|
221
|
+
if (step.status === STATUS.FAILED) {
|
|
221
222
|
output.push(repeat(stepShift) + chalk.red(step.toString()) + duration);
|
|
222
223
|
} else {
|
|
223
224
|
output.push(repeat(stepShift) + step.toString() + duration);
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
const { Formatter, formatterHelpers } = require("@cucumber/cucumber");
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const {
|
|
5
|
+
const { STATUS } = require('../../constants');
|
|
6
|
+
const TestomatClient = require('../../client');
|
|
6
7
|
|
|
7
8
|
const { GherkinDocumentParser, PickleParser } = formatterHelpers
|
|
8
9
|
const {
|
|
@@ -19,7 +20,7 @@ class CucumberReporter extends Formatter {
|
|
|
19
20
|
this.cases = [];
|
|
20
21
|
|
|
21
22
|
this.client = new TestomatClient();
|
|
22
|
-
this.status =
|
|
23
|
+
this.status = STATUS.PASSED;
|
|
23
24
|
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -33,7 +34,8 @@ class CucumberReporter extends Formatter {
|
|
|
33
34
|
const testCaseAttempt = this.eventDataCollector.getTestCaseAttempt(testCaseFinished.testCaseStartedId);
|
|
34
35
|
|
|
35
36
|
let example;
|
|
36
|
-
|
|
37
|
+
|
|
38
|
+
let status = STATUS.PASSED;
|
|
37
39
|
let color = 'green';
|
|
38
40
|
let message;
|
|
39
41
|
|
|
@@ -41,22 +43,23 @@ class CucumberReporter extends Formatter {
|
|
|
41
43
|
|
|
42
44
|
if (testCaseAttempt.worstTestStepResult) {
|
|
43
45
|
if (testCaseAttempt.worstTestStepResult.status === 'SKIPPED') {
|
|
44
|
-
status =
|
|
46
|
+
status = STATUS.SKIPPED;
|
|
45
47
|
}
|
|
46
48
|
if (testCaseAttempt.worstTestStepResult.status === 'UNDEFINED') {
|
|
47
|
-
status =
|
|
49
|
+
status = STATUS.SKIPPED;
|
|
48
50
|
message = 'Undefined steps. Implement missing steps and rerun this scenario';
|
|
49
51
|
}
|
|
50
52
|
if (testCaseAttempt.worstTestStepResult.status === 'FAILED') {
|
|
51
53
|
message = testCaseAttempt?.worstTestStepResult?.message;
|
|
52
|
-
status =
|
|
54
|
+
status = STATUS.FAILED;
|
|
53
55
|
}
|
|
54
56
|
color = getStatusColor(testCaseAttempt.worstTestStepResult.status);
|
|
55
|
-
if (status !==
|
|
57
|
+
if (status !== STATUS.PASSED) this.failures.push(testCaseAttempt);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
if (testCaseAttempt.pickle.astNodeIds.length > 1) {
|
|
59
61
|
example = getExample(testCaseAttempt);
|
|
62
|
+
// @ts-ignore
|
|
60
63
|
testCaseAttempt.example = example;
|
|
61
64
|
}
|
|
62
65
|
|
|
@@ -70,8 +73,8 @@ class CucumberReporter extends Formatter {
|
|
|
70
73
|
if (message) cliMessage += chalk.gray(message.split('\n')[0]);
|
|
71
74
|
console.log(cliMessage);
|
|
72
75
|
|
|
73
|
-
if (status !==
|
|
74
|
-
this.status =
|
|
76
|
+
if (status !== STATUS.PASSED && status !== STATUS.SKIPPED) {
|
|
77
|
+
this.status = STATUS.FAILED;
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
const time = Object.values(testCaseAttempt.stepResults)
|
|
@@ -80,12 +83,13 @@ class CucumberReporter extends Formatter {
|
|
|
80
83
|
|
|
81
84
|
if (!this.client) return;
|
|
82
85
|
|
|
83
|
-
this.client.addTestRun(
|
|
86
|
+
this.client.addTestRun(status, {
|
|
84
87
|
// error: testCaseAttempt.worstTestStepResult.message,
|
|
85
88
|
message,
|
|
86
89
|
steps: getSteps(testCaseAttempt).map(s => s.toString()).join('\n').trim(),
|
|
87
90
|
example: { ...example},
|
|
88
91
|
title: scenario,
|
|
92
|
+
test_id: testId,
|
|
89
93
|
time,
|
|
90
94
|
});
|
|
91
95
|
}
|
|
@@ -121,9 +125,9 @@ class CucumberReporter extends Formatter {
|
|
|
121
125
|
|
|
122
126
|
if (!this.client) return;
|
|
123
127
|
|
|
124
|
-
this.client.updateRunStatus(testRunFinished.success ?
|
|
128
|
+
this.client.updateRunStatus(testRunFinished.success ? STATUS.PASSED : STATUS.FAILED)
|
|
125
129
|
}
|
|
126
|
-
}
|
|
130
|
+
}
|
|
127
131
|
|
|
128
132
|
function getSteps(tc) {
|
|
129
133
|
const stepIds = Object.keys(tc.stepResults);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
// eslint-disable-next-line import/no-unresolved
|
|
1
|
+
// eslint-disable-next-line global-require, import/no-extraneous-dependencies, import/no-unresolved
|
|
2
2
|
const { Formatter } = require('cucumber');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
|
-
const { TestomatClient, TRConstants } = require('../../reporter');
|
|
5
4
|
const { parseTest } = require('../../util');
|
|
5
|
+
const { STATUS } = require('../../constants');
|
|
6
|
+
const TestomatClient = require('../../client');
|
|
6
7
|
|
|
7
8
|
const createTestomatFormatter = apiKey => {
|
|
8
9
|
if (!apiKey || apiKey === '') {
|
|
@@ -92,18 +93,18 @@ const createTestomatFormatter = apiKey => {
|
|
|
92
93
|
if (!apiKey) return;
|
|
93
94
|
|
|
94
95
|
this.client = new TestomatClient({ apiKey });
|
|
95
|
-
this.status =
|
|
96
|
+
this.status = STATUS.PASSED.toString();
|
|
96
97
|
|
|
97
98
|
options.eventBroadcaster.on('gherkin-document', addDocument);
|
|
98
|
-
options.eventBroadcaster.on('test-run-started', () => this
|
|
99
|
+
options.eventBroadcaster.on('test-run-started', () => this?.client?.createRun());
|
|
99
100
|
options.eventBroadcaster.on('test-case-finished', this.onTestCaseFinished.bind(this));
|
|
100
|
-
options.eventBroadcaster.on('test-run-finished', () => this
|
|
101
|
+
options.eventBroadcaster.on('test-run-finished', () => this?.client?.updateRunStatus(this.status));
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
onTestCaseFinished(event) {
|
|
104
105
|
const scenario = getScenario(event.sourceLocation);
|
|
105
106
|
const testId = getTestId(scenario);
|
|
106
|
-
const status = event.result.status === 'undefined' ?
|
|
107
|
+
const status = event.result.status === 'undefined' ? STATUS.SKIPPED : event.result.status;
|
|
107
108
|
|
|
108
109
|
let example = getDataTableMap(scenario, event.sourceLocation);
|
|
109
110
|
if (example) example = JSON.parse(example);
|
|
@@ -120,14 +121,17 @@ const createTestomatFormatter = apiKey => {
|
|
|
120
121
|
message = 'Undefined steps. Implement missing steps and rerun this scenario';
|
|
121
122
|
}
|
|
122
123
|
console.log(cliMessage);
|
|
123
|
-
if (status !==
|
|
124
|
-
this.status =
|
|
124
|
+
if (status !== STATUS.PASSED && status !== STATUS.SKIPPED) {
|
|
125
|
+
this.status = STATUS.FAILED;
|
|
125
126
|
}
|
|
126
|
-
|
|
127
|
-
|
|
127
|
+
|
|
128
|
+
this.client?.addTestRun(status, {
|
|
129
|
+
error: event.result.exception instanceof Error ? event.result.exception : undefined,
|
|
128
130
|
message,
|
|
129
131
|
example,
|
|
132
|
+
test_id: testId,
|
|
130
133
|
title: getTitle(scenario),
|
|
134
|
+
suite_title: getTitle(getFeature(event.sourceLocation.uri)),
|
|
131
135
|
});
|
|
132
136
|
}
|
|
133
137
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const { STATUS } = require('../../constants');
|
|
2
2
|
const { parseTest, parseSuite } = require('../../util');
|
|
3
3
|
const TestomatClient = require('../../client');
|
|
4
4
|
|
|
@@ -57,16 +57,16 @@ const testomatioReporter = on => {
|
|
|
57
57
|
|
|
58
58
|
let state;
|
|
59
59
|
switch (test.state) {
|
|
60
|
-
case 'passed': state =
|
|
61
|
-
case 'failed': state =
|
|
60
|
+
case 'passed': state = STATUS.PASSED; break;
|
|
61
|
+
case 'failed': state = STATUS.FAILED; break;
|
|
62
62
|
case 'skipped':
|
|
63
63
|
case 'pending':
|
|
64
64
|
default:
|
|
65
|
-
state =
|
|
65
|
+
state = STATUS.SKIPPED;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
addSpecTestsPromises.push(client.addTestRun(
|
|
69
|
-
title, time, example, error, files, suite_title: suiteTitle, suite_id: suiteId
|
|
68
|
+
addSpecTestsPromises.push(client.addTestRun(state, {
|
|
69
|
+
title, time, example, error, files, suite_title: suiteTitle, test_id: testId, suite_id: suiteId
|
|
70
70
|
}));
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -74,7 +74,7 @@ const testomatioReporter = on => {
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
on('after:run', async results => {
|
|
77
|
-
const status = results.totalFailed ?
|
|
77
|
+
const status = results.totalFailed ? STATUS.FAILED : STATUS.PASSED;
|
|
78
78
|
await client.updateRunStatus(status);
|
|
79
79
|
});
|
|
80
80
|
};
|
package/lib/adapter/jasmine.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const TestomatClient = require('../client');
|
|
2
2
|
const { parseTest, ansiRegExp } = require('../util');
|
|
3
|
-
const {
|
|
3
|
+
const { STATUS } = require('../constants');
|
|
4
4
|
|
|
5
5
|
class JasmineReporter {
|
|
6
6
|
constructor(options) {
|
|
@@ -32,13 +32,14 @@ class JasmineReporter {
|
|
|
32
32
|
errorMessage = `${errorMessage}Failure: ${result.failedExpectations[i].message}\n`;
|
|
33
33
|
errorMessage = `${errorMessage}\n ${result.failedExpectations[i].stack}`;
|
|
34
34
|
}
|
|
35
|
-
console.log(`${title} : ${PASSED}`);
|
|
35
|
+
console.log(`${title} : ${STATUS.PASSED}`);
|
|
36
36
|
console.log(errorMessage);
|
|
37
37
|
const testId = parseTest(title);
|
|
38
38
|
errorMessage = errorMessage.replace(ansiRegExp(), '');
|
|
39
|
-
this.client.addTestRun(
|
|
39
|
+
this.client.addTestRun(status, {
|
|
40
40
|
error: result.failedExpectations[0],
|
|
41
41
|
message: errorMessage,
|
|
42
|
+
test_id: testId,
|
|
42
43
|
title,
|
|
43
44
|
time: this.getDuration(result),
|
|
44
45
|
});
|
|
@@ -48,7 +49,7 @@ class JasmineReporter {
|
|
|
48
49
|
if (!this.client) return;
|
|
49
50
|
|
|
50
51
|
const { overallStatus } = suiteInfo;
|
|
51
|
-
const status = overallStatus === 'failed' ? FAILED : PASSED;
|
|
52
|
+
const status = overallStatus === 'failed' ? STATUS.FAILED : STATUS.PASSED;
|
|
52
53
|
|
|
53
54
|
this.client.updateRunStatus(status).then(() => done);
|
|
54
55
|
}
|