@testomatio/reporter 1.4.6 → 1.4.7

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.
@@ -207,18 +207,18 @@ function CodeceptReporter(config) {
207
207
  services.setContext(null);
208
208
 
209
209
  client.addTestRun(STATUS.FAILED, {
210
- ...stripExampleFromTitle(title),
211
- rid: id,
212
- test_id: getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`),
213
- suite_title: test.parent && test.parent.title,
214
- error,
215
- message: testObj.message,
216
- time: getDuration(test),
217
- files,
218
- steps: global.testomatioDataStore?.steps?.join('\n') || null,
219
- logs,
220
- manuallyAttachedArtifacts,
221
- meta: keyValues,
210
+ ...stripExampleFromTitle(title),
211
+ rid: id,
212
+ test_id: getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`),
213
+ suite_title: test.parent && test.parent.title,
214
+ error,
215
+ message: testObj.message,
216
+ time: getDuration(test),
217
+ files,
218
+ steps: global.testomatioDataStore?.steps?.join('\n') || null,
219
+ logs,
220
+ manuallyAttachedArtifacts,
221
+ meta: keyValues,
222
222
  });
223
223
 
224
224
  debug('artifacts', artifacts);
@@ -319,7 +319,6 @@ async function uploadAttachments(client, attachments, messagePrefix, attachmentT
319
319
  });
320
320
 
321
321
  await Promise.all(promises);
322
-
323
322
  }
324
323
 
325
324
  function getTestAndMessage(title) {
@@ -39,14 +39,15 @@ class PlaywrightReporter {
39
39
  if (!this.client) return;
40
40
 
41
41
  const { title } = test;
42
-
43
42
  const { error, duration } = result;
44
-
45
43
  const suite_title = test.parent ? test.parent?.title : path.basename(test?.location?.file);
46
44
 
47
45
  const steps = [];
48
46
  for (const step of result.steps) {
49
- appendStep(step, steps);
47
+ const appendedStep = appendStep(step);
48
+ if (appendedStep) {
49
+ steps.push(appendedStep);
50
+ }
50
51
  }
51
52
 
52
53
  const fullTestTitle = getTestContextName(test);
@@ -56,22 +57,21 @@ class PlaywrightReporter {
56
57
  }
57
58
  const manuallyAttachedArtifacts = services.artifacts.get(fullTestTitle);
58
59
  const keyValues = services.keyValues.get(fullTestTitle);
59
-
60
60
  const rid = test.id || test.testId || uuidv4();
61
61
 
62
62
  const reportTestPromise = this.client.addTestRun(checkStatus(result.status), {
63
- rid,
64
- error,
65
- test_id: getTestomatIdFromTestTitle(`${title} ${test.tags?.join(' ')}`),
66
- suite_title,
67
- title,
68
- steps: steps.join('\n'),
69
- time: duration,
70
- logs,
71
- manuallyAttachedArtifacts,
72
- meta: keyValues,
73
- file: test.location?.file,
74
- });
63
+ rid,
64
+ error,
65
+ test_id: getTestomatIdFromTestTitle(`${title} ${test.tags?.join(' ')}`),
66
+ suite_title,
67
+ title,
68
+ steps: steps.length ? steps : undefined,
69
+ time: duration,
70
+ logs,
71
+ manuallyAttachedArtifacts,
72
+ meta: keyValues,
73
+ file: test.location?.file,
74
+ });
75
75
 
