@testomatio/reporter 2.0.0-beta-esm → 2.0.0-beta.1-xml

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 (123) hide show
  1. package/lib/adapter/codecept.d.ts +2 -0
  2. package/lib/adapter/codecept.js +31 -26
  3. package/lib/adapter/cucumber/current.d.ts +14 -0
  4. package/lib/adapter/cucumber/legacy.d.ts +0 -0
  5. package/lib/adapter/cucumber.d.ts +2 -0
  6. package/lib/adapter/cypress-plugin/index.d.ts +2 -0
  7. package/lib/adapter/cypress-plugin/index.js +10 -10
  8. package/lib/adapter/jasmine.d.ts +11 -0
  9. package/lib/adapter/jest.d.ts +13 -0
  10. package/lib/adapter/mocha.d.ts +2 -0
  11. package/lib/adapter/mocha.js +4 -4
  12. package/lib/adapter/nightwatch.d.ts +4 -0
  13. package/lib/adapter/nightwatch.js +80 -0
  14. package/lib/adapter/playwright.d.ts +14 -0
  15. package/lib/adapter/playwright.js +58 -33
  16. package/lib/adapter/vitest.d.ts +35 -0
  17. package/lib/adapter/vitest.js +6 -6
  18. package/lib/adapter/webdriver.d.ts +24 -0
  19. package/lib/adapter/webdriver.js +51 -14
  20. package/lib/bin/cli.d.ts +2 -0
  21. package/lib/bin/cli.js +250 -0
  22. package/lib/bin/reportXml.d.ts +2 -0
  23. package/lib/bin/reportXml.js +15 -11
  24. package/lib/bin/startTest.d.ts +2 -0
  25. package/lib/bin/startTest.js +12 -7
  26. package/lib/bin/uploadArtifacts.d.ts +2 -0
  27. package/lib/bin/uploadArtifacts.js +82 -0
  28. package/lib/client.d.ts +76 -0
  29. package/lib/client.js +128 -53
  30. package/lib/config.d.ts +1 -0
  31. package/lib/config.js +2 -2
  32. package/lib/constants.d.ts +25 -0
  33. package/lib/constants.js +5 -1
  34. package/lib/data-storage.d.ts +34 -0
  35. package/lib/data-storage.js +19 -9
  36. package/lib/junit-adapter/adapter.d.ts +9 -0
  37. package/lib/junit-adapter/csharp.d.ts +5 -0
  38. package/lib/junit-adapter/csharp.js +11 -1
  39. package/lib/junit-adapter/index.d.ts +3 -0
  40. package/lib/junit-adapter/java.d.ts +5 -0
  41. package/lib/junit-adapter/javascript.d.ts +4 -0
  42. package/lib/junit-adapter/python.d.ts +5 -0
  43. package/lib/junit-adapter/ruby.d.ts +4 -0
  44. package/lib/output.d.ts +11 -0
  45. package/lib/package.json +3 -1
  46. package/lib/pipe/bitbucket.d.ts +23 -0
  47. package/lib/pipe/bitbucket.js +19 -9
  48. package/lib/pipe/csv.d.ts +47 -0
  49. package/lib/pipe/csv.js +2 -2
  50. package/lib/pipe/debug.d.ts +29 -0
  51. package/lib/pipe/debug.js +108 -0
  52. package/lib/pipe/github.d.ts +30 -0
  53. package/lib/pipe/github.js +37 -5
  54. package/lib/pipe/gitlab.d.ts +23 -0
  55. package/lib/pipe/gitlab.js +2 -3
  56. package/lib/pipe/html.d.ts +35 -0
  57. package/lib/pipe/html.js +9 -4
  58. package/lib/pipe/index.d.ts +1 -0
  59. package/lib/pipe/index.js +20 -10
  60. package/lib/pipe/testomatio.d.ts +70 -0
  61. package/lib/pipe/testomatio.js +54 -39
  62. package/lib/reporter-functions.d.ts +34 -0
  63. package/lib/reporter-functions.js +17 -7
  64. package/lib/reporter.d.ts +232 -0
  65. package/lib/reporter.js +19 -33
  66. package/lib/services/artifacts.d.ts +33 -0
  67. package/lib/services/index.d.ts +9 -0
  68. package/lib/services/key-values.d.ts +27 -0
  69. package/lib/services/key-values.js +1 -1
  70. package/lib/services/logger.d.ts +64 -0
  71. package/lib/services/logger.js +1 -2
  72. package/lib/template/testomatio.hbs +651 -1366
  73. package/lib/uploader.d.ts +60 -0
  74. package/lib/uploader.js +312 -0
  75. package/lib/utils/pipe_utils.d.ts +41 -0
  76. package/lib/utils/pipe_utils.js +3 -5
  77. package/lib/utils/utils.d.ts +47 -0
  78. package/lib/utils/utils.js +99 -12
  79. package/lib/xmlReader.d.ts +92 -0
  80. package/lib/xmlReader.js +64 -25
  81. package/package.json +19 -13
  82. package/src/adapter/codecept.js +30 -26
  83. package/src/adapter/cypress-plugin/index.js +5 -5
  84. package/src/adapter/mocha.cjs +1 -1
  85. package/src/adapter/mocha.js +4 -4
  86. package/src/adapter/nightwatch.js +88 -0
  87. package/src/adapter/playwright.js +59 -31
  88. package/src/adapter/vitest.js +6 -6
  89. package/src/adapter/webdriver.js +42 -12
  90. package/src/bin/cli.js +303 -0
  91. package/src/bin/reportXml.js +19 -9
  92. package/src/bin/startTest.js +9 -4
  93. package/src/bin/uploadArtifacts.js +91 -0
  94. package/src/client.js +137 -57
  95. package/src/config.js +2 -2
  96. package/src/constants.js +5 -1
  97. package/src/data-storage.js +2 -2
  98. package/src/junit-adapter/csharp.js +13 -1
  99. package/src/pipe/bitbucket.js +2 -2
  100. package/src/pipe/csv.js +3 -3
  101. package/src/pipe/debug.js +104 -0
  102. package/src/pipe/github.js +3 -5
  103. package/src/pipe/gitlab.js +6 -7
  104. package/src/pipe/html.js +14 -7
  105. package/src/pipe/index.js +5 -7
  106. package/src/pipe/testomatio.js +75 -76
  107. package/src/reporter-functions.js +18 -7
  108. package/src/reporter.cjs_decprecated +21 -0
  109. package/src/reporter.js +20 -11
  110. package/src/services/key-values.js +1 -1
  111. package/src/services/logger.js +5 -4
  112. package/src/template/testomatio.hbs +651 -1366
  113. package/src/uploader.js +371 -0
  114. package/src/utils/pipe_utils.js +4 -12
  115. package/src/utils/utils.js +64 -15
  116. package/src/xmlReader.js +76 -26
  117. package/lib/adapter/jasmine/jasmine.js +0 -63
  118. package/lib/adapter/mocha/mocha.js +0 -125
  119. package/lib/fileUploader.js +0 -245
  120. package/lib/utils/chalk.js +0 -10
  121. package/src/fileUploader.js +0 -307
  122. package/src/reporter.cjs +0 -22
  123. package/src/utils/chalk.js +0 -13
