@testomatio/reporter 2.19.0 → 2.20.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 (48) hide show
  1. package/lib/adapter/codecept.js +1 -0
  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 +250 -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 +1 -0
  12. package/lib/adapter/vitest.js +1 -0
  13. package/lib/adapter/webdriver.js +1 -0
  14. package/lib/allureReader.d.ts +4 -1
  15. package/lib/allureReader.js +2 -1
  16. package/lib/bin/cli.js +32 -13
  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/pipe/testomatio.js +17 -1
  21. package/lib/replay.js +1 -0
  22. package/lib/uploader.d.ts +1 -0
  23. package/lib/uploader.js +21 -1
  24. package/lib/utils/pipe_utils.d.ts +16 -3
  25. package/lib/utils/pipe_utils.js +45 -4
  26. package/lib/xmlReader.js +2 -0
  27. package/package.json +7 -2
  28. package/src/adapter/codecept.js +2 -0
  29. package/src/adapter/cucumber/current.js +2 -0
  30. package/src/adapter/cypress-plugin/index.js +2 -0
  31. package/src/adapter/e2e.js +245 -0
  32. package/src/adapter/jasmine.js +2 -0
  33. package/src/adapter/jest.js +2 -0
  34. package/src/adapter/mocha.js +146 -145
  35. package/src/adapter/nightwatch.js +2 -0
  36. package/src/adapter/playwright.js +2 -0
  37. package/src/adapter/vitest.js +2 -0
  38. package/src/adapter/webdriver.js +2 -0
  39. package/src/allureReader.js +2 -1
  40. package/src/bin/cli.js +30 -11
  41. package/src/client.js +11 -3
  42. package/src/data-storage.js +4 -3
  43. package/src/pipe/testomatio.js +27 -1
  44. package/src/replay.js +1 -0
  45. package/src/uploader.js +30 -1
  46. package/src/utils/pipe_utils.js +45 -4
  47. package/src/xmlReader.js +3 -0
  48. package/types/types.d.ts +1 -0
@@ -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,
package/lib/bin/cli.js CHANGED
@@ -121,35 +121,54 @@ program
121
121
  program
122
122
  .command('fetch')
123
123
  .description('Fetch runs from Testomat.io API v2')
124
+ .argument('[url]', 'URL of a run or of a (filtered) runs page in Testomat.io')
124
125
  .option('--project <slug>', 'Project slug (or set TESTOMATIO_PROJECT)')
126
+ .option('--run <id>', 'Fetch a single run by its id')
125
127
  .option('--title <text>', 'Filter by run title')
126
128
  .option('--tql <query>', 'Filter using Testomat Query Language')
127
129
  .option('--rungroup <uid>', 'Filter by rungroup id')
128
130
  .option('--limit <number>', `Max number of runs to return (max ${FETCH_RUNS_MAX_LIMIT})`, String(FETCH_RUNS_DEFAULT_LIMIT))
129
131
  .option('--latest', 'Only fetch the most recent run (shorthand for --limit 1)')
130
132
  .option('--format <format>', 'Machine-readable output: run ids, one per line (--format id) or run details (--format json)')
