@testomatio/reporter 1.5.0-beta-vitest → 1.5.1-beta
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 +39 -44
- package/lib/adapter/playwright.js +65 -43
- package/lib/bin/reportXml.js +4 -9
- package/lib/client.js +26 -2
- package/lib/pipe/gitlab.js +4 -4
- package/lib/pipe/testomatio.js +12 -0
- package/lib/xmlReader.js +18 -7
- package/package.json +4 -4
package/lib/adapter/codecept.js
CHANGED
|
@@ -129,8 +129,8 @@ function CodeceptReporter(config) {
|
|
|
129
129
|
await Promise.all(reportTestPromises);
|
|
130
130
|
|
|
131
131
|
if (upload.isArtifactsEnabled()) {
|
|
132
|
-
uploadAttachments(client, videos, '🎞️
|
|
133
|
-
uploadAttachments(client, traces, '📁 Uploading', 'trace');
|
|
132
|
+
await uploadAttachments(client, videos, '🎞️ Uploading', 'video');
|
|
133
|
+
await uploadAttachments(client, traces, '📁 Uploading', 'trace');
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
const status = failedTests.length === 0 ? STATUS.PASSED : STATUS.FAILED;
|
|
@@ -142,7 +142,6 @@ function CodeceptReporter(config) {
|
|
|
142
142
|
if (id && failedTests.includes(id)) {
|
|
143
143
|
failedTests = failedTests.filter(failed => id !== failed);
|
|
144
144
|
}
|
|
145
|
-
const testId = getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`);
|
|
146
145
|
const testObj = getTestAndMessage(title);
|
|
147
146
|
|
|
148
147
|
const logs = getTestLogs(test);
|
|
@@ -152,11 +151,12 @@ function CodeceptReporter(config) {
|
|
|
152
151
|
|
|
153
152
|
client.addTestRun(STATUS.PASSED, {
|
|
154
153
|
...stripExampleFromTitle(title),
|
|
154
|
+
rid: id,
|
|
155
155
|
suite_title: test.parent && test.parent.title,
|
|
156
156
|
message: testObj.message,
|
|
157
157
|
time: getDuration(test),
|
|
158
158
|
steps: global.testomatioDataStore.steps.join('\n') || null,
|
|
159
|
-
test_id:
|
|
159
|
+
test_id: getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`),
|
|
160
160
|
logs,
|
|
161
161
|
manuallyAttachedArtifacts,
|
|
162
162
|
meta: keyValues,
|
|
@@ -179,6 +179,7 @@ function CodeceptReporter(config) {
|
|
|
179
179
|
const testId = getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`);
|
|
180
180
|
|
|
181
181
|
client.addTestRun(STATUS.FAILED, {
|
|
182
|
+
rid: id,
|
|
182
183
|
...stripExampleFromTitle(title),
|
|
183
184
|
suite_title: suite.title,
|
|
184
185
|
test_id: testId,
|
|
@@ -194,7 +195,6 @@ function CodeceptReporter(config) {
|
|
|
194
195
|
if (test.err) error = test.err;
|
|
195
196
|
const { id, tags, title, artifacts } = test;
|
|
196
197
|
failedTests.push(id || title);
|
|
197
|
-
let testId = getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`);
|
|
198
198
|
const testObj = getTestAndMessage(title);
|
|
199
199
|
|
|
200
200
|
const files = [];
|
|
@@ -206,32 +206,27 @@ function CodeceptReporter(config) {
|
|
|
206
206
|
const keyValues = services.keyValues.get(test.fullTitle());
|
|
207
207
|
services.setContext(null);
|
|
208
208
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
debug('artifacts', artifacts);
|
|
227
|
-
|
|
228
|
-
for (const aid in artifacts) {
|
|
229
|
-
if (aid.startsWith('video')) videos.push({ testId, title, path: artifacts[aid], type: 'video/webm' });
|
|
230
|
-
if (aid.startsWith('trace')) traces.push({ testId, title, path: artifacts[aid], type: 'application/zip' });
|
|
231
|
-
}
|
|
232
|
-
});
|
|
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,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
debug('artifacts', artifacts);
|
|
233
225
|
|
|
234
|
-
|
|
226
|
+
for (const aid in artifacts) {
|
|
227
|
+
if (aid.startsWith('video')) videos.push({ rid: id, title, path: artifacts[aid], type: 'video/webm' });
|
|
228
|
+
if (aid.startsWith('trace')) traces.push({ rid: id, title, path: artifacts[aid], type: 'application/zip' });
|
|
229
|
+
}
|
|
235
230
|
|
|
236
231
|
// output.stop();
|
|
237
232
|
});
|
|
@@ -240,11 +235,11 @@ function CodeceptReporter(config) {
|
|
|
240
235
|
const { id, tags, title } = test;
|
|
241
236
|
if (failedTests.includes(id || title)) return;
|
|
242
237
|
|
|
243
|
-
const testId = getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`);
|
|
244
238
|
const testObj = getTestAndMessage(title);
|
|
245
239
|
client.addTestRun(STATUS.SKIPPED, {
|
|
240
|
+
rid: id,
|
|
246
241
|
...stripExampleFromTitle(title),
|
|
247
|
-
test_id:
|
|
242
|
+
test_id: getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`),
|
|
248
243
|
suite_title: test.parent && test.parent.title,
|
|
249
244
|
message: testObj.message,
|
|
250
245
|
time: getDuration(test),
|
|
@@ -309,21 +304,21 @@ function CodeceptReporter(config) {
|
|
|
309
304
|
}
|
|
310
305
|
|
|
311
306
|
async function uploadAttachments(client, attachments, messagePrefix, attachmentType) {
|
|
312
|
-
if (attachments
|
|
313
|
-
console.log(APP_PREFIX, `Attachments: ${messagePrefix} ${attachments.length} ${attachmentType}/-s ...`);
|
|
307
|
+
if (!attachments?.length) return;
|
|
314
308
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
309
|
+
console.log(APP_PREFIX, `Attachments: ${messagePrefix} ${attachments.length} ${attachmentType} ...`);
|
|
310
|
+
|
|
311
|
+
const promises = attachments.map(async attachment => {
|
|
312
|
+
const { rid, title, path, type } = attachment;
|
|
313
|
+
const file = { path, type, title };
|
|
314
|
+
return client.addTestRun(undefined, {
|
|
315
|
+
...stripExampleFromTitle(title),
|
|
316
|
+
rid,
|
|
317
|
+
files: [file],
|
|
323
318
|
});
|
|
319
|
+
});
|
|
324
320
|
|
|
325
|
-
|
|
326
|
-
}
|
|
321
|
+
await Promise.all(promises);
|
|
327
322
|
}
|
|
328
323
|
|
|
329
324
|
function getTestAndMessage(title) {
|
|
@@ -2,6 +2,7 @@ const chalk = require('chalk');
|
|
|
2
2
|
const crypto = require('crypto');
|
|
3
3
|
const os = require('os');
|
|
4
4
|
const path = require('path');
|
|
5
|
+
const { v4: uuidv4 } = require('uuid');
|
|
5
6
|
const fs = require('fs');
|
|
6
7
|
const { APP_PREFIX, STATUS: Status, TESTOMAT_TMP_STORAGE_DIR } = require('../constants');
|
|
7
8
|
const TestomatioClient = require('../client');
|
|
@@ -38,16 +39,15 @@ class PlaywrightReporter {
|
|
|
38
39
|
if (!this.client) return;
|
|
39
40
|
|
|
40
41
|
const { title } = test;
|
|
41
|
-
|
|
42
|
-
let testId = getTestomatIdFromTestTitle(`${title} ${test.tags?.join(' ')}`);
|
|
43
|
-
|
|
44
42
|
const { error, duration } = result;
|
|
45
|
-
|
|
46
43
|
const suite_title = test.parent ? test.parent?.title : path.basename(test?.location?.file);
|
|
47
44
|
|
|
48
45
|
const steps = [];
|
|
49
46
|
for (const step of result.steps) {
|
|
50
|
-
appendStep(step
|
|
47
|
+
const appendedStep = appendStep(step);
|
|
48
|
+
if (appendedStep) {
|
|
49
|
+
steps.push(appendedStep);
|
|
50
|
+
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const fullTestTitle = getTestContextName(test);
|
|
@@ -57,33 +57,30 @@ class PlaywrightReporter {
|
|
|
57
57
|
}
|
|
58
58
|
const manuallyAttachedArtifacts = services.artifacts.get(fullTestTitle);
|
|
59
59
|
const keyValues = services.keyValues.get(fullTestTitle);
|
|
60
|
+
const rid = test.id || test.testId || uuidv4();
|
|
61
|
+
|
|
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.length ? steps : undefined,
|
|
69
|
+
time: duration,
|
|
70
|
+
logs,
|
|
71
|
+
manuallyAttachedArtifacts,
|
|
72
|
+
meta: keyValues,
|
|
73
|
+
file: test.location?.file,
|
|
74
|
+
});
|
|
60
75
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
logs,
|
|
70
|
-
manuallyAttachedArtifacts,
|
|
71
|
-
meta: keyValues,
|
|
72
|
-
file: test.location?.file,
|
|
73
|
-
})
|
|
74
|
-
.then(pipes => {
|
|
75
|
-
testId = pipes?.filter(p => p.pipe.includes('Testomatio'))[0]?.result?.data?.test_id;
|
|
76
|
-
|
|
77
|
-
this.uploads.push({
|
|
78
|
-
testId,
|
|
79
|
-
title,
|
|
80
|
-
suite_title,
|
|
81
|
-
files: result.attachments.filter(a => a.body || a.path),
|
|
82
|
-
file: test.location?.file,
|
|
83
|
-
});
|
|
84
|
-
// remove empty uploads
|
|
85
|
-
this.uploads = this.uploads.filter(upload => upload.files.length);
|
|
86
|
-
});
|
|
76
|
+
this.uploads.push({
|
|
77
|
+
rid,
|
|
78
|
+
title: test.title,
|
|
79
|
+
files: result.attachments.filter(a => a.body || a.path),
|
|
80
|
+
file: test.location?.file,
|
|
81
|
+
});
|
|
82
|
+
// remove empty uploads
|
|
83
|
+
this.uploads = this.uploads.filter(upload => upload.files.length);
|
|
87
84
|
|
|
88
85
|
reportTestPromises.push(reportTestPromise);
|
|
89
86
|
}
|
|
@@ -115,7 +112,7 @@ class PlaywrightReporter {
|
|
|
115
112
|
const promises = [];
|
|
116
113
|
|
|
117
114
|
for (const upload of this.uploads) {
|
|
118
|
-
const {
|
|
115
|
+
const { rid, file, title } = upload;
|
|
119
116
|
|
|
120
117
|
const files = upload.files.map(attachment => ({
|
|
121
118
|
path: this.#getArtifactPath(attachment),
|
|
@@ -125,11 +122,10 @@ class PlaywrightReporter {
|
|
|
125
122
|
|
|
126
123
|
promises.push(
|
|
127
124
|
this.client.addTestRun(undefined, {
|
|
128
|
-
|
|
125
|
+
rid,
|
|
129
126
|
title,
|
|
130
|
-
suite_title,
|
|
131
127
|
files,
|
|
132
|
-
file
|
|
128
|
+
file,
|
|
133
129
|
}),
|
|
134
130
|
);
|
|
135
131
|
}
|
|
@@ -150,18 +146,44 @@ function checkStatus(status) {
|
|
|
150
146
|
);
|
|
151
147
|
}
|
|
152
148
|
|
|
153
|
-
function appendStep(step,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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';
|
|
160
162
|
}
|
|
161
163
|
|
|
164
|
+
const formattedSteps = [];
|
|
162
165
|
for (const child of step.steps || []) {
|
|
163
|
-
appendStep(child,
|
|
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;
|
|
164
180
|
}
|
|
181
|
+
|
|
182
|
+
if (step.error !== undefined) {
|
|
183
|
+
resultStep.error = step.error;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return resultStep;
|
|
165
187
|
}
|
|
166
188
|
|
|
167
189
|
function tmpFile(prefix = 'tmp.') {
|
package/lib/bin/reportXml.js
CHANGED
|
@@ -44,15 +44,10 @@ program
|
|
|
44
44
|
|
|
45
45
|
let timeoutTimer;
|
|
46
46
|
if (opts.timelimit) {
|
|
47
|
-
timeoutTimer = setTimeout(
|
|
48
|
-
(
|
|
49
|
-
|
|
50
|
-
|
|
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
|
@@ -137,6 +137,7 @@ class Client {
|
|
|
137
137
|
* @type {TestData}
|
|
138
138
|
*/
|
|
139
139
|
const {
|
|
140
|
+
rid,
|
|
140
141
|
error = null,
|
|
141
142
|
time = 0,
|
|
142
143
|
example = null,
|
|
@@ -187,6 +188,7 @@ class Client {
|
|
|
187
188
|
this.totalUploaded += artifacts.length;
|
|
188
189
|
|
|
189
190
|
const data = {
|
|
191
|
+
rid,
|
|
190
192
|
files,
|
|
191
193
|
steps,
|
|
192
194
|
status,
|
|
@@ -225,7 +227,7 @@ class Client {
|
|
|
225
227
|
/**
|
|
226
228
|
*
|
|
227
229
|
* Updates the status of the current test run and finishes the run.
|
|
228
|
-
* @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.
|
|
229
231
|
* Must be one of "passed", "failed", or "finished"
|
|
230
232
|
* @param {boolean} [isParallel] - Whether the current test run was executed in parallel with other tests.
|
|
231
233
|
* @returns {Promise<any>} - A Promise that resolves when finishes the run.
|
|
@@ -274,9 +276,12 @@ class Client {
|
|
|
274
276
|
*/
|
|
275
277
|
formatLogs({ error, steps, logs }) {
|
|
276
278
|
error = error?.trim();
|
|
277
|
-
steps = steps?.trim();
|
|
278
279
|
logs = logs?.trim();
|
|
279
280
|
|
|
281
|
+
if (Array.isArray(steps)) {
|
|
282
|
+
steps = steps.map(step => formatStep(step)).flat().join('\n');
|
|
283
|
+
}
|
|
284
|
+
|
|
280
285
|
let testLogs = '';
|
|
281
286
|
if (steps) testLogs += `${chalk.bold.blue('################[ Steps ]################')}\n${steps}\n\n`;
|
|
282
287
|
if (logs) testLogs += `${chalk.bold.gray('################[ Logs ]################')}\n${logs}\n\n`;
|
|
@@ -297,6 +302,7 @@ class Client {
|
|
|
297
302
|
stack += `${message}\n`;
|
|
298
303
|
|
|
299
304
|
if (error.diff) {
|
|
305
|
+
// diff for vitest
|
|
300
306
|
stack += error.diff;
|
|
301
307
|
stack += '\n\n';
|
|
302
308
|
} else if (error.actual && error.expected && error.actual !== error.expected) {
|
|
@@ -339,6 +345,24 @@ function isNotInternalFrame(frame) {
|
|
|
339
345
|
);
|
|
340
346
|
}
|
|
341
347
|
|
|
348
|
+
function formatStep(step, shift = 0) {
|
|
349
|
+
const prefix = ' '.repeat(shift);
|
|
350
|
+
|
|
351
|
+
const lines = [];
|
|
352
|
+
|
|
353
|
+
if (step.error) {
|
|
354
|
+
lines.push(`${prefix}${chalk.red(step.title)} ${chalk.gray(`${step.duration}ms`)}`);
|
|
355
|
+
} else {
|
|
356
|
+
lines.push(`${prefix}${step.title} ${chalk.gray(`${step.duration}ms`)}`);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
for (const child of step.steps || []) {
|
|
360
|
+
lines.push(...formatStep(child, shift + 2));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return lines;
|
|
364
|
+
}
|
|
365
|
+
|
|
342
366
|
/**
|
|
343
367
|
*
|
|
344
368
|
* @param {TestData} testData
|
package/lib/pipe/gitlab.js
CHANGED
|
@@ -79,13 +79,13 @@ class GitLabPipe {
|
|
|
79
79
|
let summary = `${this.hiddenCommentData}
|
|
80
80
|
|
|
81
81
|
| [](https://testomat.io) | ${statusEmoji(
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
88
|
-
|
|
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),
|
package/lib/pipe/testomatio.js
CHANGED
|
@@ -42,6 +42,10 @@ class TestomatioPipe {
|
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
44
|
debug('Testomatio Pipe: Enabled');
|
|
45
|
+
|
|
46
|
+
const proxyUrl = process.env.HTTP_PROXY || process.env.HTTPS_PROXY;
|
|
47
|
+
const proxy = proxyUrl ? new URL(proxyUrl) : null;
|
|
48
|
+
|
|
45
49
|
this.parallel = params.parallel;
|
|
46
50
|
this.store = store || {};
|
|
47
51
|
this.title = params.title || process.env.TESTOMATIO_TITLE;
|
|
@@ -53,6 +57,11 @@ class TestomatioPipe {
|
|
|
53
57
|
this.axios = axios.create({
|
|
54
58
|
baseURL: `${this.url.trim()}`,
|
|
55
59
|
timeout: AXIOS_TIMEOUT,
|
|
60
|
+
proxy: proxy ? {
|
|
61
|
+
host: proxy.hostname,
|
|
62
|
+
port: proxy.port,
|
|
63
|
+
protocol: proxy.protocol,
|
|
64
|
+
} : false,
|
|
56
65
|
});
|
|
57
66
|
|
|
58
67
|
// Pass the axios instance to the retry function
|
|
@@ -339,6 +348,9 @@ class TestomatioPipe {
|
|
|
339
348
|
addTest(data) {
|
|
340
349
|
if (!this.isEnabled) return;
|
|
341
350
|
if (!this.runId) return;
|
|
351
|
+
|
|
352
|
+
// add test ID + run ID
|
|
353
|
+
if (data.rid) data.rid = `${this.runId}-${data.rid}`;
|
|
342
354
|
data.api_key = this.apiKey;
|
|
343
355
|
data.create = this.createNewTests;
|
|
344
356
|
|
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,16 +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(
|
|
467
|
+
let { title, tags } = fetchProperties(isParametrized ? item : testCaseItem);
|
|
462
468
|
let example = null;
|
|
469
|
+
const suiteTitle = preferClassname ? testCaseItem.classname : item.name || testCaseItem.classname;
|
|
463
470
|
|
|
464
471
|
title ||= testCaseItem.name || testCaseItem.methodname || testCaseItem.classname;
|
|
465
472
|
tags ||= [];
|
|
466
473
|
|
|
467
|
-
const exampleMatches =
|
|
474
|
+
const exampleMatches = testCaseItem.name?.match(/\S\((.*?)\)/);
|
|
468
475
|
if (exampleMatches) {
|
|
469
|
-
example = { ...exampleMatches[1].split(',').map(v => v.replace(
|
|
476
|
+
example = { ...exampleMatches[1].split(',').map(v => v.trim().replace(/[^\w\s-]/g, '')) };
|
|
470
477
|
title = title.replace(/\(.*?\)/, '').trim();
|
|
471
478
|
}
|
|
472
479
|
|
|
@@ -480,12 +487,16 @@ function reduceTestCases(prev, item) {
|
|
|
480
487
|
if ('failure' in testCaseItem || 'error' in testCaseItem) status = STATUS.FAILED;
|
|
481
488
|
if ('skipped' in testCaseItem) status = STATUS.SKIPPED;
|
|
482
489
|
|
|
490
|
+
let rid = null;
|
|
491
|
+
if (testCaseItem.id) rid = `${ridRunId}-${testCaseItem.id}`;
|
|
492
|
+
|
|
483
493
|
prev.push({
|
|
484
|
-
|
|
494
|
+
rid,
|
|
485
495
|
file,
|
|
486
496
|
stack,
|
|
487
497
|
example,
|
|
488
498
|
tags,
|
|
499
|
+
create: true,
|
|
489
500
|
test_id: testId,
|
|
490
501
|
message,
|
|
491
502
|
line: testCaseItem.lineno,
|
|
@@ -493,7 +504,7 @@ function reduceTestCases(prev, item) {
|
|
|
493
504
|
run_time: parseFloat(testCaseItem.time || testCaseItem.duration) * 1000,
|
|
494
505
|
status,
|
|
495
506
|
title,
|
|
496
|
-
suite_title:
|
|
507
|
+
suite_title: suiteTitle,
|
|
497
508
|
});
|
|
498
509
|
});
|
|
499
510
|
return prev;
|
|
@@ -509,9 +520,9 @@ function processTestSuite(testsuite) {
|
|
|
509
520
|
suites = [testsuite];
|
|
510
521
|
}
|
|
511
522
|
|
|
512
|
-
const
|
|
523
|
+
const subSuites = suites.filter(s => s['test-suite'] && !testsuite['test-case']);
|
|
513
524
|
|
|
514
|
-
return
|
|
525
|
+
return [...subSuites.map(s => processTestSuite(s['test-suite'])), ...suites.reduce(reduceTestCases, [])].flat();
|
|
515
526
|
}
|
|
516
527
|
|
|
517
528
|
function fetchProperties(item) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testomatio/reporter",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1-beta",
|
|
4
4
|
"description": "Testomatio Reporter Client",
|
|
5
5
|
"main": "./lib/reporter.js",
|
|
6
6
|
"typings": "typings/index.d.ts",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"csv-writer": "^1.6.0",
|
|
21
21
|
"debug": "^4.3.4",
|
|
22
22
|
"dotenv": "^16.0.1",
|
|
23
|
-
"fast-xml-parser": "^4.
|
|
23
|
+
"fast-xml-parser": "^4.4.1",
|
|
24
24
|
"file-url": "3.0.0",
|
|
25
25
|
"glob": "^10.3",
|
|
26
26
|
"handlebars": "^4.7.8",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"@redocly/cli": "^1.0.0-beta.125",
|
|
64
64
|
"@wdio/reporter": "^7.16.13",
|
|
65
65
|
"chai": "^4.3.6",
|
|
66
|
-
"codeceptjs": "
|
|
66
|
+
"codeceptjs": "^3.5.11",
|
|
67
67
|
"cucumber": "^6.0.7",
|
|
68
68
|
"eslint": "^8.7.0",
|
|
69
69
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"mock-http-server": "^1.4.5",
|
|
77
77
|
"pino": "^8.15.0",
|
|
78
78
|
"prettier": "^3.2.5",
|
|
79
|
-
"puppeteer": "^
|
|
79
|
+
"puppeteer": "^22.15.0"
|
|
80
80
|
},
|
|
81
81
|
"bin": {
|
|
82
82
|
"report-xml": "./lib/bin/reportXml.js",
|