@@ -0,0 +1,92 @@
1
+ export default XmlReader;
2
+ declare class XmlReader {
3
+ constructor(opts?: {});
4
+ requestParams: {
5
+ apiKey: any;
6
+ url: any;
7
+ title: string;
8
+ env: string;
9
+ group_title: string;
10
+ detach: string;
11
+ isBatchEnabled: boolean;
12
+ };
13
+ runId: any;
14
+ adapter: import("./junit-adapter/adapter.js").default;
15
+ opts: {};
16
+ store: {};
17
+ pipesPromise: Promise<any[]>;
18
+ parser: XMLParser;
19
+ tests: any[];
20
+ stats: {};
21
+ uploader: S3Uploader;
22
+ version: any;
23
+ connectAdapter(): import("./junit-adapter/adapter.js").default;
24
+ parse(fileName: any): {
25
+ status: string;
26
+ create_tests: boolean;
27
+ tests_count: number;
28
+ passed_count: number;
29
+ skipped_count: number;
30
+ failed_count: number;
31
+ tests: any;
32
+ } | {
33
+ status: any;
34
+ create_tests: boolean;
35
+ tests_count: number;
36
+ passed_count: number;
37
+ failed_count: number;
38
+ skipped_count: number;
39
+ tests: any[];
40
+ };
41
+ processJUnit(jsonSuite: any): {
42
+ create_tests: boolean;
43
+ duration: number;
44
+ failed_count: number;
45
+ name: any;
46
+ passed_count: number;
47
+ skipped_count: number;
48
+ status: string;
49
+ tests: any[];
50
+ tests_count: number;
51
+ };
52
+ processNUnit(jsonSuite: any): {
53
+ status: any;
54
+ create_tests: boolean;
55
+ tests_count: number;
56
+ passed_count: number;
57
+ failed_count: number;
58
+ skipped_count: number;
59
+ tests: any[];
60
+ };
61
+ processTRX(jsonSuite: any): {
62
+ status: string;
63
+ create_tests: boolean;
64
+ tests_count: number;
65
+ passed_count: number;
66
+ skipped_count: number;
67
+ failed_count: number;
68
+ tests: any;
69
+ };
70
+ processXUnit(assemblies: any): {
71
+ status: string;
72
+ create_tests: boolean;
73
+ name: string;
74
+ tests_count: number;
75
+ passed_count: number;
76
+ failed_count: number;
77
+ skipped_count: number;
78
+ tests: any[];
79
+ };
80
+ calculateStats(): {};
81
+ fetchSourceCode(): void;
82
+ formatTests(): void;
83
+ formatErrors(): void;
84
+ formatStack(t: any): any;
85
+ uploadArtifacts(): Promise<void>;
86
+ createRun(): Promise<any[]>;
87
+ pipes: any;
88
+ uploadData(): Promise<any[]>;
89
+ _finishRun(): Promise<any[]>;
90
+ }
91
+ import { XMLParser } from 'fast-xml-parser';
92
+ import { S3Uploader } from './uploader.js';
package/lib/xmlReader.js CHANGED
@@ -15,12 +15,12 @@ const utils_js_1 = require("./utils/utils.js");
15
15
  const index_js_1 = require("./pipe/index.js");