131
- .action(async (opts) => {
133
+ .action(async (pageUrl, opts) => {
132
134
  const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config_js_1.config.TESTOMATIO;
133
135
  if (!apiKey) {
134
136
  log_js_1.log.error(picocolors_1.default.red('⚠️ TESTOMATIO API key required'));
135
137
  process.exit(1);
136
138
  }
137
- const project = opts.project || process.env.TESTOMATIO_PROJECT;
139
+ let page = {};
140
+ if (pageUrl) {
141
+ page = (0, pipe_utils_js_1.parseRunsUrl)(pageUrl);
142
+ if (!page) {
143
+ log_js_1.log.error(picocolors_1.default.red(`⚠️ Not a Testomat.io run or runs page URL: ${pageUrl}`));
144
+ process.exit(1);
145
+ }
146
+ }
147
+ const project = opts.project || page.project || process.env.TESTOMATIO_PROJECT;
138
148
  if (!project) {
139
149
  log_js_1.log.error(picocolors_1.default.red('⚠️ --project (or TESTOMATIO_PROJECT) is required'));
140
150
  process.exit(1);
141
151
  }
142
- const baseUrl = process.env.TESTOMATIO_URL || 'https://app.testomat.io';
143
- const url = new URL(`/api/v2/${project}/runs`, baseUrl);
144
- if (opts.title)
145
- url.searchParams.set('search', opts.title);
146
- if (opts.tql)
147
- url.searchParams.set('tql', opts.tql);
148
- if (opts.rungroup)
149
- url.searchParams.set('groupId', opts.rungroup);
150
- const requestedLimit = opts.latest ? 1 : parseInt(opts.limit, 10) || FETCH_RUNS_DEFAULT_LIMIT;
151
- const limit = Math.min(Math.max(requestedLimit, 1), FETCH_RUNS_MAX_LIMIT);
152
- url.searchParams.set('per_page', String(limit));
152
+ const baseUrl = page.baseUrl || process.env.TESTOMATIO_URL || 'https://app.testomat.io';
153
+ const runId = opts.run || page.runId;
154
+ let url;
155
+ if (runId) {
156
+ url = new URL(`/api/v2/${project}/runs/${runId}`, baseUrl);
157
+ }
158
+ else {
159
+ url = new URL(`/api/v2/${project}/runs`, baseUrl);
160
+ for (const [key, value] of page.params || [])
161
+ url.searchParams.append(key, value);
162
+ if (opts.title)
163
+ url.searchParams.set('search', opts.title);
164
+ if (opts.tql)
165
+ url.searchParams.set('tql', opts.tql);
166
+ if (opts.rungroup)
167
+ url.searchParams.set('groupId', opts.rungroup);
168
+ const requestedLimit = opts.latest ? 1 : parseInt(opts.limit, 10) || FETCH_RUNS_DEFAULT_LIMIT;
169
+ const limit = Math.min(Math.max(requestedLimit, 1), FETCH_RUNS_MAX_LIMIT);
170
+ url.searchParams.set('per_page', String(limit));
171
+ }
153
172
  const response = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
154
173
  const body = await response.json();
155
174
  if (!response.ok) {
package/lib/client.d.ts CHANGED
@@ -15,6 +15,7 @@ export class Client {
15
15
  pipeStore: {};
16
16
  runId: string;
17
17
  queue: Promise<void>;
18
+ adapterName: any;
18
19
  version: any;
19
20
  executionList: Promise<void>;
20
21
  uploader: S3Uploader;
package/lib/client.js CHANGED
@@ -37,6 +37,8 @@ class Client {
37
37
  this.pipeStore = {};
38
38
  this.runId = '';
39
39
  this.queue = Promise.resolve();
40
+ // adapter name is set by the adapter module itself on load (global.TESTOMATIO_ADAPTER)
41
+ this.adapterName = params.adapter || global.TESTOMATIO_ADAPTER;
40
42
  // @ts-ignore this line will be removed in compiled code, because __dirname is defined in commonjs
41
43
  const pathToPackageJSON = path_1.default.join(__dirname, '../package.json');
42
44
  try {
@@ -214,7 +216,9 @@ class Client {
214
216
  const uploadedFiles = [];
215
217
  const stackArtifactsEnabled = (0, utils_js_1.transformEnvVarToBoolean)(process.env.TESTOMATIO_STACK_ARTIFACTS);
216
218
  const { time = 0, example = null, filesBuffers = [], code = null, file, suite_id, test_id, timestamp, links, overwrite, tags, } = testData;
217
- let { files = [], manuallyAttachedArtifacts, message = '', meta = {} } = testData;
219
+ let { files = [], manuallyAttachedArtifacts, message = '' } = testData;
220
+ /** @type {Record<string, any>} */
221
+ let meta = testData.meta || {};
218
222
  if (stepArtifactPaths.size) {
219
223
  const isStepArtifact = item => stepArtifactPaths.has(typeof item === 'object' ? item?.path : item);
220
224
  files = files.filter(f => !isStepArtifact(f));
@@ -229,6 +233,11 @@ class Client {
229
233
  acc[key] = value;
230
234
  return acc;
231
235
  }, {});
236
+ // meta must always include reporter version and adapter used
237
+ if (this.version)
238
+ meta.reporterVersion = this.version;
239
+ if (this.adapterName)
240
+ meta.adapter = this.adapterName;
232
241
  const testContext = suite_title ? `${suite_title} ${title}` : title;
233
242
  let errorFormatted = '';
234
243
  if (error) {
@@ -335,8 +344,8 @@ class Client {
335
344
  this.queue = this.queue
336
345
  .then(() => Promise.all(this.pipes.map(p => p.finishRun(runParams))))
337
346
  .then(() => {
338
- if (!this.uploader.isEnabled)
339
- return;
347
+ // no early return when uploading is disabled:
348
+ // skipped artifacts (e.g. no S3 credentials obtained) must still be reported to the user
340
349
  const filesizeStrMaxLength = 7;
341
350
  if (this.uploader.successfulUploads.length) {
342
351
  debug('\n', constants_js_1.APP_PREFIX, `🗄️ ${this.uploader.successfulUploads.length} artifacts uploaded to S3 bucket`);
@@ -220,9 +220,10 @@ class DataStorage {
220
220
  }
221
221
  }
222
222
  function stringToMD5Hash(str) {
223
- const md5 = crypto_1.default.createHash('md5');
224
- md5.update(str);
225
- const hash = md5.digest('hex');
223
+ // sha256 instead of md5 for FIPS-enabled hosts compatibility
224
+ const sha256 = crypto_1.default.createHash('sha256');
225
+ sha256.update(str);
226
+ const hash = sha256.digest('hex');
226
227
  return `${process.env.runId || 'run'}_${hash}`;
227
228
  }
228
229
  exports.dataStorage = DataStorage.getInstance();
@@ -317,6 +317,9 @@ class TestomatioPipe {
317
317
  (0, pipe_utils_js_1.setS3Credentials)(resp.data.artifacts);
318
318
  this.#startS3CredentialsRefresh(runParams);
319
319
  }
320
+ else {
321
+ this.#warnNoS3Credentials();
322
+ }
320
323
  if (resp.data.url) {
321
324
  const respUrl = new URL(resp.data.url);
322
325
  this.runUrl = `${this.url}${respUrl.pathname}`;
@@ -345,6 +348,9 @@ class TestomatioPipe {
345
348
  (0, pipe_utils_js_1.setS3Credentials)(resp.data.artifacts);
346
349
  this.#startS3CredentialsRefresh(runParams);
347
350
  }
351
+ else {
352
+ this.#warnNoS3Credentials();
353
+ }
348
354
  this.store.runUrl = this.runUrl;
349
355
  this.store.runPublicUrl = this.runPublicUrl;
350
356
  this.store.runId = this.runId;
@@ -403,9 +409,19 @@ class TestomatioPipe {
403
409
  }
404
410
  }
405
411
  catch (err) {
406
- debug('Failed to refresh S3 credentials:', err.message || err);
412
+ log_js_1.log.warn('⚠️ Failed to refresh S3 credentials:', err.message || err, '\nArtifact uploads may fail once the current credentials expire.');
407
413
  }
408
414
  };
415
+ /**
416
+ * Warns the user when Testomat.io did not return S3 credentials for artifacts upload.
417
+ * Skipped when artifacts uploading was intentionally disabled or a custom S3 storage is configured via env.
418
+ */
419
+ #warnNoS3Credentials() {
420
+ if (process.env.TESTOMATIO_DISABLE_ARTIFACTS || process.env.S3_BUCKET)
421
+ return;
422
+ const command = `TESTOMATIO=<your_api_key> TESTOMATIO_RUN=${this.runId || '<run_id>'} npx @testomatio/reporter upload-artifacts`;
423
+ log_js_1.log.warn(`⚠️ ${picocolors_1.default.yellow('Testomat.io did not return S3 credentials for artifacts upload.')}`, 'Artifacts will not be uploaded.', 'Please check the artifact sharing settings of your project.', `\nRun "${picocolors_1.default.magenta(command)}" later with valid S3 credentials to re-upload artifacts to this run.`);
424
+ }
409
425
  #stopS3CredentialsRefresh() {
410
426
  if (this.s3CredentialsRefreshTimer) {
411
427
  clearInterval(this.s3CredentialsRefreshTimer);
package/lib/replay.js CHANGED
@@ -231,6 +231,7 @@ class Replay {
231
231
  process.env.TESTOMATIO_REPLAY = '1';
232
232
  const client = new client_js_1.default({
233
233
  apiKey: this.apiKey,
234
+ adapter: 'replay',
234
235
  batchMode: constants_js_1.BATCH_MODE.AUTO,
235
236
  ...runParams,
236
237
  ...(runId && { runId }),
package/lib/uploader.d.ts CHANGED
@@ -10,6 +10,7 @@ export class S3Uploader {
10
10
  size: number;
11
11
  }[];
12
12
  failedUploads: any[];
13
+ warnedDisabledUpload: boolean;
13
14
  /**
14
15
  * @type {{path: string, size: number, link: string}[]}
15
16
  */
package/lib/uploader.js CHANGED
@@ -26,6 +26,7 @@ class S3Uploader {
26
26
  */
27
27
  this.skippedUploads = [];
28
28
  this.failedUploads = [];
29
+ this.warnedDisabledUpload = false;
29
30
  /**
30
31
  * @type {{path: string, size: number, link: string}[]}
31
32
  */
@@ -84,6 +85,22 @@ class S3Uploader {
84
85
  disableLogStorage() {
85
86
  this.storeEnabled = false;
86
87
  }
88
+ /**
89
+ * Warns once when artifact uploading is disabled not intentionally by the user,
90
+ * e.g. S3 credentials were not obtained from Testomat.io and no custom S3 storage is configured.
91
+ * Without this warning artifacts are skipped silently.
92
+ */
93
+ #warnDisabledUpload(runId) {
94
+ if (this.warnedDisabledUpload)
95
+ return;
96
+ const { S3_BUCKET, TESTOMATIO_DISABLE_ARTIFACTS } = this.getConfig();
97
+ // uploading was intentionally disabled by the user or a custom S3 storage is used, nothing to warn about
98
+ if (TESTOMATIO_DISABLE_ARTIFACTS || S3_BUCKET)
99
+ return;
100
+ this.warnedDisabledUpload = true;
101
+ const command = `TESTOMATIO=<your_api_key> TESTOMATIO_RUN=${runId || '<run_id>'} npx @testomatio/reporter upload-artifacts`;
102
+ log_js_1.log.warn(`🗄️ ${picocolors_1.default.yellow('Artifacts uploading is disabled: S3 credentials were not obtained from Testomat.io')}`, picocolors_1.default.yellow('(and no custom S3 storage is configured).'), 'Artifacts will not be uploaded.', `\nRun "${picocolors_1.default.magenta(command)}" later with valid S3 credentials to re-upload artifacts to this run.`);
103
+ }
87
104
  /**
88
105
  *
89
106
  * @param {*} Body
@@ -202,6 +219,7 @@ class S3Uploader {
202
219
  debug(`File ${filePath} does not exist`);
203
220
  }
204
221
  if (!this.isEnabled) {
222
+ this.#warnDisabledUpload(runId);
205
223
  this.storeUploadedFile(filePath, runId, rid, false);
206
224
  this.skippedUploads.push({ path: filePath, size: fileSize });
207
225
  return;
@@ -239,8 +257,10 @@ class S3Uploader {
239
257
  /* WDIO: some artifacts uploading started before createRun function completion
240
258
  probably, the reason is that run is NOT created in adapter (but via cli) */
241
259
  this.isEnabled = this.isEnabled ?? this.checkEnabled();
242
- if (!this.isEnabled)
260
+ if (!this.isEnabled) {
261
+ this.#warnDisabledUpload(pathInS3[0]);
243
262
  return;
263
+ }
244
264
  let Key = pathInS3.filter(p => !!p).join('/');
245
265
  const ext = this.#getFileExtBase64(buffer.toString('base64'));
246
266
  if (ext) {
@@ -139,16 +139,29 @@ export function formatRunOutput(store: {
139
139
  }, format?: string): string;
140
140
  /**
141
141
  * Format the runs fetched via the `fetch` command for machine-readable output.
142
- * `json` prints the full array of run objects; `id` prints one run id per line;
142
+ * `json` prints the full array of run objects (a single object for one run); `id` prints one run id per line;
143
143
  * any other format prints a human-readable multi-line summary per run.
144
144
  *
145
- * @param {{data?: Array}} body - Parsed response body from GET /api/v2/:project/runs.
145
+ * @param {{data?: Array|Object}} body - Parsed response body from GET /api/v2/:project/runs[/:id].
146
146
  * @param {string} [format] - Value of the CLI `--format` option.
147
147
  * @returns {string}
148
148
  */
149
149
  export function formatFetchRunsOutput(body: {
150
- data?: any[];
150
+ data?: any[] | any;
151
151
  }, format?: string): string;
152
+ /**
153
+ * Parse a Testomat.io app URL of a run (/projects/:project/runs/:id)
154
+ * or of a runs page (/projects/:project/runs?filterParam=...) into API v2 request parts.
155
+ *
156
+ * @param {string} pageUrl
157
+ * @returns {{baseUrl: string, project: string, runId?: string, params: string[][]}|null}
158
+ */
159
+ export function parseRunsUrl(pageUrl: string): {
160
+ baseUrl: string;
161
+ project: string;
162
+ runId?: string;
163
+ params: string[][];
164
+ } | null;
152
165
  /**
153
166
  * Calculate the approximate size of data in bytes (JSON stringified, UTF-8 encoded length).
154
167
  * @param {Object} data - Data to measure
@@ -18,6 +18,7 @@ exports.parsePipeOptions = parsePipeOptions;
18
18
  exports.formatFilterListIds = formatFilterListIds;
19
19
  exports.formatRunOutput = formatRunOutput;
20
20
  exports.formatFetchRunsOutput = formatFetchRunsOutput;
21
+ exports.parseRunsUrl = parseRunsUrl;
21
22
  exports.getObjectSize = getObjectSize;
22
23
  exports.splitTestsIntoChunks = splitTestsIntoChunks;
23
24
  const humanize_duration_1 = __importDefault(require("humanize-duration"));
@@ -362,17 +363,18 @@ function formatRunOutput(store, format) {
362
363
  }
363
364
  /**
364
365
  * Format the runs fetched via the `fetch` command for machine-readable output.
365
- * `json` prints the full array of run objects; `id` prints one run id per line;
366
+ * `json` prints the full array of run objects (a single object for one run); `id` prints one run id per line;
366
367
  * any other format prints a human-readable multi-line summary per run.
367
368
  *
368
- * @param {{data?: Array}} body - Parsed response body from GET /api/v2/:project/runs.
369
+ * @param {{data?: Array|Object}} body - Parsed response body from GET /api/v2/:project/runs[/:id].
369
370
  * @param {string} [format] - Value of the CLI `--format` option.
370
371
  * @returns {string}
371
372
  */
372
373
  function formatFetchRunsOutput(body, format) {
373
- const runs = body?.data || [];
374
+ const data = body?.data || [];
375
+ const runs = [data].flat();
374
376
  if (format === 'json')
375
- return JSON.stringify(runs, null, 2);
377
+ return JSON.stringify(data, null, 2);
376
378
  if (format === 'id')
377
379
  return runs.map(run => run.id).filter(Boolean).join('\n');
378
380
  return runs
@@ -380,6 +382,8 @@ function formatFetchRunsOutput(body, format) {
380
382
  const lines = [`* ID: ${run.id}`];
381
383
  if (run.title)
382
384
  lines.push(` title: ${run.title}`);
385
+ if (run.rungroup_id)
386
+ lines.push(` rungroup: ${run.rungroup_id}`);
383
387
  if (run.launched_at)
384
388
  lines.push(` started at: ${run.launched_at}`);
385
389
  if (run.finished_at)
@@ -400,6 +404,41 @@ function formatFetchRunsOutput(body, format) {
400
404
  })
401
405
  .join('\n');
402
406
  }
407
+ // filterParam keys of the runs page which are API params on their own; the rest go under filter[...]
408
+ const RUNS_PAGE_PARAMS = ['search', 'tql', 'groupId'];
409
+ /**
410
+ * Parse a Testomat.io app URL of a run (/projects/:project/runs/:id)
411
+ * or of a runs page (/projects/:project/runs?filterParam=...) into API v2 request parts.
412
+ *
413
+ * @param {string} pageUrl
414
+ * @returns {{baseUrl: string, project: string, runId?: string, params: string[][]}|null}
415
+ */
416
+ function parseRunsUrl(pageUrl) {
417
+ let url;
418
+ try {
419
+ url = new URL(pageUrl);
420
+ }
421
+ catch (e) {
422
+ return null;
423
+ }
424
+ const match = url.pathname.match(/\/projects\/([^/]+)\/runs(?:\/([^/]+))?\/?$/);
425
+ if (!match)
426
+ return null;
427
+ const [, project, runId] = match;
428
+ const params = [];
429
+ for (const [key, value] of new URLSearchParams(url.searchParams.get('filterParam') || '')) {
430
+ // "groups" only switches the page to the grouped view
431
+ if (!value || key === 'groups')
432
+ continue;
433
+ if (RUNS_PAGE_PARAMS.includes(key)) {
434
+ params.push([key, value]);
435
+ continue;
436
+ }
437
+ const [name, ...nested] = key.split('[');
438
+ params.push([`filter[${name}]${nested.map(part => `[${part}`).join('')}`, value]);
439
+ }
440
+ return { baseUrl: url.origin, project, runId, params };
441
+ }
403
442
 
404
443
  module.exports.updateFilterType = updateFilterType;
405
444
 
@@ -431,6 +470,8 @@ module.exports.formatRunOutput = formatRunOutput;
431
470
 
432
471
  module.exports.formatFetchRunsOutput = formatFetchRunsOutput;
433
472
 
473
+ module.exports.parseRunsUrl = parseRunsUrl;
474
+
434
475
  module.exports.getObjectSize = getObjectSize;
435
476
 
436
477
  module.exports.splitTestsIntoChunks = splitTestsIntoChunks;
package/lib/xmlReader.js CHANGED
@@ -432,6 +432,8 @@ class XmlReader {
432
432
  }
433
433
  this.adapter.formatTest(t);
434
434
  t.title = (0, utils_js_1.humanize)(t.title);
435
+ // meta must always include reporter version and adapter used
436
+ t.meta = { ...t.meta, reporterVersion: this.version, adapter: 'xml' };
435
437
  });
436
438
  }
437
439
  formatErrors() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "2.19.0",
3
+ "version": "2.20.0",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -65,7 +65,8 @@
65
65
  "test:playwright": "mocha tests/adapter/playwright.test.js",
66
66
  "test:codecept": "mocha tests/adapter/codecept.test.js tests/adapter/codecept_comprehensive.test.js tests/adapter/codecept_steps_sections.test.js",
67
67
  "test:vitest": "mocha tests/adapter/vitest.test.js",
68
- "test:frameworks": "npm run test:playwright && npm run test:codecept && npm run test:vitest",
68
+ "test:e2e": "mocha tests/adapter/e2e.test.js",
69
+ "test:frameworks": "npm run test:playwright && npm run test:codecept && npm run test:vitest && npm run test:e2e",
69
70
  "test:all": "npm run test && npm run test:frameworks",
70
71
  "test:adapters": "mocha tests/adapter/*.test.js",
71
72
  "test:codecept:bug948": "mocha tests/adapter/codecept_aftersuite_failure.test.js",
@@ -129,6 +130,10 @@
129
130
  "./lib/adapter/cypress-plugin": "./lib/adapter/cypress-plugin/index.js",
130
131
  "./cypress-plugin": "./lib/adapter/cypress-plugin/index.js",
131
132
  "./cypress": "./lib/adapter/cypress-plugin/index.js",
133
+ "./e2e": {
134
+ "import": "./src/adapter/e2e.js",
135
+ "require": "./lib/adapter/e2e.js"
136
+ },
132
137
  "./lib/adapter/jasmine.js": "./lib/adapter/jasmine.js",
133
138
  "./jasmine": "./lib/adapter/jasmine.js",
134
139
  "./lib/adapter/jest.js": "./lib/adapter/jest.js",
@@ -11,6 +11,8 @@ import codeceptjs from 'codeceptjs';
11
11
  import { log } from '../utils/log.js';
12
12
 
13
13
  const debug = createDebugMessages('@testomatio/reporter:adapter:codeceptjs');
14
+
15
+ global.TESTOMATIO_ADAPTER = 'codeceptjs';
14
16
  // @ts-ignore
15
17
  if (!global.codeceptjs) {
16
18
  // @ts-ignore
@@ -8,6 +8,8 @@ import { getTestomatIdFromTestTitle, fileSystem } from '../../utils/utils.js';
8
8
  import { config } from '../../config.js';
9
9
  import { services } from '../../services/index.js';
10
10
 
11
+ global.TESTOMATIO_ADAPTER = 'cucumber';
12
+
11
13
  const { GherkinDocumentParser, PickleParser } = formatterHelpers;
12
14
  const { getGherkinScenarioLocationMap, getGherkinStepMap } = GherkinDocumentParser;
13
15
  const { getPickleStepMap } = PickleParser;
@@ -3,6 +3,8 @@ import { getTestomatIdFromTestTitle, parseSuite } from '../../utils/utils.js';
3
3
  import TestomatClient from '../../client.js';
4
4
  import { config } from '../../config.js';
5
5
 
6
+ global.TESTOMATIO_ADAPTER = 'cypress';
7
+
6
8
  const testomatioReporter = on => {
7
9
  if (!config.TESTOMATIO) {
8
10
  console.log('TESTOMATIO key is empty, ignoring reports');