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