76
76
  this.uploads.push({
77
77
  rid,
@@ -146,18 +146,44 @@ function checkStatus(status) {
146
146
  );
147
147
  }
148
148
 
149
- function appendStep(step, steps = [], shift = 0) {
150
- const prefix = ' '.repeat(shift);
151
-
152
- if (step.error) {
153
- steps.push(`${prefix}${chalk.red(step.title)} ${chalk.gray(`${step.duration}ms`)}`);
154
- } else {
155
- steps.push(`${prefix}${step.title} ${chalk.gray(`${step.duration}ms`)}`);
149
+ function appendStep(step, shift = 0) {
150
+ let newCategory = step.category;
151
+ switch (newCategory) {
152
+ case 'test.step':
153
+ newCategory = 'user';
154
+ break;
155
+ case 'hook':
156
+ newCategory = 'hook';
157
+ break;
158
+ case 'attach':
159
+ return null; // Skip steps with category 'attach'
160
+ default:
161
+ newCategory = 'framework';
156
162
  }
157
163
 
164
+ const formattedSteps = [];
158
165
  for (const child of step.steps || []) {
159
- appendStep(child, steps, shift + 2);
166
+ const appendedChild = appendStep(child, shift + 2);
167
+ if (appendedChild) {
168
+ formattedSteps.push(appendedChild);
169
+ }
170
+ }
171
+
172
+ const resultStep = {
173
+ category: newCategory,
174
+ title: step.title,
175
+ duration: step.duration,
176
+ };
177
+
178
+ if (formattedSteps.length) {
179
+ resultStep.steps = formattedSteps;
160
180
  }
181
+
182
+ if (step.error !== undefined) {
183
+ resultStep.error = step.error;
184
+ }
185
+
186
+ return resultStep;
161
187
  }
162
188
 
163
189
  function tmpFile(prefix = 'tmp.') {
@@ -44,15 +44,10 @@ program
44
44
 
45
45
  let timeoutTimer;
46
46
  if (opts.timelimit) {
47
- timeoutTimer = setTimeout(
48
- () => {
49
- console.log(
50
- `⚠️ Reached timeout of ${opts.timelimit}s. Exiting... (Exit code is 0 to not fail the pipeline)`,
51
- );
52
- process.exit(0);
53
- },
54
- parseInt(opts.timelimit, 10) * 1000,
55
- );
47
+ timeoutTimer = setTimeout(() => {
48
+ console.log(`⚠️ Reached timeout of ${opts.timelimit}s. Exiting... (Exit code is 0 to not fail the pipeline)`);
49
+ process.exit(0);
50
+ }, parseInt(opts.timelimit, 10) * 1000);
56
51
  }
57
52
 
58
53
  try {
package/lib/client.js CHANGED
@@ -227,7 +227,7 @@ class Client {
227
227
  /**
228
228
  *
229
229
  * Updates the status of the current test run and finishes the run.
230
- * @param {'passed' | 'failed' | 'finished'} status - The status of the current test run.
230
+ * @param {'passed' | 'failed' | 'skipped' | 'finished'} status - The status of the current test run.
231
231
  * Must be one of "passed", "failed", or "finished"
232
232
  * @param {boolean} [isParallel] - Whether the current test run was executed in parallel with other tests.
233
233
  * @returns {Promise<any>} - A Promise that resolves when finishes the run.
@@ -276,7 +276,7 @@ class Client {
276
276
  */
277
277
  formatLogs({ error, steps, logs }) {
278
278
  error = error?.trim();
279
- steps = steps?.trim();
279
+ steps = typeof steps === 'string' ? steps?.trim() : steps;
280
280
  logs = logs?.trim();
281
281
 
282
282
  let testLogs = '';
@@ -299,7 +299,7 @@ class Client {
299
299
  stack += `${message}\n`;
300
300
 
301
301
  if (error.diff) {
302
- // diff for vitest
302
+ // diff for vitest
303
303
  stack += error.diff;
304
304
  stack += '\n\n';
305
305
  } else if (error.actual && error.expected && error.actual !== error.expected) {
@@ -79,13 +79,13 @@ class GitLabPipe {
79
79
  let summary = `${this.hiddenCommentData}
80
80
 
81
81
  | [![Testomat.io Report](${testomatLogoURL})](https://testomat.io) | ${statusEmoji(
82
- runParams.status,
83
- )} ${runParams.status.toUpperCase()} ${statusEmoji(runParams.status)} |
82
+ runParams.status,
83
+ )} ${runParams.status.toUpperCase()} ${statusEmoji(runParams.status)} |
84
84
  | --- | --- |
85
85
  | Tests | ✔️ **${this.tests.length}** tests run |
86
86
  | Summary | ${statusEmoji('failed')} **${failedCount}** failed; ${statusEmoji(
87
- 'passed',
88
- )} **${passedCount}** passed; **${statusEmoji('skipped')}** ${skippedCount} skipped |
87
+ 'passed',
88
+ )} **${passedCount}** passed; **${statusEmoji('skipped')}** ${skippedCount} skipped |
89
89
  | Duration | 🕐 **${humanizeDuration(
90
90
  parseInt(
91
91
  this.tests.reduce((a, t) => a + (t.run_time || 0), 0),
@@ -106,7 +106,6 @@ const fetchSourceCodeFromStackTrace = (stack = '') => {
106
106
  };
107
107
 
108
108
  const TEST_ID_REGEX = /@T([\w\d]{8})/;
109
- const SUITE_ID_REGEX = /@[Ss]([\w\d]{8})/;
110
109
 
111
110
  const fetchIdFromCode = (code, opts = {}) => {
112
111
  const comments = code
@@ -134,10 +133,6 @@ const fetchIdFromOutput = output => {
134
133
  return lines.find(c => c.match(TEST_ID_REGEX))?.match(TEST_ID_REGEX)?.[1];
135
134
  };
136
135
 
137
- const fetchSuiteId = (title) => {
138
- return title.find(c => c.match(/@s/))?.match(TEST_ID_REGEX)?.[1];
139
- };
140
-
141
136
  const fetchSourceCode = (contents, opts = {}) => {
142
137
  if (!opts.title && !opts.line) return '';
143
138
 
package/lib/xmlReader.js CHANGED
@@ -2,6 +2,7 @@ const debug = require('debug')('@testomatio/reporter:xml');
2
2
  const path = require('path');
3
3
  const chalk = require('chalk');
4
4
  const fs = require('fs');
5
+ const { randomUUID } = require('crypto');
5
6
  const { XMLParser } = require('fast-xml-parser');
6
7
  const { APP_PREFIX, STATUS } = require('./constants');
7
8
  const {
@@ -17,6 +18,8 @@ const pipesFactory = require('./pipe');
17
18
  const adapterFactory = require('./junit-adapter');
18
19
  const config = require('./config');
19
20
 
21
+ const ridRunId = randomUUID();
22
+
20
23
  const TESTOMATIO_URL = process.env.TESTOMATIO_URL || 'https://app.testomat.io';
21
24
  const { TESTOMATIO_RUNGROUP_TITLE, TESTOMATIO_TITLE, TESTOMATIO_ENV, TESTOMATIO_RUN } = process.env;
22
25
 
@@ -457,17 +460,20 @@ function reduceTestCases(prev, item) {
457
460
  if (testCaseItem.error && testCaseItem.error['#text']) stack = testCaseItem.error['#text'];
458
461
  if (!message) message = stack.trim().split('\n')[0];
459
462
 
463
+ const isParametrized = item.type === 'ParameterizedMethod';
464
+ const preferClassname = reduceOptions.preferClassname || isParametrized;
465
+
460
466
  // SpecFlow config
461
- let { title, tags } = fetchProperties(item.type === 'ParameterizedMethod' ? item : testCaseItem);
467
+ let { title, tags } = fetchProperties(isParametrized ? item : testCaseItem);
462
468
  let example = null;
463
- const suiteTitle = reduceOptions.preferClassname ? testCaseItem.classname : item.name || testCaseItem.classname;
469
+ const suiteTitle = preferClassname ? testCaseItem.classname : item.name || testCaseItem.classname;
464
470
 
465
471
  title ||= testCaseItem.name || testCaseItem.methodname || testCaseItem.classname;
466
472
  tags ||= [];
467
473
 
468
- const exampleMatches = title.match(/\((.*?)\)/);
474
+ const exampleMatches = testCaseItem.name?.match(/\S\((.*?)\)/);
469
475
  if (exampleMatches) {
470
- example = { ...exampleMatches[1].split(',').map(v => v.replace(/^['"]|['"]$/g, '')) };
476
+ example = { ...exampleMatches[1].split(',').map(v => v.trim().replace(/[^\w\s-]/g, '')) };
471
477
  title = title.replace(/\(.*?\)/, '').trim();
472
478
  }
473
479
 
@@ -481,12 +487,16 @@ function reduceTestCases(prev, item) {
481
487
  if ('failure' in testCaseItem || 'error' in testCaseItem) status = STATUS.FAILED;
482
488
  if ('skipped' in testCaseItem) status = STATUS.SKIPPED;
483
489
 
490
+ let rid = null;
491
+ if (testCaseItem.id) rid = `${ridRunId}-${testCaseItem.id}`;
492
+
484
493
  prev.push({
485
- create: true,
494
+ rid,
486
495
  file,
487
496
  stack,
488
497
  example,
489
498
  tags,
499
+ create: true,
490
500
  test_id: testId,
491
501
  message,
492
502
  line: testCaseItem.lineno,
@@ -510,9 +520,9 @@ function processTestSuite(testsuite) {
510
520
  suites = [testsuite];
511
521
  }
512
522
 
513
- const res = suites.flat().reduce(reduceTestCases, []);
523
+ const subSuites = suites.filter(s => s['test-suite'] && !testsuite['test-case']);
514
524
 
515
- return res;
525
+ return [...subSuites.map(s => processTestSuite(s['test-suite'])), ...suites.reduce(reduceTestCases, [])].flat();
516
526
  }
517
527
 
518
528
  function fetchProperties(item) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "1.4.6",
3
+ "version": "1.4.7",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "main": "./lib/reporter.js",
6
6
  "typings": "typings/index.d.ts",