@testomatio/reporter 2.19.0 → 2.21.0
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/lib/adapter/codecept.js +26 -2
- package/lib/adapter/cucumber/current.js +1 -0
- package/lib/adapter/cypress-plugin/index.js +1 -0
- package/lib/adapter/e2e.d.ts +49 -0
- package/lib/adapter/e2e.js +254 -0
- package/lib/adapter/jasmine.js +1 -0
- package/lib/adapter/jest.js +1 -0
- package/lib/adapter/mocha.d.ts +4 -1
- package/lib/adapter/mocha.js +123 -122
- package/lib/adapter/nightwatch.js +1 -0
- package/lib/adapter/playwright.js +33 -1
- package/lib/adapter/vitest.js +5 -1
- package/lib/adapter/webdriver.js +45 -2
- package/lib/allureReader.d.ts +4 -1
- package/lib/allureReader.js +2 -1
- package/lib/bin/cli.js +212 -19
- package/lib/client.d.ts +1 -0
- package/lib/client.js +12 -3
- package/lib/data-storage.js +4 -3
- package/lib/fetch/report.d.ts +31 -0
- package/lib/fetch/report.js +81 -0
- package/lib/fetch/testruns.d.ts +133 -0
- package/lib/fetch/testruns.js +286 -0
- package/lib/pipe/markdown.d.ts +1 -0
- package/lib/pipe/markdown.js +7 -0
- package/lib/pipe/testomatio.js +17 -1
- package/lib/replay.js +1 -0
- package/lib/reporter-functions.js +39 -0
- package/lib/uploader.d.ts +17 -0
- package/lib/uploader.js +75 -1
- package/lib/utils/detectRunner.d.ts +23 -0
- package/lib/utils/detectRunner.js +149 -0
- package/lib/utils/pipe_utils.d.ts +16 -3
- package/lib/utils/pipe_utils.js +45 -4
- package/lib/xmlReader.js +2 -0
- package/package.json +8 -3
- package/src/adapter/codecept.js +24 -2
- package/src/adapter/cucumber/current.js +2 -0
- package/src/adapter/cypress-plugin/index.js +2 -0
- package/src/adapter/e2e.js +248 -0
- package/src/adapter/jasmine.js +2 -0
- package/src/adapter/jest.js +2 -0
- package/src/adapter/mocha.js +146 -145
- package/src/adapter/nightwatch.js +2 -0
- package/src/adapter/playwright.js +33 -1
- package/src/adapter/vitest.js +6 -1
- package/src/adapter/webdriver.js +46 -2
- package/src/allureReader.js +2 -1
- package/src/bin/cli.js +246 -18
- package/src/client.js +11 -3
- package/src/data-storage.js +4 -3
- package/src/fetch/report.js +86 -0
- package/src/fetch/testruns.js +283 -0
- package/src/pipe/markdown.js +7 -0
- package/src/pipe/testomatio.js +27 -1
- package/src/replay.js +1 -0
- package/src/reporter-functions.js +41 -0
- package/src/uploader.js +81 -1
- package/src/utils/detectRunner.js +151 -0
- package/src/utils/pipe_utils.js +45 -4
- package/src/xmlReader.js +3 -0
- package/types/types.d.ts +1 -0
package/src/adapter/mocha.js
CHANGED
|
@@ -6,6 +6,8 @@ import { config } from '../config.js';
|
|
|
6
6
|
import { services } from '../services/index.js';
|
|
7
7
|
import pc from 'picocolors';
|
|
8
8
|
|
|
9
|
+
global.TESTOMATIO_ADAPTER = 'mocha';
|
|
10
|
+
|
|
9
11
|
const {
|
|
10
12
|
EVENT_RUN_BEGIN,
|
|
11
13
|
EVENT_RUN_END,
|
|
@@ -18,157 +20,160 @@ const {
|
|
|
18
20
|
EVENT_TEST_END,
|
|
19
21
|
} = Mocha.Runner.constants;
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
23
|
+
// ES class so it works with mocha 12, where Base is a class and utils.inherits is gone
|
|
24
|
+
class MochaReporter extends Mocha.reporters.Base {
|
|
25
|
+
constructor(runner, opts) {
|
|
26
|
+
super(runner, opts);
|
|
27
|
+
let passes = 0;
|
|
28
|
+
let failures = 0;
|
|
29
|
+
let skipped = 0;
|
|
30
|
+
// let artifactStore;
|
|
31
|
+
|
|
32
|
+
const apiKey = opts?.reporterOptions?.apiKey || config.TESTOMATIO;
|
|
33
|
+
|
|
34
|
+
const client = new TestomatClient({ apiKey });
|
|
35
|
+
|
|
36
|
+
// Track hook failures
|
|
37
|
+
const hookFailures = new Map();
|
|
38
|
+
|
|
39
|
+
runner.on(EVENT_RUN_BEGIN, () => {
|
|
40
|
+
client.createRun();
|
|
41
|
+
|
|
42
|
+
// clear dir with artifacts/logs
|
|
43
|
+
fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
runner.on(EVENT_SUITE_BEGIN, async suite => {
|
|
47
|
+
services.setContext(suite.fullTitle());
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
runner.on(EVENT_SUITE_END, async suite => {
|
|
51
|
+
if (hookFailures.has(suite.fullTitle())) {
|
|
52
|
+
const { error, suiteTitle } = hookFailures.get(suite.fullTitle());
|
|
53
|
+
|
|
54
|
+
for (const test of suite.tests) {
|
|
55
|
+
if (test.state === 'pending' || !test.state) {
|
|
56
|
+
const testId = getTestomatIdFromTestTitle(test.title);
|
|
57
|
+
const artifacts = services.artifacts.get(test.fullTitle());
|
|
58
|
+
const keyValues = services.keyValues.get(test.fullTitle());
|
|
59
|
+
const links = services.links.get(test.fullTitle());
|
|
60
|
+
|
|
61
|
+
client.addTestRun(STATUS.FAILED, {
|
|
62
|
+
error,
|
|
63
|
+
suite_title: suiteTitle || suite.title,
|
|
64
|
+
file: suite.file,
|
|
65
|
+
test_id: testId,
|
|
66
|
+
title: test.title,
|
|
67
|
+
code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
|
|
68
|
+
time: 0,
|
|
69
|
+
manuallyAttachedArtifacts: artifacts,
|
|
70
|
+
meta: keyValues,
|
|
71
|
+
links,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
69
74
|
}
|
|
70
75
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
services.setContext(null);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
runner.on(EVENT_TEST_PASS, async test => {
|
|
85
|
-
passes += 1;
|
|
86
|
-
|
|
87
|
-
console.log(pc.bold(pc.green('✔')), test.fullTitle());
|
|
88
|
-
const testId = getTestomatIdFromTestTitle(test.title);
|
|
89
|
-
|
|
90
|
-
const logs = getTestLogs(test);
|
|
91
|
-
const artifacts = services.artifacts.get(test.fullTitle());
|
|
92
|
-
const keyValues = services.keyValues.get(test.fullTitle());
|
|
93
|
-
const links = services.links.get(test.fullTitle());
|
|
94
|
-
|
|
95
|
-
client.addTestRun(STATUS.PASSED, {
|
|
96
|
-
test_id: testId,
|
|
97
|
-
suite_title: getSuiteTitle(test),
|
|
98
|
-
title: getTestName(test),
|
|
99
|
-
code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
|
|
100
|
-
file: getFile(test),
|
|
101
|
-
time: test.duration,
|
|
102
|
-
logs,
|
|
103
|
-
manuallyAttachedArtifacts: artifacts,
|
|
104
|
-
meta: keyValues,
|
|
105
|
-
links,
|
|
76
|
+
|
|
77
|
+
services.setContext(null);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
runner.on(EVENT_TEST_BEGIN, async test => {
|
|
81
|
+
services.setContext(test.fullTitle());
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
runner.on(EVENT_TEST_END, async () => {
|
|
85
|
+
services.setContext(null);
|
|
106
86
|
});
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
87
|
+
|
|
88
|
+
runner.on(EVENT_TEST_PASS, async test => {
|
|
89
|
+
passes += 1;
|
|
90
|
+
|
|
91
|
+
console.log(pc.bold(pc.green('✔')), test.fullTitle());
|
|
92
|
+
const testId = getTestomatIdFromTestTitle(test.title);
|
|
93
|
+
|
|
94
|
+
const logs = getTestLogs(test);
|
|
95
|
+
const artifacts = services.artifacts.get(test.fullTitle());
|
|
96
|
+
const keyValues = services.keyValues.get(test.fullTitle());
|
|
97
|
+
const links = services.links.get(test.fullTitle());
|
|
98
|
+
|
|
99
|
+
client.addTestRun(STATUS.PASSED, {
|
|
100
|
+
test_id: testId,
|
|
101
|
+
suite_title: getSuiteTitle(test),
|
|
102
|
+
title: getTestName(test),
|
|
103
|
+
code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
|
|
104
|
+
file: getFile(test),
|
|
105
|
+
time: test.duration,
|
|
106
|
+
logs,
|
|
107
|
+
manuallyAttachedArtifacts: artifacts,
|
|
108
|
+
meta: keyValues,
|
|
109
|
+
links,
|
|
110
|
+
});
|
|
127
111
|
});
|
|
128
|
-
});
|
|
129
112
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
113
|
+
runner.on(EVENT_TEST_PENDING, test => {
|
|
114
|
+
skipped += 1;
|
|
115
|
+
console.log('skip: %s', test.fullTitle());
|
|
116
|
+
const testId = getTestomatIdFromTestTitle(test.title);
|
|
117
|
+
const artifacts = services.artifacts.get(test.fullTitle());
|
|
118
|
+
const keyValues = services.keyValues.get(test.fullTitle());
|
|
119
|
+
const links = services.links.get(test.fullTitle());
|
|
120
|
+
|
|
121
|
+
client.addTestRun(STATUS.SKIPPED, {
|
|
122
|
+
title: getTestName(test),
|
|
123
|
+
suite_title: getSuiteTitle(test),
|
|
124
|
+
code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
|
|
125
|
+
file: getFile(test),
|
|
126
|
+
test_id: testId,
|
|
127
|
+
time: test.duration,
|
|
128
|
+
manuallyAttachedArtifacts: artifacts,
|
|
129
|
+
meta: keyValues,
|
|
130
|
+
links,
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
runner.on(EVENT_TEST_FAIL, async (test, err) => {
|
|
135
|
+
failures += 1;
|
|
136
|
+
console.log(pc.bold(pc.red('✖')), test.fullTitle(), pc.gray(err.message));
|
|
137
|
+
|
|
138
|
+
const isHookFailure = test.title.includes('before each') || test.title.includes('after each');
|
|
133
139
|
|
|
134
|
-
|
|
140
|
+
if (isHookFailure && test.parent) {
|
|
141
|
+
hookFailures.set(test.parent.fullTitle(), {
|
|
142
|
+
error: err,
|
|
143
|
+
suiteTitle: getSuiteTitle(test),
|
|
144
|
+
});
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const testId = getTestomatIdFromTestTitle(test.title);
|
|
135
149
|
|
|
136
|
-
|
|
137
|
-
|
|
150
|
+
const logs = getTestLogs(test);
|
|
151
|
+
const artifacts = services.artifacts.get(test.fullTitle());
|
|
152
|
+
const keyValues = services.keyValues.get(test.fullTitle());
|
|
153
|
+
const links = services.links.get(test.fullTitle());
|
|
154
|
+
|
|
155
|
+
client.addTestRun(STATUS.FAILED, {
|
|
138
156
|
error: err,
|
|
139
|
-
|
|
157
|
+
suite_title: getSuiteTitle(test),
|
|
158
|
+
file: getFile(test),
|
|
159
|
+
test_id: testId,
|
|
160
|
+
title: getTestName(test),
|
|
161
|
+
code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
|
|
162
|
+
time: test.duration,
|
|
163
|
+
logs,
|
|
164
|
+
manuallyAttachedArtifacts: artifacts,
|
|
165
|
+
meta: keyValues,
|
|
166
|
+
links,
|
|
140
167
|
});
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const testId = getTestomatIdFromTestTitle(test.title);
|
|
145
|
-
|
|
146
|
-
const logs = getTestLogs(test);
|
|
147
|
-
const artifacts = services.artifacts.get(test.fullTitle());
|
|
148
|
-
const keyValues = services.keyValues.get(test.fullTitle());
|
|
149
|
-
const links = services.links.get(test.fullTitle());
|
|
150
|
-
|
|
151
|
-
client.addTestRun(STATUS.FAILED, {
|
|
152
|
-
error: err,
|
|
153
|
-
suite_title: getSuiteTitle(test),
|
|
154
|
-
file: getFile(test),
|
|
155
|
-
test_id: testId,
|
|
156
|
-
title: getTestName(test),
|
|
157
|
-
code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
|
|
158
|
-
time: test.duration,
|
|
159
|
-
logs,
|
|
160
|
-
manuallyAttachedArtifacts: artifacts,
|
|
161
|
-
meta: keyValues,
|
|
162
|
-
links,
|
|
163
168
|
});
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
169
|
+
|
|
170
|
+
runner.on(EVENT_RUN_END, () => {
|
|
171
|
+
const status = failures === 0 ? STATUS.PASSED : STATUS.FAILED;
|
|
172
|
+
console.log(pc.bold(status), `${passes} passed, ${failures} failed, ${skipped} skipped`);
|
|
173
|
+
// @ts-ignore
|
|
174
|
+
client.updateRunStatus(status);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
172
177
|
}
|
|
173
178
|
|
|
174
179
|
function getTestLogs(test) {
|
|
@@ -204,8 +209,4 @@ function getTestName(test) {
|
|
|
204
209
|
return test.title;
|
|
205
210
|
}
|
|
206
211
|
|
|
207
|
-
// To have this reporter "extend" a built-in reporter uncomment the following line:
|
|
208
|
-
// @ts-ignore
|
|
209
|
-
Mocha.utils.inherits(MochaReporter, Mocha.reporters.Spec);
|
|
210
|
-
|
|
211
212
|
export default MochaReporter;
|
|
@@ -3,6 +3,8 @@ import { config } from '../config.js';
|
|
|
3
3
|
import { STATUS } from '../constants.js';
|
|
4
4
|
import { getTestomatIdFromTestTitle } from '../utils/utils.js';
|
|
5
5
|
|
|
6
|
+
global.TESTOMATIO_ADAPTER = 'nightwatch';
|
|
7
|
+
|
|
6
8
|
const apiKey = config.TESTOMATIO;
|
|
7
9
|
const client = new TestomatClient({ apiKey });
|
|
8
10
|
|
|
@@ -14,6 +14,8 @@ import { fetchLinksFromLogs } from './utils/playwright.js';
|
|
|
14
14
|
import { formatStep, addStatusToStep, addArtifactsToStep } from './utils/step-formatter.js';
|
|
15
15
|
import { log } from '../utils/log.js';
|
|
16
16
|
|
|
17
|
+
global.TESTOMATIO_ADAPTER = 'playwright';
|
|
18
|
+
|
|
17
19
|
class PlaywrightReporter {
|
|
18
20
|
constructor(config = {}) {
|
|
19
21
|
this.client = new TestomatioClient({ apiKey: config?.apiKey });
|
|
@@ -108,7 +110,11 @@ class PlaywrightReporter {
|
|
|
108
110
|
if (result.status === 'passed') status = 'failed';
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
const
|
|
113
|
+
const testStatus = checkStatus(status);
|
|
114
|
+
let failedUrl;
|
|
115
|
+
if (testStatus === Status.FAILED) failedUrl = lastNavigatedUrl(result.steps, test.parent.project().use.baseURL);
|
|
116
|
+
|
|
117
|
+
const reportTestPromise = this.client.addTestRun(testStatus, {
|
|
112
118
|
rid: `${rid}-${project.name}`,
|
|
113
119
|
error,
|
|
114
120
|
test_id: getTestomatIdFromTestTitle(`${title} ${tags.join(' ')}`),
|
|
@@ -126,6 +132,7 @@ class PlaywrightReporter {
|
|
|
126
132
|
isMobile: project.isMobile,
|
|
127
133
|
project: project.name,
|
|
128
134
|
projectDependencies: project.dependencies?.length ? project.dependencies : null,
|
|
135
|
+
failedUrl,
|
|
129
136
|
...testMeta,
|
|
130
137
|
...meta,
|
|
131
138
|
...project.metadata, // metadata has any type (in playwright), but we will stringify it in client.js
|
|
@@ -242,6 +249,31 @@ function isScreenshotArtifact(attachment) {
|
|
|
242
249
|
return attachment?.contentType === 'image/png' && attachment?.name === 'screenshot';
|
|
243
250
|
}
|
|
244
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Last url the test navigated to; the reporter has no access to the page itself.
|
|
254
|
+
* @returns {string|undefined}
|
|
255
|
+
*/
|
|
256
|
+
function lastNavigatedUrl(steps, baseURL) {
|
|
257
|
+
const url = findLastNavigation(steps);
|
|
258
|
+
if (!url) return;
|
|
259
|
+
try {
|
|
260
|
+
return new URL(url, baseURL).href;
|
|
261
|
+
} catch {
|
|
262
|
+
return url;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function findLastNavigation(steps = []) {
|
|
267
|
+
let url;
|
|
268
|
+
for (const step of steps) {
|
|
269
|
+
// 'Navigate to "url"' since Playwright 1.53, 'page.goto(url)' before
|
|
270
|
+
const match = step.title.match(/^Navigate to "(.+)"$/) || step.title.match(/^page\.goto\((.+)\)$/);
|
|
271
|
+
if (step.category === 'pw:api' && match) url = match[1];
|
|
272
|
+
url = findLastNavigation(step.steps) || url;
|
|
273
|
+
}
|
|
274
|
+
return url;
|
|
275
|
+
}
|
|
276
|
+
|
|
245
277
|
function appendStep(step, shift = 0) {
|
|
246
278
|
// nesting too deep, ignore those steps
|
|
247
279
|
if (shift >= 10) return;
|
package/src/adapter/vitest.js
CHANGED
|
@@ -6,6 +6,8 @@ import createDebugMessages from 'debug';
|
|
|
6
6
|
|
|
7
7
|
const debug = createDebugMessages('@testomatio/reporter:adapter-jest');
|
|
8
8
|
|
|
9
|
+
global.TESTOMATIO_ADAPTER = 'vitest';
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* @typedef {import('../../types/types.js').VitestTest} VitestTest
|
|
11
13
|
* @typedef {import('../../types/types.js').VitestTestFile} VitestTestFile
|
|
@@ -396,7 +398,10 @@ function normalizeVitestTest(test) {
|
|
|
396
398
|
file,
|
|
397
399
|
suiteTitle,
|
|
398
400
|
logs: '',
|
|
399
|
-
meta:
|
|
401
|
+
meta: {
|
|
402
|
+
...(test.task?.meta || {}),
|
|
403
|
+
...(typeof test.meta === 'function' ? test.meta() : test.meta || {}),
|
|
404
|
+
},
|
|
400
405
|
};
|
|
401
406
|
}
|
|
402
407
|
|
package/src/adapter/webdriver.js
CHANGED
|
@@ -4,6 +4,11 @@ import { getTestomatIdFromTestTitle, fileSystem } from '../utils/utils.js';
|
|
|
4
4
|
import { services } from '../services/index.js';
|
|
5
5
|
import { TESTOMAT_TMP_STORAGE_DIR } from '../constants.js';
|
|
6
6
|
import { stringToMD5Hash } from '../data-storage.js';
|
|
7
|
+
import createDebugMessages from 'debug';
|
|
8
|
+
|
|
9
|
+
const debug = createDebugMessages('@testomatio/reporter:adapter:webdriver');
|
|
10
|
+
|
|
11
|
+
global.TESTOMATIO_ADAPTER = 'webdriverio';
|
|
7
12
|
|
|
8
13
|
class WebdriverReporter extends WDIOReporter {
|
|
9
14
|
constructor(options) {
|
|
@@ -120,7 +125,8 @@ class WebdriverReporter extends WDIOReporter {
|
|
|
120
125
|
async addTest(test) {
|
|
121
126
|
if (!this.client) return;
|
|
122
127
|
|
|
123
|
-
const { title, _duration: duration, state, error, output, links, artifacts,
|
|
128
|
+
const { title, _duration: duration, state, error, output, links, artifacts, logs } = test;
|
|
129
|
+
let { meta } = test;
|
|
124
130
|
|
|
125
131
|
const testId = getTestomatIdFromTestTitle(title);
|
|
126
132
|
|
|
@@ -131,6 +137,11 @@ class WebdriverReporter extends WDIOReporter {
|
|
|
131
137
|
|
|
132
138
|
const rid = stringToMD5Hash(test.fullTitle);
|
|
133
139
|
|
|
140
|
+
if (state === 'failed') {
|
|
141
|
+
const failedUrl = (await grabCurrentUrl()) || lastNavigatedUrl(output);
|
|
142
|
+
if (failedUrl) meta = { ...meta, failedUrl };
|
|
143
|
+
}
|
|
144
|
+
|
|
134
145
|
await this.client.addTestRun(state, {
|
|
135
146
|
rid,
|
|
136
147
|
manuallyAttachedArtifacts: test.artifacts,
|
|
@@ -148,7 +159,7 @@ class WebdriverReporter extends WDIOReporter {
|
|
|
148
159
|
/**
|
|
149
160
|
* @param {import('../../types/types.js').WebdriverIOScenario} scenario
|
|
150
161
|
*/
|
|
151
|
-
addBddScenario(scenario) {
|
|
162
|
+
async addBddScenario(scenario) {
|
|
152
163
|
if (!this.client) return;
|
|
153
164
|
|
|
154
165
|
const { title, _duration: duration } = scenario;
|
|
@@ -167,6 +178,12 @@ class WebdriverReporter extends WDIOReporter {
|
|
|
167
178
|
|
|
168
179
|
const tags = scenario.tags.map(tag => tag.name);
|
|
169
180
|
|
|
181
|
+
let meta;
|
|
182
|
+
if (scenarioState === 'failed') {
|
|
183
|
+
const failedUrl = await grabCurrentUrl();
|
|
184
|
+
if (failedUrl) meta = { failedUrl };
|
|
185
|
+
}
|
|
186
|
+
|
|
170
187
|
return this.client.addTestRun(scenarioState, {
|
|
171
188
|
error: error ? Error(error) : null,
|
|
172
189
|
title,
|
|
@@ -174,11 +191,38 @@ class WebdriverReporter extends WDIOReporter {
|
|
|
174
191
|
time: duration,
|
|
175
192
|
tags,
|
|
176
193
|
file: scenario.file,
|
|
194
|
+
meta,
|
|
177
195
|
// filesBuffers: screenshotsBuffers,
|
|
178
196
|
});
|
|
179
197
|
}
|
|
180
198
|
}
|
|
181
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Current url of the browser in this worker; reporters run in the worker process.
|
|
202
|
+
* @returns {Promise<string|undefined>}
|
|
203
|
+
*/
|
|
204
|
+
async function grabCurrentUrl() {
|
|
205
|
+
// @ts-ignore
|
|
206
|
+
const browser = globalThis.browser;
|
|
207
|
+
if (typeof browser?.getUrl !== 'function') return;
|
|
208
|
+
try {
|
|
209
|
+
const url = await browser.getUrl();
|
|
210
|
+
// multiremote returns a url per browser
|
|
211
|
+
if (typeof url === 'string') return url;
|
|
212
|
+
} catch (err) {
|
|
213
|
+
debug('Failed to grab url of failed test', err?.message || err);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Last url opened by the test, taken from its command log.
|
|
219
|
+
* @returns {string|undefined}
|
|
220
|
+
*/
|
|
221
|
+
function lastNavigatedUrl(output = []) {
|
|
222
|
+
const navigations = output.filter(el => el.endpoint === '/session/:sessionId/url' && el.body?.url);
|
|
223
|
+
return navigations.at(-1)?.body.url;
|
|
224
|
+
}
|
|
225
|
+
|
|
182
226
|
/**
|
|
183
227
|
*
|
|
184
228
|
* @param {*} fullTestTitle
|
package/src/allureReader.js
CHANGED
|
@@ -186,7 +186,8 @@ class AllureReader {
|
|
|
186
186
|
steps: this.convertSteps(result.steps || [], resultsDir),
|
|
187
187
|
message: result.statusDetails?.message || '',
|
|
188
188
|
stack: result.statusDetails?.trace || '',
|
|
189
|
-
meta
|
|
189
|
+
// meta must always include reporter version and adapter used
|
|
190
|
+
meta: { ...this.extractMeta(result), reporterVersion: this.version, adapter: 'allure' },
|
|
190
191
|
links: this.extractLinks(result),
|
|
191
192
|
artifacts: [],
|
|
192
193
|
create: true,
|