@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.
Files changed (62) hide show
  1. package/lib/adapter/codecept.js +26 -2
  2. package/lib/adapter/cucumber/current.js +1 -0
  3. package/lib/adapter/cypress-plugin/index.js +1 -0
  4. package/lib/adapter/e2e.d.ts +49 -0
  5. package/lib/adapter/e2e.js +254 -0
  6. package/lib/adapter/jasmine.js +1 -0
  7. package/lib/adapter/jest.js +1 -0
  8. package/lib/adapter/mocha.d.ts +4 -1
  9. package/lib/adapter/mocha.js +123 -122
  10. package/lib/adapter/nightwatch.js +1 -0
  11. package/lib/adapter/playwright.js +33 -1
  12. package/lib/adapter/vitest.js +5 -1
  13. package/lib/adapter/webdriver.js +45 -2
  14. package/lib/allureReader.d.ts +4 -1
  15. package/lib/allureReader.js +2 -1
  16. package/lib/bin/cli.js +212 -19
  17. package/lib/client.d.ts +1 -0
  18. package/lib/client.js +12 -3
  19. package/lib/data-storage.js +4 -3
  20. package/lib/fetch/report.d.ts +31 -0
  21. package/lib/fetch/report.js +81 -0
  22. package/lib/fetch/testruns.d.ts +133 -0
  23. package/lib/fetch/testruns.js +286 -0
  24. package/lib/pipe/markdown.d.ts +1 -0
  25. package/lib/pipe/markdown.js +7 -0
  26. package/lib/pipe/testomatio.js +17 -1
  27. package/lib/replay.js +1 -0
  28. package/lib/reporter-functions.js +39 -0
  29. package/lib/uploader.d.ts +17 -0
  30. package/lib/uploader.js +75 -1
  31. package/lib/utils/detectRunner.d.ts +23 -0
  32. package/lib/utils/detectRunner.js +149 -0
  33. package/lib/utils/pipe_utils.d.ts +16 -3
  34. package/lib/utils/pipe_utils.js +45 -4
  35. package/lib/xmlReader.js +2 -0
  36. package/package.json +8 -3
  37. package/src/adapter/codecept.js +24 -2
  38. package/src/adapter/cucumber/current.js +2 -0
  39. package/src/adapter/cypress-plugin/index.js +2 -0
  40. package/src/adapter/e2e.js +248 -0
  41. package/src/adapter/jasmine.js +2 -0
  42. package/src/adapter/jest.js +2 -0
  43. package/src/adapter/mocha.js +146 -145
  44. package/src/adapter/nightwatch.js +2 -0
  45. package/src/adapter/playwright.js +33 -1
  46. package/src/adapter/vitest.js +6 -1
  47. package/src/adapter/webdriver.js +46 -2
  48. package/src/allureReader.js +2 -1
  49. package/src/bin/cli.js +246 -18
  50. package/src/client.js +11 -3
  51. package/src/data-storage.js +4 -3
  52. package/src/fetch/report.js +86 -0
  53. package/src/fetch/testruns.js +283 -0
  54. package/src/pipe/markdown.js +7 -0
  55. package/src/pipe/testomatio.js +27 -1
  56. package/src/replay.js +1 -0
  57. package/src/reporter-functions.js +41 -0
  58. package/src/uploader.js +81 -1
  59. package/src/utils/detectRunner.js +151 -0
  60. package/src/utils/pipe_utils.js +45 -4
  61. package/src/xmlReader.js +3 -0
  62. package/types/types.d.ts +1 -0