16
16
  const index_js_2 = __importDefault(require("./junit-adapter/index.js"));
17
17
  const config_js_1 = require("./config.js");
18
- const fileUploader_js_1 = require("./fileUploader.js");
18
+ const uploader_js_1 = require("./uploader.js");
19
19
  // @ts-ignore this line will be removed in compiled code, because __dirname is defined in commonjs
20
20
  const debug = (0, debug_1.default)('@testomatio/reporter:xml');
21
21
  const ridRunId = (0, crypto_1.randomUUID)();
22
22
  const TESTOMATIO_URL = process.env.TESTOMATIO_URL || 'https://app.testomat.io';
23
- const { TESTOMATIO_RUNGROUP_TITLE, TESTOMATIO_TITLE, TESTOMATIO_ENV, TESTOMATIO_RUN } = process.env;
23
+ const { TESTOMATIO_RUNGROUP_TITLE, TESTOMATIO_SUITE, TESTOMATIO_MAX_STACK_TRACE, TESTOMATIO_TITLE, TESTOMATIO_ENV, TESTOMATIO_RUN, TESTOMATIO_MARK_DETACHED } = process.env;
24
24
  const options = {
25
25
  ignoreDeclaration: true,
26
26
  ignoreAttributes: false,
@@ -28,6 +28,7 @@ const options = {
28
28
  attributeNamePrefix: '',
29
29
  parseTagValue: true,
30
30
  };
31
+ const MAX_OUTPUT_LENGTH = parseInt(TESTOMATIO_MAX_STACK_TRACE, 10) || 10000;
31
32
  const reduceOptions = {};
32
33
  class XmlReader {
33
34
  constructor(opts = {}) {
@@ -37,6 +38,7 @@ class XmlReader {
37
38
  title: TESTOMATIO_TITLE,
38
39
  env: TESTOMATIO_ENV,
39
40
  group_title: TESTOMATIO_RUNGROUP_TITLE,
41
+ detach: TESTOMATIO_MARK_DETACHED,
40
42
  // batch uploading is implemented for xml already
41
43
  isBatchEnabled: false,
42
44
  };
@@ -51,7 +53,7 @@ class XmlReader {
51
53
  this.tests = [];
52
54
  this.stats = {};
53
55
  this.stats.language = opts.lang?.toLowerCase();
54
- this.filesToUpload = {};
56
+ this.uploader = new uploader_js_1.S3Uploader();
55
57
  // @ts-ignore
56
58
  const packageJsonPath = path_1.default.resolve(__dirname, '..', 'package.json');
57
59
  this.version = JSON.parse(fs_1.default.readFileSync(packageJsonPath).toString()).version;
@@ -74,7 +76,7 @@ class XmlReader {
74
76
  /(<system-out><!\[CDATA\[)([\s\S]*?)(\]\]><\/system-out>)/g,
75
77
  ];
76
78
  for (const regex of cutRegexes) {
77
- xmlData = xmlData.replace(regex, (_, p1, p2, p3) => `${p1}${p2.substring(0, 5000)}${p3}`);
79
+ xmlData = xmlData.replace(regex, (_, p1, p2, p3) => `${p1}${p2.substring(0, MAX_OUTPUT_LENGTH)}${p3}`);
78
80
  }
79
81
  const jsonResult = this.parser.parse(xmlData);
80
82
  let jsonSuite;
@@ -105,16 +107,24 @@ class XmlReader {
105
107
  const resultTests = processTestSuite(testsuite);
106
108
  const hasFailures = resultTests.filter(t => t.status === 'failed').length > 0;
107
109
  const status = failures > 0 || errors > 0 || hasFailures ? 'failed' : 'passed';
110
+ const time = testsuite.time || 0;
111
+ // debug('time', jsonSuite, time)
112
+ if (time) {
113
+ if (!this.stats.duration)
114
+ this.stats.duration = 0;
115
+ this.stats.duration += parseFloat(time);
116
+ }
108
117
  this.tests = this.tests.concat(resultTests);
109
118
  return {
110
- status,
111
119
  create_tests: true,
120
+ duration: parseFloat(time),
121
+ failed_count: parseInt(failures, 10),
112
122
  name,
113
- tests_count: parseInt(tests, 10),
114
123
  passed_count: parseInt(tests, 10) - parseInt(failures, 10),
115
- failed_count: parseInt(failures, 10),
116
124
  skipped_count: 0,
125
+ status,
117
126
  tests: resultTests,
127
+ tests_count: parseInt(tests, 10),
118
128
  };
119
129
  }
120
130
  processNUnit(jsonSuite) {
@@ -193,7 +203,7 @@ class XmlReader {
193
203
  this.tests = results.filter(t => !!t.title);
194
204
  return {
195
205
  status,
196
- create_tests: true,
206
+ create_tests: !process.env.IGNORE_NEW_TESTS,
197
207
  tests_count: parseInt(counters.total, 10),
198
208
  passed_count: parseInt(counters.passed, 10),
199
209
  skipped_count: parseInt(counters.notExecuted, 10),
@@ -266,6 +276,7 @@ class XmlReader {
266
276
  calculateStats() {
267
277
  this.stats = {
268
278
  ...this.stats,
279
+ detach: this.requestParams.detach,
269
280
  status: 'passed',
270
281
  create_tests: true,
271
282
  tests_count: 0,
@@ -303,6 +314,8 @@ class XmlReader {
303
314
  this.stats.language = 'js';
304
315
  if (file.endsWith('.ts'))
305
316
  this.stats.language = 'ts';
317
+ if (file.endsWith('.cs'))
318
+ this.stats.language = 'csharp';
306
319
  }
307
320
  if (!fs_1.default.existsSync(file)) {
308
321
  debug('Failed to open file with the source code', file);
@@ -349,13 +362,13 @@ class XmlReader {
349
362
  async uploadArtifacts() {
350
363
  for (const test of this.tests.filter(t => !!t.stack)) {
351
364
  let files = [];
352
- if (test.files?.length)
353
- files = test.files.map(f => path_1.default.join(process.cwd(), f));
354
- files = [...files, ...(0, utils_js_1.fetchFilesFromStackTrace)(test.stack)];
365
+ if (!test.files?.length)
366
+ continue;
367
+ files = test.files.map(f => path_1.default.isAbsolute(f) ? f : path_1.default.join(process.cwd(), f));
355
368
  if (!files.length)
356
369
  continue;
357
370
  const runId = this.runId || this.store.runId || Date.now().toString();
358
- test.artifacts = await Promise.all(files.map(f => fileUploader_js_1.upload.uploadFileByPath(f, runId)));
371
+ test.artifacts = await Promise.all(files.map(f => this.uploader.uploadFileByPath(f, [runId, path_1.default.basename(f)])));
359
372
  console.log(constants_js_1.APP_PREFIX, `🗄️ Uploaded ${picocolors_1.default.bold(`${files.length} artifacts`)} for test ${test.title}`);
360
373
  }
361
374
  }
@@ -369,7 +382,9 @@ class XmlReader {
369
382
  };
370
383
  debug('Run', runParams);
371
384
  this.pipes = this.pipes || (await this.pipesPromise);
372
- return Promise.all(this.pipes.map(p => p.createRun(runParams)));
385
+ const run = await Promise.all(this.pipes.map(p => p.createRun(runParams)));
386
+ this.uploader.checkEnabled();
387
+ return run;
373
388
  }
374
389
  async uploadData() {
375
390
  await this.uploadArtifacts();
@@ -378,16 +393,14 @@ class XmlReader {
378
393
  this.fetchSourceCode();
379
394
  this.formatErrors();
380
395
  this.formatTests();
381
- debug('Uploading data', {
382
- ...this.stats,
383
- tests: this.tests,
384
- });
385
396
  const dataString = {
386
397
  ...this.stats,
387
398
  api_key: this.requestParams.apiKey,
388
399
  status: 'finished',
400
+ duration: this.stats.duration,
389
401
  tests: this.tests,
390
402
  };
403
+ debug('Uploading data', dataString);
391
404
  this.pipes = this.pipes || (await this.pipesPromise);
392
405
  return Promise.all(this.pipes.map(p => p.finishRun(dataString)));
393
406
  }
@@ -405,14 +418,17 @@ function reduceTestCases(prev, item) {
405
418
  testCases = [testCases];
406
419
  }
407
420
  // suite inside test case
408
- if (item['test-suite'] && item['test-suite']['test-case'])
409
- testCases.push(...item['test-suite']['test-case']);
421
+ const testCase = item['test-suite']?.['test-case'];
422
+ if (testCase) {
423
+ const nestedCases = Array.isArray(testCase) ? testCase : [testCase];
424
+ testCases.push(...nestedCases);
425
+ }
410
426
  const suiteOutput = item['system-out'] || item.output || item.log || '';
411
427
  const suiteErr = item['system-err'] || item.output || item.log || '';
412
428
  testCases
413
429
  .filter(t => !!t)
414
430
  .forEach(testCaseItem => {
415
- const file = testCaseItem.file || item.filepath || '';
431
+ const file = testCaseItem.file || item.filepath || item.fullname || '';
416
432
  let stack = '';
417
433
  let message = '';
418
434
  if (testCaseItem.error)
@@ -444,17 +460,35 @@ function reduceTestCases(prev, item) {
444
460
  example = { ...exampleMatches[1].split(',').map(v => v.trim().replace(/[^\w\s-]/g, '')) };
445
461
  title = title.replace(/\(.*?\)/, '').trim();
446
462
  }
447
- // eslint-disable-next-line
448
463
  stack = `${testCaseItem['system-out'] || testCaseItem.output || testCaseItem.log || ''}\n\n${stack}\n\n${suiteOutput}\n\n${suiteErr}`.trim();
449
- const testId = (0, utils_js_1.fetchIdFromOutput)(stack);
464
+ let testId = (0, utils_js_1.fetchIdFromOutput)(stack);
465
+ if (tags?.length && !testId) {
466
+ testId = tags.filter(t => t.startsWith('T')).map(t => `@${t}`).find(t => t.match(utils_js_1.TEST_ID_REGEX))?.slice(2);
467
+ }
450
468
  let status = constants_js_1.STATUS.PASSED.toString();
451
469
  if ('failure' in testCaseItem || 'error' in testCaseItem)
452
470
  status = constants_js_1.STATUS.FAILED;
453
471
  if ('skipped' in testCaseItem)
454
472
  status = constants_js_1.STATUS.SKIPPED;
473
+ if (testCaseItem.result && Object.values(constants_js_1.STATUS).includes(testCaseItem.result.toLowerCase())) {
474
+ status = testCaseItem.result.toLowerCase();
475
+ }
455
476
  let rid = null;
456
477
  if (testCaseItem.id)
457
478
  rid = `${ridRunId}-${testCaseItem.id}`;
479
+ // Extract attachments
480
+ let files = [];
481
+ if (testCaseItem.attachments) {
482
+ const attachments = Array.isArray(testCaseItem.attachments.attachment)
483
+ ? testCaseItem.attachments.attachment
484
+ : [testCaseItem.attachments.attachment];
485
+ files = attachments
486
+ .filter(a => a && a.filePath)
487
+ .map(a => a.filePath);
488
+ }
489
+ // Extract files from stack trace using existing utility
490
+ const stackFiles = (0, utils_js_1.fetchFilesFromStackTrace)(stack);
491
+ files = [...new Set([...files, ...stackFiles])]; // Remove duplicates
458
492
  prev.push({
459
493
  rid,
460
494
  file,
@@ -469,7 +503,9 @@ function reduceTestCases(prev, item) {
469
503
  run_time: parseFloat(testCaseItem.time || testCaseItem.duration) * 1000,
470
504
  status,
471
505
  title,
506
+ root_suite_id: TESTOMATIO_SUITE,
472
507
  suite_title: suiteTitle,
508
+ files,
473
509
  });
474
510
  });
475
511
  return prev;
@@ -493,11 +529,14 @@ function fetchProperties(item) {
493
529
  let title = '';
494
530
  if (!item.properties)
495
531
  return {};
496
- const prop = [item.properties?.property].flat().find(p => p.name === 'Description');
532
+ // Handle both single property and array of properties
533
+ const properties = Array.isArray(item.properties.property)
534
+ ? item.properties.property
535
+ : [item.properties.property].filter(Boolean);
536
+ const prop = properties.find(p => p.name === 'Description');
497
537
  if (prop)
498
538
  title = prop.value;
499
- [item.properties?.property]
500
- .flat()
539
+ properties
501
540
  .filter(p => p.name === 'Category')
502
541
  .forEach(p => tags.push(p.value));
503
542
  return { title, tags };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "2.0.0-beta-esm",
3
+ "version": "2.0.0-beta.1-xml",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "engines": {
6
6
  "node": ">=18"
@@ -14,19 +14,19 @@
14
14
  "@aws-sdk/client-s3": "^3.279.0",
15
15
  "@aws-sdk/lib-storage": "^3.279.0",
16
16
  "@cucumber/cucumber": "^10.9.0",
17
- "@octokit/rest": "^19.0.5",
17
+ "@octokit/rest": "^21.1.1",
18
18
  "aws-sdk": "^2.1072.0",
19
19
  "axios": "^1.6.2",
20
20
  "axios-retry": "^3.9.1",
21
21
  "callsite-record": "^4.1.4",
22
- "chalk": "^5.3.0",
23
- "commander": "^4.1.1",
22
+ "commander": "^12",
24
23
  "cross-spawn": "^7.0.3",
25
24
  "csv-writer": "^1.6.0",
26
25
  "debug": "^4.3.4",
27
26
  "dotenv": "^16.0.1",
28
27
  "fast-xml-parser": "^4.4.1",
29
28
  "file-url": "3.0.0",
29
+ "filesize": "^10.1.6",
30
30
  "glob": "^10.3",
31
31
  "handlebars": "^4.7.8",
32
32
  "has-flag": "^5.0.1",
@@ -37,6 +37,7 @@
37
37
  "lodash.merge": "^4.6.2",
38
38
  "minimatch": "^9.0.3",
39
39
  "picocolors": "^1.0.1",
40
+ "pretty-ms": "^7.0.1",
40
41
  "promise-retry": "^2.0.1",
41
42
  "strip-ansi": "^7.1.0",
42
43
  "uuid": "^9.0.0"
@@ -48,7 +49,6 @@
48
49
  "testcafe"
49
50
  ],
50
51
  "scripts": {
51
- "@cucumber/cucumber": "^10.9.0",
52
52
  "clear-exportdir": "rm -rf export/",
53
53
  "pretty": "npx prettier --check .",
54
54
  "pretty:fix": "prettier --write .",
@@ -67,10 +67,12 @@
67
67
  "test:adapter:playwright:example": "npx playwright test --config='./tests/adapter/examples/playwright/playwright.config.ts'",
68
68
  "test:adapter:vitest:example": "npx vitest --config='./tests/adapter/examples/vitest/vitest.config.ts'",
69
69
  "test:storage": "npx mocha tests-storage/artifact-storage.test.js && npx mocha tests-storage/data-storage.test.js && TESTOMATIO_INTERCEPT_CONSOLE_LOGS=true npx mocha tests-storage/logger.test.js && npx mocha tests-storage/logger-2.test.js && npx mocha tests-storage/reporter-functions.test.js",
70
- "build:cjs": "rm -rf ./cjs && tsc --module commonjs && npx tsx build/scripts/edit-js-files.js && npx tsx build/scripts/edit-package-json.js && chmod +x ./build/scripts/copy-tesmplate.sh && ./build/scripts/copy-tesmplate.sh"
70
+ "build": "rm -rf ./cjs && tsc --module commonjs && npx tsx build/scripts/edit-js-files.js && npx tsx build/scripts/edit-package-json.js && chmod +x ./build/scripts/copy-tesmplate.sh && ./build/scripts/copy-tesmplate.sh",
71
+ "build:bun": "rm -rf ./cjs && bun build ./src/reporter.js ./src/bin/reportXml.js ./src/bin/startTest.js ./src/bin/uploadArtifacts.js --outdir ./cjs --target node",
72
+ "build:watch:bun": "rm -rf ./cjs && bun build ./src/bin/reportXml.js ./src/bin/startTest.js ./src/bin/uploadArtifacts.js --outdir ./cjs --target node --watch --onSuccess \"build/scripts/post-build.js\""
71
73
  },
72
74
  "devDependencies": {
73
- "@playwright/test": "^1.46.1",
75
+ "@playwright/test": "^1.49.1",
74
76
  "@redocly/cli": "^1.0.0-beta.125",
75
77
  "@types/cross-spawn": "^6.0.6",
76
78
  "@types/cucumber": "^7.0.0",
@@ -79,8 +81,7 @@
79
81
  "chai": "^4.3.6",
80
82
  "codeceptjs": "^3.6.5",
81
83
  "cucumber": "^6.0.7",
82
- "eslint": "^8.57.0",
83
- "eslint-config-airbnb-base": "^15.0.0",
84
+ "eslint": "^9.24.0",
84
85
  "eslint-config-prettier": "^8.3.0",
85
86
  "eslint-plugin-import": "^2.25.4",
86
87
  "jasmine": "^5.2.0",
@@ -95,14 +96,16 @@
95
96
  "vitest": "^1.6.0"
96
97
  },
97
98
  "bin": {
99
+ "@testomatio/reporter": "./lib/bin/cli.js",
98
100
  "report-xml": "./lib/bin/reportXml.js",
99
- "start-test-run": "./lib/bin/startTest.js"
101
+ "start-test-run": "./lib/bin/startTest.js",
102
+ "upload-artifacts": "./lib/bin/uploadArtifacts.js"
100
103
  },
101
104
  "exports": {
102
105
  ".": {
103
106
  "import": "./src/reporter.js",
104
107
  "require": "./lib/reporter.js",
105
- "types": "./index.d.ts"
108
+ "types": "./types/types.d.ts"
106
109
  },
107
110
  "./lib/adapter/codecept/codecept.js": "./lib/adapter/codecept.js",
108
111
  "./lib/adapter/codecept": "./lib/adapter/codecept.js",
@@ -111,6 +114,7 @@
111
114
  "./cucumber": "./lib/adapter/cucumber/current.js",
112
115
  "./lib/adapter/cypress-plugin": "./lib/adapter/cypress-plugin/index.js",
113
116
  "./cypress-plugin": "./lib/adapter/cypress-plugin/index.js",
117
+ "./cypress": "./lib/adapter/cypress-plugin/index.js",
114
118
  "./lib/adapter/jasmine.js": "./lib/adapter/jasmine.js",
115
119
  "./jasmine": "./lib/adapter/jasmine.js",
116
120
  "./lib/adapter/jest.js": "./lib/adapter/jest.js",
@@ -118,10 +122,12 @@
118
122
  "./lib/adapter/mocha/mocha.js": "./lib/adapter/mocha.js",
119
123
  "./mocha": "./lib/adapter/mocha.js",
120
124
  "./lib/adapter/playwright.js": "./lib/adapter/playwright.js",
125
+ "./nightwatch": "./lib/adapter/nightwatch.js",
121
126
  "./playwright": "./lib/adapter/playwright.js",
122
- "./vitest": "./src/adapter/vitest.js",
127
+ "./vitest": "./lib/adapter/vitest.js",
123
128
  "./lib/adapter/webdriver.js": "./lib/adapter/webdriver.js",
124
129
  "./lib/adapter/webdriver": "./lib/adapter/webdriver.js",
125
- "./webdriver": "./lib/adapter/webdriver.js"
130
+ "./webdriver": "./lib/adapter/webdriver.js",
131
+ "./wdio": "./lib/adapter/webdriver.js"
126
132
  }
127
133
  }
@@ -4,8 +4,6 @@ import TestomatClient from '../client.js';
4
4
  import { STATUS, APP_PREFIX, TESTOMAT_TMP_STORAGE_DIR } from '../constants.js';
5
5
  import { getTestomatIdFromTestTitle, fileSystem } from '../utils/utils.js';
6
6
  import { services } from '../services/index.js';
7
- import { upload } from '../fileUploader.js';
8
- // eslint-disable-next-line
9
7
  import codeceptjs from 'codeceptjs';
10
8
 
11
9
  const debug = createDebugMessages('@testomatio/reporter:adapter:codeceptjs');
@@ -46,8 +44,9 @@ function CodeceptReporter(config) {
46
44
  const { apiKey } = config;
47
45
 
48
46
  const getDuration = test => {
49
- if (testTimeMap[test.id]) {
50
- return Date.now() - testTimeMap[test.id];
47
+ if (!test.uid) return 0;
48
+ if (testTimeMap[test.uid]) {
49
+ return Date.now() - testTimeMap[test.uid];
51
50
  }
52
51
 
53
52
  return 0;
@@ -125,7 +124,8 @@ function CodeceptReporter(config) {
125
124
  services.setContext(test.fullTitle());
126
125
 
127
126
  testTimeMap[test.id] = Date.now();
128
- // start logging
127
+ if (!test.uid) return;
128
+ testTimeMap[test.uid] = Date.now();
129
129
  });
130
130
 
131
131
  event.dispatcher.on(event.all.result, async () => {
@@ -133,10 +133,8 @@ function CodeceptReporter(config) {
133
133
  // all tests were reported and we can upload videos
134
134
  await Promise.all(reportTestPromises);
135
135
 
136
- if (upload.isArtifactsEnabled()) {
137
- await uploadAttachments(client, videos, '🎞️ Uploading', 'video');
138
- await uploadAttachments(client, traces, '📁 Uploading', 'trace');
139
- }
136
+ await uploadAttachments(client, videos, '🎞️ Uploading', 'video');
137
+ await uploadAttachments(client, traces, '📁 Uploading', 'trace');
140
138
 
141
139
  const status = failedTests.length === 0 ? STATUS.PASSED : STATUS.FAILED;
142
140
  // @ts-ignore
@@ -144,9 +142,9 @@ function CodeceptReporter(config) {
144
142
  });
145
143
 
146
144
  event.dispatcher.on(event.test.passed, test => {
147
- const { id, tags, title } = test;
148
- if (id && failedTests.includes(id)) {
149
- failedTests = failedTests.filter(failed => id !== failed);
145
+ const { uid, tags, title } = test;
146
+ if (uid && failedTests.includes(uid)) {
147
+ failedTests = failedTests.filter(failed => uid !== failed);
150
148
  }
151
149
  const testObj = getTestAndMessage(title);
152
150
 
@@ -157,7 +155,7 @@ function CodeceptReporter(config) {
157
155
 
158
156
  client.addTestRun(STATUS.PASSED, {
159
157
  ...stripExampleFromTitle(title),
160
- rid: id,
158
+ rid: uid,
161
159
  suite_title: test.parent && test.parent.title,
162
160
  message: testObj.message,
163
161
  time: getDuration(test),
@@ -180,12 +178,12 @@ function CodeceptReporter(config) {
180
178
  if (!suite) return;
181
179
  if (!suite.tests) return;
182
180
  for (const test of suite.tests) {
183
- const { id, tags, title } = test;
184
- failedTests.push(id || title);
181
+ const { uid, tags, title } = test;
182
+ failedTests.push(uid || title);
185
183
  const testId = getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`);
186
184
 
187
185
  client.addTestRun(STATUS.FAILED, {
188
- rid: id,
186
+ rid: uid,
189
187
  ...stripExampleFromTitle(title),
190
188
  suite_title: suite.title,
191
189
  test_id: testId,
@@ -199,8 +197,8 @@ function CodeceptReporter(config) {
199
197
  event.dispatcher.on(event.test.after, test => {
200
198
  if (test.state && test.state !== STATUS.FAILED) return;
201
199
  if (test.err) error = test.err;
202
- const { id, tags, title, artifacts } = test;
203
- failedTests.push(id || title);
200
+ const { uid, tags, title, artifacts } = test;
201
+ failedTests.push(uid || title);
204
202
  const testObj = getTestAndMessage(title);
205
203
 
206
204
  const files = [];
@@ -214,7 +212,7 @@ function CodeceptReporter(config) {
214
212
 
215
213
  client.addTestRun(STATUS.FAILED, {
216
214
  ...stripExampleFromTitle(title),
217
- rid: id,
215
+ rid: uid,
218
216
  test_id: getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`),
219
217
  suite_title: test.parent && test.parent.title,
220
218
  error,
@@ -230,20 +228,20 @@ function CodeceptReporter(config) {
230
228
  debug('artifacts', artifacts);
231
229
 
232
230
  for (const aid in artifacts) {
233
- if (aid.startsWith('video')) videos.push({ rid: id, title, path: artifacts[aid], type: 'video/webm' });
234
- if (aid.startsWith('trace')) traces.push({ rid: id, title, path: artifacts[aid], type: 'application/zip' });
231
+ if (aid.startsWith('video')) videos.push({ rid: uid, title, path: artifacts[aid], type: 'video/webm' });
232
+ if (aid.startsWith('trace')) traces.push({ rid: uid, title, path: artifacts[aid], type: 'application/zip' });
235
233
  }
236
234
 
237
235
  // output.stop();
238
236
  });
239
237
 
240
238
  event.dispatcher.on(event.test.skipped, test => {
241
- const { id, tags, title } = test;
242
- if (failedTests.includes(id || title)) return;
239
+ const { uid, tags, title } = test;
240
+ if (failedTests.includes(uid || title)) return;
243
241
 
244
242
  const testObj = getTestAndMessage(title);
245
243
  client.addTestRun(STATUS.SKIPPED, {
246
- rid: id,
244
+ rid: uid,
247
245
  ...stripExampleFromTitle(title),
248
246
  test_id: getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`),
249
247
  suite_title: test.parent && test.parent.title,
@@ -272,7 +270,6 @@ function CodeceptReporter(config) {
272
270
  for (let i = 0; i < Math.max(currentMetaStep.length, metaSteps.length); i++) {
273
271
  if (currentMetaStep[i] !== metaSteps[i]) {
274
272
  stepShift = 2 * i;
275
- // eslint-disable-next-line no-continue
276
273
  if (!metaSteps[i]) continue;
277
274
  if (metaSteps[i].isBDD()) {
278
275
  // output.push(repeat(stepShift) + pc.bold(metaSteps[i].toString()) + metaSteps[i].comment);
@@ -312,11 +309,17 @@ function CodeceptReporter(config) {
312
309
  async function uploadAttachments(client, attachments, messagePrefix, attachmentType) {
313
310
  if (!attachments?.length) return;
314
311
 
315
- console.log(APP_PREFIX, `Attachments: ${messagePrefix} ${attachments.length} ${attachmentType} ...`);
312
+ if (client.uploader.isEnabled) {
313
+ console.log(APP_PREFIX, `Attachments: ${messagePrefix} ${attachments.length} ${attachmentType} ...`);
314
+ }
316
315
 
317
316
  const promises = attachments.map(async attachment => {
318
317
  const { rid, title, path, type } = attachment;
319
318
  const file = { path, type, title };
319
+
320
+ // we are storing file if upload is disabled
321
+ if (!client.uploader.isEnabled) return client.uploader.storeUploadedFile(path, client.runId, rid, false);
322
+
320
323
  return client.addTestRun(undefined, {
321
324
  ...stripExampleFromTitle(title),
322
325
  rid,
@@ -367,3 +370,4 @@ function getTestLogs(test) {
367
370
  }
368
371
 
369
372
  export { CodeceptReporter };
373
+ export default CodeceptReporter;
@@ -1,7 +1,7 @@
1
1
  import { STATUS } from '../../constants.js';
2
2
  import { getTestomatIdFromTestTitle, parseSuite } from '../../utils/utils.js';
3
3
  import TestomatClient from '../../client.js';
4
- import {config} from '../../config.js';
4
+ import { config } from '../../config.js';
5
5
 
6
6
  const testomatioReporter = on => {
7
7
  if (!config.TESTOMATIO) {
@@ -44,22 +44,22 @@ const testomatioReporter = on => {
44
44
 
45
45
  if (!error && test.displayError) {
46
46
  error = { message: test.displayError };
47
- // eslint-disable-next-line
48
47
  error.inspect = function () {
49
48
  return this.message;
50
49
  };
51
50
  }
52
51
 
53
- const formattedError = error ? {
52
+ const formattedError = error
53
+ ? {
54
54
  message: error.message,
55
55
  name: error.name,
56
56
  inspect:
57
57
  error.inspect ||
58
- // eslint-disable-next-line
59
58
  function () {
60
59
  return this.message;
61
60
  },
62
- } : undefined;
61
+ }
62
+ : undefined;
63
63
 
64
64
  const screenshots = Array.isArray(results.screenshots)
65
65
  ? results.screenshots
@@ -1,2 +1,2 @@
1
- const MochaReporter = require('../../../lib/adapter/mocha/mocha.js');
1
+ const MochaReporter = require('../../../lib/adapter/mocha.js');
2
2
  module.exports = MochaReporter;
@@ -1,4 +1,3 @@
1
- // eslint-disable-next-line global-require, import/no-extraneous-dependencies
2
1
  import Mocha from 'mocha';
3
2
  import TestomatClient from '../client.js';
4
3
  import { STATUS, TESTOMAT_TMP_STORAGE_DIR } from '../constants.js';
@@ -33,6 +32,7 @@ function MochaReporter(runner, opts) {
33
32
  runner.on(EVENT_RUN_BEGIN, () => {
34
33
  client.createRun();
35
34
 
35
+ // clear dir with artifacts/logs
36
36
  fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
37
37
  });
38
38
 
@@ -66,7 +66,7 @@ function MochaReporter(runner, opts) {
66
66
  test_id: testId,
67
67
  suite_title: getSuiteTitle(test),
68
68
  title: getTestName(test),
69
- code: test.body.toString(),
69
+ code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
70
70
  file: getFile(test),
71
71
  time: test.duration,
72
72
  logs,
@@ -82,7 +82,7 @@ function MochaReporter(runner, opts) {
82
82
  client.addTestRun(STATUS.SKIPPED, {
83
83
  title: getTestName(test),
84
84
  suite_title: getSuiteTitle(test),
85
- code: test.body.toString(),
85
+ code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
86
86
  file: getFile(test),
87
87
  test_id: testId,
88
88
  time: test.duration,
@@ -102,7 +102,7 @@ function MochaReporter(runner, opts) {
102
102
  file: getFile(test),
103
103
  test_id: testId,
104
104
  title: getTestName(test),
105
- code: test.body.toString(),
105
+ code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
106
106
  time: test.duration,
107
107
  logs,
108
108
  });