@testomatio/reporter 0.4.6 → 0.5.0-beta.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/.eslintrc.js +18 -22
- package/.github/workflows/node.js.yml +2 -1
- package/.prettierrc.js +12 -0
- package/Changelog.md +18 -18
- package/README.md +122 -93
- package/example/codecept/codecept.conf.js +7 -7
- package/example/codecept/index_test.js +8 -8
- package/example/codecept/sample_test.js +4 -4
- package/example/codecept/steps.d.ts +1 -1
- package/example/codecept/steps_file.js +4 -2
- package/example/core/index.js +6 -6
- package/example/jest/index.test.js +3 -3
- package/example/jest/jest.config.js +1 -1
- package/example/jest/sample.test.js +4 -4
- package/example/mocha/test/index.test.js +5 -5
- package/lib/adapter/codecept.js +62 -67
- package/lib/adapter/cucumber.js +35 -52
- package/lib/adapter/cypress-plugin/index.js +42 -0
- package/lib/adapter/jasmine.js +15 -6
- package/lib/adapter/jest.js +9 -10
- package/lib/adapter/mocha.js +17 -14
- package/lib/adapter/playwright.js +25 -25
- package/lib/adapter/webdriver.js +3 -3
- package/lib/bin/startTest.js +56 -60
- package/lib/client.js +58 -110
- package/lib/constants.js +6 -6
- package/lib/fileUploader.js +17 -16
- package/lib/output.js +6 -8
- package/lib/reporter.js +2 -2
- package/lib/util.js +18 -5
- package/package.json +27 -15
- package/testcafe/index.js +11 -14
- package/tests/adapter/config/index.js +10 -0
- package/tests/adapter/examples/codecept/codecept.conf.js +33 -0
- package/tests/adapter/examples/codecept/index_test.js +11 -0
- package/tests/adapter/examples/codecept/jsconfig.json +5 -0
- package/tests/adapter/examples/codecept/output/Test_for_suite_2_@Tc2171bd2.failed.png +0 -0
- package/tests/adapter/examples/codecept/output/Test_issue_for_suite_1_@Tca70c8c4.failed.png +0 -0
- package/tests/adapter/examples/codecept/sample_test.js +7 -0
- package/tests/adapter/examples/codecept/steps_file.js +10 -0
- package/tests/adapter/examples/jasmine/index.test.js +11 -0
- package/tests/adapter/examples/jasmine/passReporterOpts.sh +8 -0
- package/tests/adapter/examples/jest/index.test.js +11 -0
- package/tests/adapter/examples/jest/jest.config.js +4 -0
- package/tests/adapter/examples/mocha/index.test.js +13 -0
- package/tests/adapter/examples/mocha/mocha.config.js +4 -0
- package/tests/adapter/index.test.js +136 -0
- package/tests/adapter/utils/index.js +40 -0
- package/.prettierrc.json +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
describe(
|
|
2
|
-
test(
|
|
1
|
+
describe('Suite 1', () => {
|
|
2
|
+
test('Test addition', () => {
|
|
3
3
|
expect(1 + 2).toBe(4);
|
|
4
4
|
});
|
|
5
5
|
|
|
6
|
-
test(
|
|
6
|
+
test('Test some more addition', () => {
|
|
7
7
|
expect(1 + 2).toBe(3);
|
|
8
8
|
});
|
|
9
9
|
});
|
|
@@ -132,7 +132,7 @@ module.exports = {
|
|
|
132
132
|
// snapshotSerializers: [],
|
|
133
133
|
|
|
134
134
|
// The test environment that will be used for testing
|
|
135
|
-
testEnvironment:
|
|
135
|
+
testEnvironment: 'node',
|
|
136
136
|
|
|
137
137
|
// Options that will be passed to the testEnvironment
|
|
138
138
|
// testEnvironmentOptions: {},
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
describe(
|
|
2
|
-
test(
|
|
1
|
+
describe('Suite 2', () => {
|
|
2
|
+
test('This is a sample test 3', () => {
|
|
3
3
|
expect(1 + 2).toBe(3);
|
|
4
4
|
});
|
|
5
5
|
|
|
6
|
-
test(
|
|
6
|
+
test('This is a sample test 4', () => {
|
|
7
7
|
expect(1 + 2).toBe(3);
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
-
test(
|
|
10
|
+
test('Test for suite 2', () => {
|
|
11
11
|
expect(1 + 2).toBe(3);
|
|
12
12
|
});
|
|
13
13
|
});
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
const assert = require(
|
|
1
|
+
const assert = require('assert');
|
|
2
2
|
|
|
3
|
-
describe(
|
|
4
|
-
it(
|
|
3
|
+
describe('Sample mocha suite', () => {
|
|
4
|
+
it('Sample mocha test', () => {
|
|
5
5
|
assert.equal([1, 2, 3].indexOf(4), 0);
|
|
6
6
|
});
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
-
describe(
|
|
10
|
-
it(
|
|
9
|
+
describe('Sample mocha suite 2', () => {
|
|
10
|
+
it('Sample mocha test 2', () => {
|
|
11
11
|
assert.equal(1, 1);
|
|
12
12
|
});
|
|
13
13
|
});
|
package/lib/adapter/codecept.js
CHANGED
|
@@ -1,63 +1,46 @@
|
|
|
1
|
-
/* eslint-disable no-param-reassign */
|
|
2
1
|
if (!global.codeceptjs) {
|
|
3
|
-
|
|
2
|
+
// eslint-disable-next-line global-require
|
|
3
|
+
global.codeceptjs = require('codeceptjs');
|
|
4
4
|
}
|
|
5
|
+
|
|
5
6
|
const { event, recorder, codecept } = global.codeceptjs;
|
|
6
|
-
const chalk = require(
|
|
7
|
-
const TestomatClient = require(
|
|
8
|
-
const { FAILED } = require(
|
|
9
|
-
const TRConstants = require(
|
|
10
|
-
const upload = require(
|
|
11
|
-
const Output = require(
|
|
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');
|
|
12
13
|
|
|
13
14
|
let currentMetaStep = [];
|
|
14
15
|
let error;
|
|
15
16
|
let stepShift = 0;
|
|
17
|
+
|
|
16
18
|
const output = new Output({
|
|
17
|
-
filterFn:
|
|
19
|
+
filterFn: stack => !stack.includes('codeceptjs/lib/output'), // output from codeceptjs
|
|
18
20
|
});
|
|
21
|
+
|
|
19
22
|
let stepStart = new Date();
|
|
20
23
|
|
|
21
24
|
const MAJOR_VERSION = parseInt(codecept.version().match(/\d/)[0], 10);
|
|
22
25
|
|
|
26
|
+
const DATA_REGEXP = /[|\s]+?(\{".*\}|\[.*\])/;
|
|
27
|
+
|
|
23
28
|
if (MAJOR_VERSION < 3) {
|
|
24
|
-
console.log(
|
|
25
|
-
"🔴 This reporter works with CodeceptJS 3+, please update your tests"
|
|
26
|
-
);
|
|
29
|
+
console.log('🔴 This reporter works with CodeceptJS 3+, please update your tests');
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
if (tags) {
|
|
31
|
-
for (const tag of tags) {
|
|
32
|
-
if (tag.startsWith("@T")) {
|
|
33
|
-
return tag.substring(2, tag.length);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return null;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const getTestAndMessage = (title) => {
|
|
42
|
-
const testObj = { message: "" };
|
|
43
|
-
const testArr = title.split(/\s(\|\s\{.*?\})/);
|
|
44
|
-
testObj.title = testArr[0];
|
|
45
|
-
|
|
46
|
-
return testObj;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
module.exports = (config) => {
|
|
32
|
+
function CodeceptReporter(config) {
|
|
50
33
|
let failedTests = [];
|
|
51
34
|
let videos = [];
|
|
52
35
|
const testTimeMap = {};
|
|
53
36
|
const { apiKey } = config;
|
|
54
37
|
|
|
55
38
|
if (!apiKey) {
|
|
56
|
-
console.log(
|
|
39
|
+
console.log('TESTOMATIO key is empty, ignoring reports');
|
|
57
40
|
return;
|
|
58
41
|
}
|
|
59
42
|
|
|
60
|
-
const getDuration =
|
|
43
|
+
const getDuration = test => {
|
|
61
44
|
if (testTimeMap[test.id]) {
|
|
62
45
|
return Date.now() - testTimeMap[test.id];
|
|
63
46
|
}
|
|
@@ -71,7 +54,7 @@ module.exports = (config) => {
|
|
|
71
54
|
|
|
72
55
|
// Listening to events
|
|
73
56
|
event.dispatcher.on(event.all.before, () => {
|
|
74
|
-
recorder.add(
|
|
57
|
+
recorder.add('Creating new run', () => client.createRun());
|
|
75
58
|
videos = [];
|
|
76
59
|
});
|
|
77
60
|
|
|
@@ -84,23 +67,24 @@ module.exports = (config) => {
|
|
|
84
67
|
});
|
|
85
68
|
});
|
|
86
69
|
|
|
87
|
-
event.dispatcher.on(event.test.started,
|
|
70
|
+
event.dispatcher.on(event.test.started, test => {
|
|
88
71
|
testTimeMap[test.id] = Date.now();
|
|
89
|
-
err = null;
|
|
90
72
|
});
|
|
91
73
|
|
|
92
74
|
event.dispatcher.on(event.all.result, async () => {
|
|
93
75
|
if (videos.length && upload.isEnabled()) {
|
|
94
76
|
console.log(TRConstants.APP_PREFIX, `🎞️ Uploading ${videos.length} videos...`);
|
|
95
77
|
|
|
96
|
-
|
|
78
|
+
const promises = [];
|
|
97
79
|
for (const video of videos) {
|
|
98
80
|
const { testId, title, path, type } = video;
|
|
99
81
|
const file = { path, type, title };
|
|
100
|
-
promises.push(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
82
|
+
promises.push(
|
|
83
|
+
client.addTestRun(testId, undefined, {
|
|
84
|
+
...stripExampleFromTitle(title),
|
|
85
|
+
files: [file],
|
|
86
|
+
}),
|
|
87
|
+
);
|
|
104
88
|
}
|
|
105
89
|
await Promise.all(promises);
|
|
106
90
|
}
|
|
@@ -109,10 +93,10 @@ module.exports = (config) => {
|
|
|
109
93
|
client.updateRunStatus(status);
|
|
110
94
|
});
|
|
111
95
|
|
|
112
|
-
event.dispatcher.on(event.test.passed,
|
|
96
|
+
event.dispatcher.on(event.test.passed, test => {
|
|
113
97
|
const { id, tags, title } = test;
|
|
114
98
|
if (id && failedTests.includes(id)) {
|
|
115
|
-
failedTests = failedTests.filter(
|
|
99
|
+
failedTests = failedTests.filter(failed => id !== failed);
|
|
116
100
|
}
|
|
117
101
|
const testId = parseTest(tags);
|
|
118
102
|
const testObj = getTestAndMessage(title);
|
|
@@ -129,7 +113,7 @@ module.exports = (config) => {
|
|
|
129
113
|
error = err;
|
|
130
114
|
});
|
|
131
115
|
|
|
132
|
-
event.dispatcher.on(event.test.after,
|
|
116
|
+
event.dispatcher.on(event.test.after, test => {
|
|
133
117
|
if (test.state && test.state !== FAILED) return;
|
|
134
118
|
if (test.err) error = test.err;
|
|
135
119
|
const { id, tags, title, artifacts } = test;
|
|
@@ -156,7 +140,7 @@ module.exports = (config) => {
|
|
|
156
140
|
output.stop();
|
|
157
141
|
});
|
|
158
142
|
|
|
159
|
-
event.dispatcher.on(event.test.skipped,
|
|
143
|
+
event.dispatcher.on(event.test.skipped, test => {
|
|
160
144
|
const { tags, title } = test;
|
|
161
145
|
const testId = parseTest(tags);
|
|
162
146
|
const testObj = getTestAndMessage(title);
|
|
@@ -168,13 +152,13 @@ module.exports = (config) => {
|
|
|
168
152
|
output.stop();
|
|
169
153
|
});
|
|
170
154
|
|
|
171
|
-
event.dispatcher.on(event.step.started,
|
|
155
|
+
event.dispatcher.on(event.step.started, step => {
|
|
172
156
|
stepShift = 0;
|
|
173
157
|
step.started = true;
|
|
174
158
|
stepStart = new Date();
|
|
175
159
|
});
|
|
176
160
|
|
|
177
|
-
event.dispatcher.on(event.step.finished,
|
|
161
|
+
event.dispatcher.on(event.step.finished, step => {
|
|
178
162
|
if (!step.started) return;
|
|
179
163
|
let processingStep = step;
|
|
180
164
|
const metaSteps = [];
|
|
@@ -184,24 +168,15 @@ module.exports = (config) => {
|
|
|
184
168
|
}
|
|
185
169
|
const shift = metaSteps.length;
|
|
186
170
|
|
|
187
|
-
for (
|
|
188
|
-
let i = 0;
|
|
189
|
-
i < Math.max(currentMetaStep.length, metaSteps.length);
|
|
190
|
-
i++
|
|
191
|
-
) {
|
|
171
|
+
for (let i = 0; i < Math.max(currentMetaStep.length, metaSteps.length); i++) {
|
|
192
172
|
if (currentMetaStep[i] !== metaSteps[i]) {
|
|
193
173
|
stepShift = 2 * i;
|
|
174
|
+
// eslint-disable-next-line no-continue
|
|
194
175
|
if (!metaSteps[i]) continue;
|
|
195
176
|
if (metaSteps[i].isBDD()) {
|
|
196
|
-
output.push(
|
|
197
|
-
repeat(stepShift) +
|
|
198
|
-
chalk.bold(metaSteps[i].toString()) +
|
|
199
|
-
metaSteps[i].comment
|
|
200
|
-
);
|
|
177
|
+
output.push(repeat(stepShift) + chalk.bold(metaSteps[i].toString()) + metaSteps[i].comment);
|
|
201
178
|
} else {
|
|
202
|
-
output.push(
|
|
203
|
-
repeat(stepShift) + chalk.green.bold(metaSteps[i].toString())
|
|
204
|
-
);
|
|
179
|
+
output.push(repeat(stepShift) + chalk.green.bold(metaSteps[i].toString()));
|
|
205
180
|
}
|
|
206
181
|
}
|
|
207
182
|
}
|
|
@@ -220,23 +195,43 @@ module.exports = (config) => {
|
|
|
220
195
|
}
|
|
221
196
|
});
|
|
222
197
|
|
|
223
|
-
event.dispatcher.on(event.step.comment,
|
|
198
|
+
event.dispatcher.on(event.step.comment, step => {
|
|
224
199
|
output.push(chalk.cyan.bold(step.toString()));
|
|
225
200
|
});
|
|
226
|
-
}
|
|
201
|
+
}
|
|
227
202
|
|
|
228
|
-
|
|
203
|
+
function parseTest(tags) {
|
|
204
|
+
if (tags) {
|
|
205
|
+
for (const tag of tags) {
|
|
206
|
+
if (tag.startsWith('@T')) {
|
|
207
|
+
return tag.substring(2, tag.length);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function getTestAndMessage(title) {
|
|
216
|
+
const testObj = { message: '' };
|
|
217
|
+
const testArr = title.split(/\s(\|\s\{.*?\})/);
|
|
218
|
+
testObj.title = testArr[0];
|
|
219
|
+
|
|
220
|
+
return testObj;
|
|
221
|
+
}
|
|
229
222
|
|
|
230
223
|
function stripExampleFromTitle(title) {
|
|
231
224
|
const res = title.match(DATA_REGEXP);
|
|
232
225
|
if (!res) return { title, example: null };
|
|
233
226
|
|
|
234
227
|
const example = JSON.parse(res[1]);
|
|
235
|
-
title = title.replace(DATA_REGEXP,
|
|
228
|
+
title = title.replace(DATA_REGEXP, '').trim();
|
|
236
229
|
|
|
237
230
|
return { title, example };
|
|
238
231
|
}
|
|
239
232
|
|
|
240
233
|
function repeat(num) {
|
|
241
|
-
return
|
|
234
|
+
return ''.padStart(num, ' ');
|
|
242
235
|
}
|
|
236
|
+
|
|
237
|
+
module.exports = CodeceptReporter;
|
package/lib/adapter/cucumber.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
// eslint-disable-next-line import/no-unresolved
|
|
2
|
+
const { Formatter } = require('cucumber');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const { TestomatClient, TRConstants } = require('../reporter');
|
|
5
|
+
const { parseTest } = require('../util');
|
|
6
|
+
|
|
7
|
+
const createTestomatFormatter = apiKey => {
|
|
8
|
+
if (!apiKey || apiKey === '') {
|
|
9
|
+
console.log(chalk.red('TESTOMATIO key is empty, ignoring reports'));
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
const documents = {};
|
|
12
13
|
const dataTableMap = {};
|
|
13
14
|
|
|
14
|
-
const addDocument =
|
|
15
|
+
const addDocument = gherkinDocument => {
|
|
15
16
|
documents[gherkinDocument.uri] = gherkinDocument.document;
|
|
16
17
|
};
|
|
17
18
|
|
|
18
|
-
const getTitle =
|
|
19
|
+
const getTitle = scenario => {
|
|
19
20
|
let { name } = scenario;
|
|
20
21
|
if (scenario.tags.length) {
|
|
21
|
-
let tags =
|
|
22
|
+
let tags = '';
|
|
22
23
|
for (const tag of scenario.tags) {
|
|
23
24
|
tags = `${tags} ${tag.name}`;
|
|
24
25
|
}
|
|
@@ -27,18 +28,15 @@ const createTestomatFormatter = (apiKey) => {
|
|
|
27
28
|
return name;
|
|
28
29
|
};
|
|
29
30
|
|
|
30
|
-
const getFeature =
|
|
31
|
+
const getFeature = uri => documents[uri].feature;
|
|
31
32
|
|
|
32
|
-
const getScenario =
|
|
33
|
+
const getScenario = location => {
|
|
33
34
|
const { children } = getFeature(location.uri);
|
|
34
35
|
for (const scenario of children) {
|
|
35
|
-
if (
|
|
36
|
-
scenario.type === "Scenario" &&
|
|
37
|
-
scenario.location.line === location.line
|
|
38
|
-
) {
|
|
36
|
+
if (scenario.type === 'Scenario' && scenario.location.line === location.line) {
|
|
39
37
|
return scenario;
|
|
40
38
|
}
|
|
41
|
-
if (scenario.type ===
|
|
39
|
+
if (scenario.type === 'ScenarioOutline') {
|
|
42
40
|
for (const example of scenario.examples) {
|
|
43
41
|
for (const tableBody of example.tableBody) {
|
|
44
42
|
if (tableBody.location.line === location.line) {
|
|
@@ -53,19 +51,15 @@ const createTestomatFormatter = (apiKey) => {
|
|
|
53
51
|
};
|
|
54
52
|
|
|
55
53
|
const loadDataTable = (scenario, uri) => {
|
|
56
|
-
if (scenario.type ===
|
|
54
|
+
if (scenario.type === 'ScenarioOutline') {
|
|
57
55
|
for (const example of scenario.examples) {
|
|
58
56
|
for (const tableBody of example.tableBody) {
|
|
59
|
-
const dataMap = example.tableHeader.cells.reduce(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
dataTableMap[`${uri}:${tableBody.location.line}`] =
|
|
68
|
-
JSON.stringify(dataMap);
|
|
57
|
+
const dataMap = example.tableHeader.cells.reduce((acc, cell, index) => {
|
|
58
|
+
acc[cell.value] = tableBody.cells[index].value;
|
|
59
|
+
return acc;
|
|
60
|
+
}, {});
|
|
61
|
+
|
|
62
|
+
dataTableMap[`${uri}:${tableBody.location.line}`] = JSON.stringify(dataMap);
|
|
69
63
|
}
|
|
70
64
|
}
|
|
71
65
|
}
|
|
@@ -77,10 +71,10 @@ const createTestomatFormatter = (apiKey) => {
|
|
|
77
71
|
loadDataTable(scenario, sourceLocation.uri);
|
|
78
72
|
}
|
|
79
73
|
|
|
80
|
-
return dataTableMap[key] ||
|
|
74
|
+
return dataTableMap[key] || '';
|
|
81
75
|
};
|
|
82
76
|
|
|
83
|
-
const getTestId =
|
|
77
|
+
const getTestId = scenario => {
|
|
84
78
|
if (scenario) {
|
|
85
79
|
for (const tag of scenario.tags) {
|
|
86
80
|
const testId = parseTest(tag.name);
|
|
@@ -100,41 +94,30 @@ const createTestomatFormatter = (apiKey) => {
|
|
|
100
94
|
this.client = new TestomatClient({ apiKey });
|
|
101
95
|
this.status = TRConstants.PASSED;
|
|
102
96
|
|
|
103
|
-
options.eventBroadcaster.on(
|
|
104
|
-
options.eventBroadcaster.on(
|
|
105
|
-
|
|
106
|
-
options.eventBroadcaster.on(
|
|
107
|
-
"test-case-finished",
|
|
108
|
-
this.onTestCaseFinished.bind(this)
|
|
109
|
-
);
|
|
110
|
-
options.eventBroadcaster.on("test-run-finished", () =>
|
|
111
|
-
this.client.updateRunStatus(this.status));
|
|
97
|
+
options.eventBroadcaster.on('gherkin-document', addDocument);
|
|
98
|
+
options.eventBroadcaster.on('test-run-started', () => this.client.createRun());
|
|
99
|
+
options.eventBroadcaster.on('test-case-finished', this.onTestCaseFinished.bind(this));
|
|
100
|
+
options.eventBroadcaster.on('test-run-finished', () => this.client.updateRunStatus(this.status));
|
|
112
101
|
}
|
|
113
102
|
|
|
114
103
|
onTestCaseFinished(event) {
|
|
115
104
|
const scenario = getScenario(event.sourceLocation);
|
|
116
105
|
const testId = getTestId(scenario);
|
|
117
|
-
const status =
|
|
118
|
-
event.result.status === "undefined"
|
|
119
|
-
? TRConstants.SKIPPED
|
|
120
|
-
: event.result.status;
|
|
106
|
+
const status = event.result.status === 'undefined' ? TRConstants.SKIPPED : event.result.status;
|
|
121
107
|
|
|
122
108
|
let example = getDataTableMap(scenario, event.sourceLocation);
|
|
123
109
|
if (example) example = JSON.parse(example);
|
|
124
110
|
|
|
125
111
|
if (!scenario.name) return;
|
|
126
112
|
|
|
127
|
-
let message =
|
|
128
|
-
let cliMessage = `- ${scenario.name}: ${chalk.bold(
|
|
129
|
-
status.toUpperCase()
|
|
130
|
-
)}`;
|
|
113
|
+
let message = '';
|
|
114
|
+
let cliMessage = `- ${scenario.name}: ${chalk.bold(status.toUpperCase())}`;
|
|
131
115
|
|
|
132
|
-
if (event.result.status ===
|
|
116
|
+
if (event.result.status === 'undefined') {
|
|
133
117
|
cliMessage += chalk.yellow(
|
|
134
|
-
|
|
118
|
+
' (undefined steps. Run Cucumber without this formatter and implement missing steps)',
|
|
135
119
|
);
|
|
136
|
-
message =
|
|
137
|
-
"Undefined steps. Implement missing steps and rerun this scenario";
|
|
120
|
+
message = 'Undefined steps. Implement missing steps and rerun this scenario';
|
|
138
121
|
}
|
|
139
122
|
console.log(cliMessage);
|
|
140
123
|
if (status !== TRConstants.PASSED && status !== TRConstants.SKIPPED) {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const TRConstants = require('../../constants');
|
|
2
|
+
const { parseTest } = require('../../util');
|
|
3
|
+
const TestomatClient = require('../../client');
|
|
4
|
+
|
|
5
|
+
const testomatioReporter = on => {
|
|
6
|
+
const client = new TestomatClient({ apiKey: process.env.TESTOMATIO });
|
|
7
|
+
|
|
8
|
+
on('before:run', async () => {
|
|
9
|
+
await client.createRun();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
on('after:spec', async (_spec, results) => {
|
|
13
|
+
const addSpecTestsPromises = [];
|
|
14
|
+
|
|
15
|
+
for (const test of results.tests) {
|
|
16
|
+
const latestAttempt = test.attempts[test.attempts.length - 1];
|
|
17
|
+
console.log({ latestAttempt })
|
|
18
|
+
const time = latestAttempt.duration;
|
|
19
|
+
const error = latestAttempt.error;
|
|
20
|
+
|
|
21
|
+
const title = test.title[1]; // [0] - spec title, [1] - test title
|
|
22
|
+
const testId = parseTest(title);
|
|
23
|
+
|
|
24
|
+
const videos = [results.video];
|
|
25
|
+
const screenshots = results.screenshots.map(screenshot => screenshot.path);
|
|
26
|
+
const files = [...videos, ...screenshots];
|
|
27
|
+
|
|
28
|
+
const state = test.state === 'passed' ? TRConstants.PASSED : TRConstants.FAILED;
|
|
29
|
+
|
|
30
|
+
addSpecTestsPromises.push(client.addTestRun(testId, state, { title, time, error, files }));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
await Promise.all(addSpecTestsPromises);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
on('after:run', async results => {
|
|
37
|
+
const status = results.totalFailed ? TRConstants.FAILED : TRConstants.PASSED;
|
|
38
|
+
await client.updateRunStatus(status);
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
module.exports = testomatioReporter;
|
package/lib/adapter/jasmine.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const TestomatClient = require(
|
|
2
|
-
const { parseTest, ansiRegExp } = require(
|
|
3
|
-
const { PASSED } = require(
|
|
1
|
+
const TestomatClient = require('../client');
|
|
2
|
+
const { parseTest, ansiRegExp } = require('../util');
|
|
3
|
+
const { PASSED, FAILED } = require('../constants');
|
|
4
4
|
|
|
5
5
|
class JasmineReporter {
|
|
6
6
|
constructor(options) {
|
|
@@ -8,7 +8,7 @@ class JasmineReporter {
|
|
|
8
8
|
const { apiKey } = options;
|
|
9
9
|
|
|
10
10
|
if (!apiKey) {
|
|
11
|
-
console.log(
|
|
11
|
+
console.log('TESTOMATIO key is empty, ignoring reports');
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -33,7 +33,7 @@ class JasmineReporter {
|
|
|
33
33
|
|
|
34
34
|
const title = result.description;
|
|
35
35
|
const { status } = result;
|
|
36
|
-
let errorMessage =
|
|
36
|
+
let errorMessage = '';
|
|
37
37
|
|
|
38
38
|
for (let i = 0; i < result.failedExpectations.length; i += 1) {
|
|
39
39
|
errorMessage = `${errorMessage}Failure: ${result.failedExpectations[i].message}\n`;
|
|
@@ -42,7 +42,7 @@ class JasmineReporter {
|
|
|
42
42
|
console.log(`${title} : ${PASSED}`);
|
|
43
43
|
console.log(errorMessage);
|
|
44
44
|
const testId = parseTest(title);
|
|
45
|
-
errorMessage = errorMessage.replace(ansiRegExp(),
|
|
45
|
+
errorMessage = errorMessage.replace(ansiRegExp(), '');
|
|
46
46
|
this.client.addTestRun(testId, status, {
|
|
47
47
|
error: result.failedExpectations[0],
|
|
48
48
|
message: errorMessage,
|
|
@@ -50,6 +50,15 @@ class JasmineReporter {
|
|
|
50
50
|
time: this.getDuration(result),
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
|
+
|
|
54
|
+
jasmineDone(suiteInfo, done) {
|
|
55
|
+
if (!this.client) return;
|
|
56
|
+
|
|
57
|
+
const { overallStatus } = suiteInfo;
|
|
58
|
+
const status = overallStatus === 'failed' ? FAILED : PASSED;
|
|
59
|
+
|
|
60
|
+
this.client.updateRunStatus(status).then(() => done);
|
|
61
|
+
}
|
|
53
62
|
}
|
|
54
63
|
|
|
55
64
|
module.exports = JasmineReporter;
|
package/lib/adapter/jest.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const TestomatClient = require(
|
|
2
|
-
const TRConstants = require(
|
|
3
|
-
const { parseTest, ansiRegExp } = require(
|
|
1
|
+
const TestomatClient = require('../client');
|
|
2
|
+
const TRConstants = require('../constants');
|
|
3
|
+
const { parseTest, ansiRegExp } = require('../util');
|
|
4
4
|
|
|
5
5
|
class JestReporter {
|
|
6
6
|
constructor(globalConfig, options) {
|
|
@@ -9,7 +9,7 @@ class JestReporter {
|
|
|
9
9
|
const { apiKey } = options;
|
|
10
10
|
|
|
11
11
|
if (!apiKey) {
|
|
12
|
-
console.log(
|
|
12
|
+
console.log('TESTOMATIO key is empty, ignoring reports');
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -26,19 +26,19 @@ class JestReporter {
|
|
|
26
26
|
let steps = null;
|
|
27
27
|
const { status, title, duration, failureMessages } = result;
|
|
28
28
|
if (failureMessages[0]) {
|
|
29
|
-
let errorMessage = failureMessages[0].replace(ansiRegExp(),
|
|
30
|
-
errorMessage = errorMessage.split(
|
|
29
|
+
let errorMessage = failureMessages[0].replace(ansiRegExp(), '');
|
|
30
|
+
errorMessage = errorMessage.split('\n')[0];
|
|
31
31
|
error = {
|
|
32
32
|
message: errorMessage,
|
|
33
33
|
};
|
|
34
34
|
steps = failureMessages[0];
|
|
35
35
|
}
|
|
36
36
|
const testId = parseTest(title);
|
|
37
|
-
const deducedStatus = status ===
|
|
37
|
+
const deducedStatus = status === 'pending' ? 'skipped' : status;
|
|
38
38
|
|
|
39
39
|
// In jest if test is not matched with test name pattern it is considered as skipped.
|
|
40
40
|
// So adding a check if it is skipped for real or because of test pattern
|
|
41
|
-
if (!this._globalConfig.testNamePattern || deducedStatus !==
|
|
41
|
+
if (!this._globalConfig.testNamePattern || deducedStatus !== 'skipped') {
|
|
42
42
|
this.client.addTestRun(testId, deducedStatus, {
|
|
43
43
|
error,
|
|
44
44
|
steps,
|
|
@@ -53,8 +53,7 @@ class JestReporter {
|
|
|
53
53
|
if (!this.client) return;
|
|
54
54
|
|
|
55
55
|
const { numFailedTests } = results;
|
|
56
|
-
const status =
|
|
57
|
-
numFailedTests === 0 ? TRConstants.PASSED : TRConstants.FAILED;
|
|
56
|
+
const status = numFailedTests === 0 ? TRConstants.PASSED : TRConstants.FAILED;
|
|
58
57
|
this.client.updateRunStatus(status);
|
|
59
58
|
}
|
|
60
59
|
}
|
package/lib/adapter/mocha.js
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
|
-
const
|
|
2
|
-
const TestomatClient = require(
|
|
3
|
-
const TRConstants = require(
|
|
4
|
-
const { parseTest } = require(
|
|
1
|
+
const Mocha = require('mocha');
|
|
2
|
+
const TestomatClient = require('../client');
|
|
3
|
+
const TRConstants = require('../constants');
|
|
4
|
+
const { parseTest } = require('../util');
|
|
5
|
+
|
|
6
|
+
const { EVENT_RUN_BEGIN, EVENT_RUN_END, EVENT_TEST_FAIL, EVENT_TEST_PASS } = Mocha.Runner.constants;
|
|
5
7
|
|
|
6
8
|
function MochaReporter(runner, opts) {
|
|
7
|
-
|
|
9
|
+
Mocha.reporters.Base.call(this, runner);
|
|
8
10
|
let passes = 0;
|
|
9
11
|
let failures = 0;
|
|
10
12
|
|
|
11
13
|
const { apiKey } = opts.reporterOptions;
|
|
14
|
+
|
|
12
15
|
if (!apiKey) {
|
|
13
|
-
console.log(
|
|
16
|
+
console.log('TESTOMATIO key is empty, ignoring reports');
|
|
14
17
|
return;
|
|
15
18
|
}
|
|
16
19
|
const client = new TestomatClient({ apiKey });
|
|
17
20
|
|
|
18
|
-
runner.on(
|
|
21
|
+
runner.on(EVENT_RUN_BEGIN, () => {
|
|
19
22
|
client.createRun();
|
|
20
23
|
});
|
|
21
24
|
|
|
22
|
-
runner.on(
|
|
25
|
+
runner.on(EVENT_TEST_PASS, test => {
|
|
23
26
|
passes += 1;
|
|
24
|
-
console.log(
|
|
27
|
+
console.log('pass: %s', test.fullTitle());
|
|
25
28
|
const testId = parseTest(test.title);
|
|
26
29
|
client.addTestRun(testId, TRConstants.PASSED, {
|
|
27
30
|
title: test.title,
|
|
@@ -29,9 +32,9 @@ function MochaReporter(runner, opts) {
|
|
|
29
32
|
});
|
|
30
33
|
});
|
|
31
34
|
|
|
32
|
-
runner.on(
|
|
35
|
+
runner.on(EVENT_TEST_FAIL, (test, err) => {
|
|
33
36
|
failures += 1;
|
|
34
|
-
console.log(
|
|
37
|
+
console.log('fail: %s -- error: %s', test.fullTitle(), err.message);
|
|
35
38
|
const testId = parseTest(test.title);
|
|
36
39
|
client.addTestRun(testId, TRConstants.FAILED, {
|
|
37
40
|
error: err,
|
|
@@ -40,14 +43,14 @@ function MochaReporter(runner, opts) {
|
|
|
40
43
|
});
|
|
41
44
|
});
|
|
42
45
|
|
|
43
|
-
runner.on(
|
|
44
|
-
console.log(
|
|
46
|
+
runner.on(EVENT_RUN_END, () => {
|
|
47
|
+
console.log('end: %d/%d', passes, passes + failures);
|
|
45
48
|
const status = failures === 0 ? TRConstants.PASSED : TRConstants.FAILED;
|
|
46
49
|
client.updateRunStatus(status);
|
|
47
50
|
});
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
// To have this reporter "extend" a built-in reporter uncomment the following line:
|
|
51
|
-
|
|
54
|
+
Mocha.utils.inherits(MochaReporter, Mocha.reporters.Spec);
|
|
52
55
|
|
|
53
56
|
module.exports = MochaReporter;
|