@@ -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
- function MochaReporter(runner, opts) {
15
- mocha_1.default.reporters.Base.call(this, runner);
16
- let passes = 0;
17
- let failures = 0;
18
- let skipped = 0;
19
- // let artifactStore;
20
- const apiKey = opts?.reporterOptions?.apiKey || config_js_1.config.TESTOMATIO;
21
- const client = new client_js_1.default({ apiKey });
22
- // Track hook failures
23
- const hookFailures = new Map();
24
- runner.on(EVENT_RUN_BEGIN, () => {
25
- client.createRun();
26
- // clear dir with artifacts/logs
27
- utils_js_1.fileSystem.clearDir(constants_js_1.TESTOMAT_TMP_STORAGE_DIR);
28
- });
29
- runner.on(EVENT_SUITE_BEGIN, async (suite) => {
30
- index_js_1.services.setContext(suite.fullTitle());
31
- });
32
- runner.on(EVENT_SUITE_END, async (suite) => {
33
- if (hookFailures.has(suite.fullTitle())) {
34
- const { error, suiteTitle } = hookFailures.get(suite.fullTitle());
35
- for (const test of suite.tests) {
36
- if (test.state === 'pending' || !test.state) {
37
- const testId = (0, utils_js_1.getTestomatIdFromTestTitle)(test.title);
38
- const artifacts = index_js_1.services.artifacts.get(test.fullTitle());
39
- const keyValues = index_js_1.services.keyValues.get(test.fullTitle());
40
- const links = index_js_1.services.links.get(test.fullTitle());
41
- client.addTestRun(constants_js_1.STATUS.FAILED, {
42
- error,
43
- suite_title: suiteTitle || suite.title,
44
- file: suite.file,
45
- test_id: testId,
46
- title: test.title,
47
- code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
48
- time: 0,
49
- manuallyAttachedArtifacts: artifacts,
50
- meta: keyValues,
51
- links,
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
- index_js_1.services.setContext(null);
57
- });
58
- runner.on(EVENT_TEST_BEGIN, async (test) => {
59
- index_js_1.services.setContext(test.fullTitle());
60
- });
61
- runner.on(EVENT_TEST_END, async () => {
62
- index_js_1.services.setContext(null);
63
- });
64
- runner.on(EVENT_TEST_PASS, async (test) => {
65
- passes += 1;
66
- console.log(picocolors_1.default.bold(picocolors_1.default.green('✔')), test.fullTitle());
67
- const testId = (0, utils_js_1.getTestomatIdFromTestTitle)(test.title);
68
- const logs = getTestLogs(test);
69
- const artifacts = index_js_1.services.artifacts.get(test.fullTitle());
70
- const keyValues = index_js_1.services.keyValues.get(test.fullTitle());
71
- const links = index_js_1.services.links.get(test.fullTitle());
72
- client.addTestRun(constants_js_1.STATUS.PASSED, {
73
- test_id: testId,
74
- suite_title: getSuiteTitle(test),
75
- title: getTestName(test),
76
- code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
77
- file: getFile(test),
78
- time: test.duration,
79
- logs,
80
- manuallyAttachedArtifacts: artifacts,
81
- meta: keyValues,
82
- links,
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
- runner.on(EVENT_TEST_PENDING, test => {
86
- skipped += 1;
87
- console.log('skip: %s', test.fullTitle());
88
- const testId = (0, utils_js_1.getTestomatIdFromTestTitle)(test.title);
89
- const artifacts = index_js_1.services.artifacts.get(test.fullTitle());
90
- const keyValues = index_js_1.services.keyValues.get(test.fullTitle());
91
- const links = index_js_1.services.links.get(test.fullTitle());
92
- client.addTestRun(constants_js_1.STATUS.SKIPPED, {
93
- title: getTestName(test),
94
- suite_title: getSuiteTitle(test),
95
- code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
96
- file: getFile(test),
97
- test_id: testId,
98
- time: test.duration,
99
- manuallyAttachedArtifacts: artifacts,
100
- meta: keyValues,
101
- links,
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
- runner.on(EVENT_TEST_FAIL, async (test, err) => {
105
- failures += 1;
106
- console.log(picocolors_1.default.bold(picocolors_1.default.red('✖')), test.fullTitle(), picocolors_1.default.gray(err.message));
107
- const isHookFailure = test.title.includes('before each') || test.title.includes('after each');
108
- if (isHookFailure && test.parent) {
109
- hookFailures.set(test.parent.fullTitle(), {
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
- suiteTitle: getSuiteTitle(test),
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
- runner.on(EVENT_RUN_END, () => {
135
- const status = failures === 0 ? constants_js_1.STATUS.PASSED : constants_js_1.STATUS.FAILED;
136
- console.log(picocolors_1.default.bold(status), `${passes} passed, ${failures} failed, ${skipped} skipped`);
137
- // @ts-ignore
138
- client.updateRunStatus(status);
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 reportTestPromise = this.client.addTestRun(checkStatus(status), {
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)
@@ -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: typeof test.meta === 'function' ? test.meta() : {},
397
+ meta: {
398
+ ...(test.task?.meta || {}),
399
+ ...(typeof test.meta === 'function' ? test.meta() : test.meta || {}),
400
+ },
397
401
  };
398
402
  }
399
403
  return {
@@ -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, meta, logs } = test;
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
@@ -35,7 +35,10 @@ declare class AllureReader {
35
35
  steps: any;
36
36
  message: any;
37
37
  stack: any;
38
- meta: {};
38
+ meta: {
39
+ reporterVersion: any;
40
+ adapter: string;
41
+ };
39
42
  links: {
40
43
  label: string;
41
44
  }[];
@@ -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: this.extractMeta(result),
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,