@testomatio/reporter 2.3.8 → 2.3.9
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 +12 -9
- package/lib/client.d.ts +0 -10
- package/lib/client.js +14 -126
- package/lib/junit-adapter/csharp.js +4 -1
- package/lib/junit-adapter/nunit-parser.js +4 -2
- package/lib/pipe/bitbucket.js +5 -5
- package/lib/pipe/gitlab.js +4 -4
- package/lib/pipe/testomatio.js +17 -13
- package/lib/reporter-functions.js +1 -3
- package/lib/utils/log-formatter.d.ts +28 -0
- package/lib/utils/log-formatter.js +127 -0
- package/lib/xmlReader.js +14 -4
- package/package.json +2 -2
- package/src/adapter/codecept.js +19 -19
- package/src/adapter/mocha.js +1 -1
- package/src/adapter/playwright.js +2 -2
- package/src/bin/cli.js +1 -1
- package/src/client.js +15 -112
- package/src/junit-adapter/csharp.js +4 -1
- package/src/junit-adapter/nunit-parser.js +9 -7
- package/src/pipe/bitbucket.js +5 -5
- package/src/pipe/debug.js +1 -2
- package/src/pipe/gitlab.js +4 -4
- package/src/pipe/testomatio.js +73 -79
- package/src/reporter-functions.js +2 -3
- package/src/reporter.js +1 -2
- package/src/services/links.js +1 -1
- package/src/utils/log-formatter.js +113 -0
- package/src/xmlReader.js +14 -4
package/lib/xmlReader.js
CHANGED
|
@@ -221,9 +221,14 @@ class XmlReader {
|
|
|
221
221
|
_parseTRXTestDefinition(td) {
|
|
222
222
|
const title = td.name.replace(/\(.*?\)/, '').trim();
|
|
223
223
|
const exampleMatch = td.name.match(/\((.*?)\)/);
|
|
224
|
-
const example = exampleMatch
|
|
225
|
-
|
|
226
|
-
|
|
224
|
+
const example = exampleMatch
|
|
225
|
+
? {
|
|
226
|
+
...exampleMatch[1]
|
|
227
|
+
.split(',')
|
|
228
|
+
.map(p => p.trim())
|
|
229
|
+
.filter(p => p !== ''),
|
|
230
|
+
}
|
|
231
|
+
: null;
|
|
227
232
|
const suite = td.TestMethod.className.split(', ')[0].split('.');
|
|
228
233
|
const suite_title = suite.pop();
|
|
229
234
|
// Convert namespace to file path for C#
|
|
@@ -518,7 +523,12 @@ function reduceTestCases(prev, item) {
|
|
|
518
523
|
tags ||= [];
|
|
519
524
|
const exampleMatches = testCaseItem.name?.match(/\S\((.*?)\)/);
|
|
520
525
|
if (exampleMatches) {
|
|
521
|
-
example = {
|
|
526
|
+
example = {
|
|
527
|
+
...exampleMatches[1]
|
|
528
|
+
.split(',')
|
|
529
|
+
.map(v => v.trim().replace(/[^\w\s-]/g, ''))
|
|
530
|
+
.filter(v => v !== ''),
|
|
531
|
+
};
|
|
522
532
|
title = title.replace(/\(.*?\)/, '').trim();
|
|
523
533
|
}
|
|
524
534
|
stack = `${testCaseItem['system-out'] || testCaseItem.output || testCaseItem.log || ''}\n\n${stack}\n\n${suiteOutput}\n\n${suiteErr}`.trim();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testomatio/reporter",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.9",
|
|
4
4
|
"description": "Testomatio Reporter Client",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18"
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
"vitest": "^1.6.0"
|
|
107
107
|
},
|
|
108
108
|
"bin": {
|
|
109
|
-
"
|
|
109
|
+
"testomatio/reporter": "./lib/bin/cli.js",
|
|
110
110
|
"report-xml": "./lib/bin/reportXml.js",
|
|
111
111
|
"start-test-run": "./lib/bin/startTest.js",
|
|
112
112
|
"upload-artifacts": "./lib/bin/uploadArtifacts.js"
|
package/src/adapter/codecept.js
CHANGED
|
@@ -17,12 +17,15 @@ if (!global.codeceptjs) {
|
|
|
17
17
|
// @ts-ignore
|
|
18
18
|
const { event, recorder, codecept, output } = global.codeceptjs;
|
|
19
19
|
|
|
20
|
-
const [, MAJOR_VERSION, MINOR_VERSION] = codecept
|
|
20
|
+
const [, MAJOR_VERSION, MINOR_VERSION] = codecept
|
|
21
|
+
.version()
|
|
22
|
+
.match(/(\d+)\.(\d+)/)
|
|
23
|
+
.map(Number);
|
|
21
24
|
|
|
22
25
|
// Constants for hook execution order
|
|
23
26
|
const HOOK_EXECUTION_ORDER = {
|
|
24
27
|
PRE_TEST: ['BeforeSuiteHook', 'BeforeHook'],
|
|
25
|
-
POST_TEST: ['AfterHook', 'AfterSuiteHook']
|
|
28
|
+
POST_TEST: ['AfterHook', 'AfterSuiteHook'],
|
|
26
29
|
};
|
|
27
30
|
|
|
28
31
|
// codeceptjs workers are self-contained
|
|
@@ -35,7 +38,9 @@ if (MAJOR_VERSION < 3) {
|
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
if (MAJOR_VERSION === 3 && MINOR_VERSION < 7) {
|
|
38
|
-
console.log(
|
|
41
|
+
console.log(
|
|
42
|
+
'🔴 CodeceptJS 3.7+ is supported, please upgrade CodeceptJS or use 1.6 version of `@testomatio/reporter`',
|
|
43
|
+
);
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
function CodeceptReporter(config) {
|
|
@@ -57,18 +62,18 @@ function CodeceptReporter(config) {
|
|
|
57
62
|
say: output.say,
|
|
58
63
|
};
|
|
59
64
|
|
|
60
|
-
output.debug = function(msg) {
|
|
65
|
+
output.debug = function (msg) {
|
|
61
66
|
originalOutput.debug(msg);
|
|
62
67
|
dataStorage.putData('log', repeat(this?.stepShift || 0) + pc.cyan(msg.toString()));
|
|
63
68
|
};
|
|
64
69
|
|
|
65
|
-
output.say = function(message, color = 'cyan') {
|
|
70
|
+
output.say = function (message, color = 'cyan') {
|
|
66
71
|
originalOutput.say(message, color);
|
|
67
72
|
const sayMsg = repeat(this?.stepShift || 0) + ` ${pc.bold(pc[color](message))}`;
|
|
68
73
|
dataStorage.putData('log', sayMsg);
|
|
69
74
|
};
|
|
70
75
|
|
|
71
|
-
output.log = function(msg) {
|
|
76
|
+
output.log = function (msg) {
|
|
72
77
|
originalOutput.log(msg);
|
|
73
78
|
dataStorage.putData('log', repeat(this?.stepShift || 0) + pc.gray(msg));
|
|
74
79
|
};
|
|
@@ -108,7 +113,7 @@ function CodeceptReporter(config) {
|
|
|
108
113
|
});
|
|
109
114
|
|
|
110
115
|
// Hook event listeners
|
|
111
|
-
event.dispatcher.on(event.hook.started,
|
|
116
|
+
event.dispatcher.on(event.hook.started, hook => {
|
|
112
117
|
output.stepShift = 2;
|
|
113
118
|
currentHook = hook.name;
|
|
114
119
|
let title = hook.hookName;
|
|
@@ -126,7 +131,6 @@ function CodeceptReporter(config) {
|
|
|
126
131
|
services.setContext(null);
|
|
127
132
|
});
|
|
128
133
|
|
|
129
|
-
|
|
130
134
|
// mark as failed all tests inside the failed hook
|
|
131
135
|
event.dispatcher.on(event.hook.failed, hook => {
|
|
132
136
|
if (hook.name !== 'BeforeSuiteHook') return;
|
|
@@ -148,7 +152,6 @@ function CodeceptReporter(config) {
|
|
|
148
152
|
}
|
|
149
153
|
});
|
|
150
154
|
|
|
151
|
-
|
|
152
155
|
event.dispatcher.on(event.suite.before, suite => {
|
|
153
156
|
dataStorage.setContext(suite.fullTitle());
|
|
154
157
|
});
|
|
@@ -167,7 +170,7 @@ function CodeceptReporter(config) {
|
|
|
167
170
|
testTimeMap[test.uid] = Date.now();
|
|
168
171
|
});
|
|
169
172
|
|
|
170
|
-
event.dispatcher.on(event.all.result, async
|
|
173
|
+
event.dispatcher.on(event.all.result, async result => {
|
|
171
174
|
debug('waiting for all tests to be reported');
|
|
172
175
|
// all tests were reported and we can upload videos
|
|
173
176
|
await Promise.all(reportTestPromises);
|
|
@@ -327,7 +330,7 @@ function captureHookStep(step, currentHook, hookSteps) {
|
|
|
327
330
|
status: step.status,
|
|
328
331
|
startTime,
|
|
329
332
|
endTime,
|
|
330
|
-
helperMethod: step.helperMethod
|
|
333
|
+
helperMethod: step.helperMethod,
|
|
331
334
|
});
|
|
332
335
|
hookSteps.set(currentHook, hookStepsArray);
|
|
333
336
|
}
|
|
@@ -422,13 +425,12 @@ function processTestSteps(steps, hierarchy) {
|
|
|
422
425
|
}
|
|
423
426
|
}
|
|
424
427
|
|
|
425
|
-
|
|
426
428
|
function createSectionStep(metaStep) {
|
|
427
429
|
return {
|
|
428
430
|
category: 'user',
|
|
429
431
|
title: metaStep.toString(), // Use built-in toString method
|
|
430
432
|
duration: metaStep.duration || 0, // Use built-in duration
|
|
431
|
-
steps: []
|
|
433
|
+
steps: [],
|
|
432
434
|
};
|
|
433
435
|
}
|
|
434
436
|
|
|
@@ -439,7 +441,7 @@ function createHookSection(hookName, steps) {
|
|
|
439
441
|
category: 'hook',
|
|
440
442
|
title: formatHookName(hookName),
|
|
441
443
|
duration: 0,
|
|
442
|
-
steps: []
|
|
444
|
+
steps: [],
|
|
443
445
|
};
|
|
444
446
|
|
|
445
447
|
for (const step of steps) {
|
|
@@ -457,7 +459,6 @@ function formatHookName(hookName) {
|
|
|
457
459
|
return hookName.replace(/Hook$/, '');
|
|
458
460
|
}
|
|
459
461
|
|
|
460
|
-
|
|
461
462
|
// Format CodeceptJS step using its built-in methods
|
|
462
463
|
function formatCodeceptStep(step) {
|
|
463
464
|
if (!step) return null;
|
|
@@ -469,14 +470,14 @@ function formatCodeceptStep(step) {
|
|
|
469
470
|
const formattedStep = {
|
|
470
471
|
category,
|
|
471
472
|
title,
|
|
472
|
-
duration
|
|
473
|
+
duration,
|
|
473
474
|
};
|
|
474
475
|
|
|
475
476
|
// Add error if step failed
|
|
476
477
|
if (step.status === 'failed' && step.err) {
|
|
477
478
|
formattedStep.error = {
|
|
478
479
|
message: step.err.message || 'Step failed',
|
|
479
|
-
stack: step.err.stack || ''
|
|
480
|
+
stack: step.err.stack || '',
|
|
480
481
|
};
|
|
481
482
|
}
|
|
482
483
|
|
|
@@ -500,10 +501,9 @@ function formatHookStep(step) {
|
|
|
500
501
|
return {
|
|
501
502
|
category: 'hook',
|
|
502
503
|
title,
|
|
503
|
-
duration: step.duration || 0
|
|
504
|
+
duration: step.duration || 0,
|
|
504
505
|
};
|
|
505
506
|
}
|
|
506
507
|
|
|
507
|
-
|
|
508
508
|
export { CodeceptReporter };
|
|
509
509
|
export default CodeceptReporter;
|
package/src/adapter/mocha.js
CHANGED
|
@@ -84,7 +84,7 @@ function MochaReporter(runner, opts) {
|
|
|
84
84
|
const artifacts = services.artifacts.get(test.fullTitle());
|
|
85
85
|
const keyValues = services.keyValues.get(test.fullTitle());
|
|
86
86
|
const links = services.links.get(test.fullTitle());
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
client.addTestRun(STATUS.SKIPPED, {
|
|
89
89
|
title: getTestName(test),
|
|
90
90
|
suite_title: getSuiteTitle(test),
|
|
@@ -254,7 +254,7 @@ function generateTmpFilepath(filename = '') {
|
|
|
254
254
|
*/
|
|
255
255
|
function extractTags(test) {
|
|
256
256
|
const tagsSet = new Set();
|
|
257
|
-
|
|
257
|
+
|
|
258
258
|
// Extract tags from test title (@tag format)
|
|
259
259
|
const titleTagsMatch = test.title.match(/@\w+/g);
|
|
260
260
|
if (titleTagsMatch) {
|
|
@@ -262,7 +262,7 @@ function extractTags(test) {
|
|
|
262
262
|
tagsSet.add(tag.replace('@', '').toLowerCase());
|
|
263
263
|
});
|
|
264
264
|
}
|
|
265
|
-
|
|
265
|
+
|
|
266
266
|
// Extract tags from test.tags (Playwright built-in tags)
|
|
267
267
|
if (test.tags && Array.isArray(test.tags)) {
|
|
268
268
|
test.tags.forEach(tag => {
|
package/src/bin/cli.js
CHANGED
|
@@ -36,7 +36,7 @@ program
|
|
|
36
36
|
.command('start')
|
|
37
37
|
.description('Start a new run and return its ID')
|
|
38
38
|
.option('--kind <type>', 'Specify run type: automated, manual, or mixed')
|
|
39
|
-
.action(async
|
|
39
|
+
.action(async opts => {
|
|
40
40
|
cleanLatestRunId();
|
|
41
41
|
|
|
42
42
|
console.log('Starting a new Run on Testomat.io...');
|
package/src/client.js
CHANGED
|
@@ -1,30 +1,18 @@
|
|
|
1
1
|
import createDebugMessages from 'debug';
|
|
2
|
-
import createCallsiteRecord from 'callsite-record';
|
|
3
|
-
import { minimatch } from 'minimatch';
|
|
4
2
|
import fs from 'fs';
|
|
5
3
|
import pc from 'picocolors';
|
|
6
|
-
import { randomUUID } from 'crypto';
|
|
7
4
|
import { APP_PREFIX, STATUS } from './constants.js';
|
|
8
5
|
import { pipesFactory } from './pipe/index.js';
|
|
9
6
|
import { glob } from 'glob';
|
|
10
|
-
import path
|
|
7
|
+
import path from 'path';
|
|
11
8
|
import { fileURLToPath } from 'node:url';
|
|
12
9
|
import { S3Uploader } from './uploader.js';
|
|
13
|
-
import {
|
|
14
|
-
formatStep,
|
|
15
|
-
truncate,
|
|
16
|
-
readLatestRunId,
|
|
17
|
-
storeRunId,
|
|
18
|
-
validateSuiteId,
|
|
19
|
-
transformEnvVarToBoolean
|
|
20
|
-
} from './utils/utils.js';
|
|
10
|
+
import { readLatestRunId, storeRunId, validateSuiteId, transformEnvVarToBoolean } from './utils/utils.js';
|
|
21
11
|
import { filesize as prettyBytes } from 'filesize';
|
|
22
|
-
import {
|
|
12
|
+
import { formatLogs, formatError, stripColors } from './utils/log-formatter.js';
|
|
23
13
|
|
|
24
14
|
const debug = createDebugMessages('@testomatio/reporter:client');
|
|
25
15
|
|
|
26
|
-
const stripColors = stripVTControlCharacters || ((str) => str?.replace(/\x1b\[[0-9;]*m/g, '') || '');
|
|
27
|
-
|
|
28
16
|
// removed __dirname usage, because:
|
|
29
17
|
// 1. replaced with ESM syntax (import.meta.url), but it throws an error on tsc compilation;
|
|
30
18
|
// 2. got error "__dirname already defined" in compiles js code (cjs dir)
|
|
@@ -163,19 +151,12 @@ class Client {
|
|
|
163
151
|
/**
|
|
164
152
|
* @type {TestData}
|
|
165
153
|
*/
|
|
166
|
-
const {
|
|
167
|
-
rid,
|
|
168
|
-
error = null,
|
|
169
|
-
steps: originalSteps,
|
|
170
|
-
title,
|
|
171
|
-
suite_title,
|
|
172
|
-
} = testData;
|
|
154
|
+
const { rid, error = null, steps: originalSteps, title, suite_title } = testData;
|
|
173
155
|
let steps = originalSteps;
|
|
174
156
|
|
|
175
157
|
const uploadedFiles = [];
|
|
176
158
|
const stackArtifactsEnabled = transformEnvVarToBoolean(process.env.TESTOMATIO_STACK_ARTIFACTS);
|
|
177
159
|
|
|
178
|
-
|
|
179
160
|
const {
|
|
180
161
|
time = 0,
|
|
181
162
|
example = null,
|
|
@@ -204,24 +185,24 @@ class Client {
|
|
|
204
185
|
|
|
205
186
|
let errorFormatted = '';
|
|
206
187
|
if (error) {
|
|
207
|
-
errorFormatted +=
|
|
188
|
+
errorFormatted += formatError(error) || '';
|
|
208
189
|
message = error?.message;
|
|
209
190
|
}
|
|
210
191
|
|
|
211
|
-
let fullLogs =
|
|
192
|
+
let fullLogs = formatLogs({ error: errorFormatted, steps, logs: testData.logs });
|
|
212
193
|
|
|
213
194
|
if (stackArtifactsEnabled && fullLogs?.trim()?.length > 0) {
|
|
214
195
|
uploadedFiles.push(
|
|
215
|
-
this.uploader.uploadFileAsBuffer(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
196
|
+
this.uploader.uploadFileAsBuffer(Buffer.from(stripColors(fullLogs), 'utf8'), [
|
|
197
|
+
this.runId,
|
|
198
|
+
rid,
|
|
199
|
+
`logs_${+new Date()}.log`,
|
|
200
|
+
]),
|
|
219
201
|
);
|
|
220
202
|
fullLogs = '';
|
|
221
203
|
steps = null;
|
|
222
204
|
}
|
|
223
205
|
|
|
224
|
-
|
|
225
206
|
if (!this.pipes || !this.pipes.length)
|
|
226
207
|
this.pipes = await pipesFactory(this.paramsForPipesFactory || {}, this.pipeStore);
|
|
227
208
|
|
|
@@ -232,7 +213,7 @@ class Client {
|
|
|
232
213
|
return [];
|
|
233
214
|
}
|
|
234
215
|
|
|
235
|
-
if (
|
|
216
|
+
if (isTestShouldBeExcludedFromReport(testData)) return [];
|
|
236
217
|
|
|
237
218
|
if (status === STATUS.SKIPPED && process.env.TESTOMATIO_EXCLUDE_SKIPPED) {
|
|
238
219
|
debug('Skipping test from report', testData?.title);
|
|
@@ -408,84 +389,6 @@ class Client {
|
|
|
408
389
|
|
|
409
390
|
return this.queue;
|
|
410
391
|
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Returns the formatted stack including the stack trace, steps, and logs.
|
|
414
|
-
* @returns {string}
|
|
415
|
-
*/
|
|
416
|
-
formatLogs({ error, steps, logs }) {
|
|
417
|
-
error = error?.trim();
|
|
418
|
-
logs = logs?.trim().split('\n').map(l => truncate(l)).join('\n');
|
|
419
|
-
|
|
420
|
-
if (Array.isArray(steps)) {
|
|
421
|
-
steps = steps
|
|
422
|
-
.map(step => formatStep(step))
|
|
423
|
-
.flat()
|
|
424
|
-
.join('\n');
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
let testLogs = '';
|
|
428
|
-
if (steps) testLogs += `${pc.bold(pc.blue('################[ Steps ]################'))}\n${steps}\n\n`;
|
|
429
|
-
if (logs) testLogs += `${pc.bold(pc.gray('################[ Logs ]################'))}\n${logs}\n\n`;
|
|
430
|
-
if (error) testLogs += `${pc.bold(pc.red('################[ Failure ]################'))}\n${error}`;
|
|
431
|
-
return testLogs;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
formatError(error, message) {
|
|
435
|
-
if (!message) message = error.message;
|
|
436
|
-
if (error.inspect) message = error.inspect() || '';
|
|
437
|
-
|
|
438
|
-
let stack = '';
|
|
439
|
-
if (error.name) stack += `${pc.red(error.name)}`;
|
|
440
|
-
if (error.operator) stack += ` (${pc.red(error.operator)})`;
|
|
441
|
-
// add new line if something was added to stack
|
|
442
|
-
if (stack) stack += ': ';
|
|
443
|
-
|
|
444
|
-
stack += `${message}\n`;
|
|
445
|
-
|
|
446
|
-
if (error.diff) {
|
|
447
|
-
// diff for vitest
|
|
448
|
-
stack += error.diff;
|
|
449
|
-
stack += '\n\n';
|
|
450
|
-
} else if (error.actual && error.expected && error.actual !== error.expected) {
|
|
451
|
-
// diffs for mocha, cypress, codeceptjs style
|
|
452
|
-
stack += `\n\n${pc.bold(pc.green('+ expected'))} ${pc.bold(pc.red('- actual'))}`;
|
|
453
|
-
stack += `\n${pc.green(`+ ${error.expected.toString().split('\n').join('\n+ ')}`)}`;
|
|
454
|
-
stack += `\n${pc.red(`- ${error.actual.toString().split('\n').join('\n- ')}`)}`;
|
|
455
|
-
stack += '\n\n';
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
const customFilter = process.env.TESTOMATIO_STACK_IGNORE;
|
|
459
|
-
|
|
460
|
-
try {
|
|
461
|
-
let hasFrame = false;
|
|
462
|
-
const record = createCallsiteRecord({
|
|
463
|
-
forError: error,
|
|
464
|
-
isCallsiteFrame: frame => {
|
|
465
|
-
if (customFilter && minimatch(frame.fileName, customFilter)) return false;
|
|
466
|
-
if (hasFrame) return false;
|
|
467
|
-
if (isNotInternalFrame(frame)) hasFrame = true;
|
|
468
|
-
return hasFrame;
|
|
469
|
-
},
|
|
470
|
-
});
|
|
471
|
-
// @ts-ignore
|
|
472
|
-
if (record && !record.filename.startsWith('http')) {
|
|
473
|
-
stack += record.renderSync({ stackFilter: isNotInternalFrame });
|
|
474
|
-
}
|
|
475
|
-
return stack;
|
|
476
|
-
} catch (e) {
|
|
477
|
-
console.log(e);
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
function isNotInternalFrame(frame) {
|
|
483
|
-
return (
|
|
484
|
-
frame.getFileName() &&
|
|
485
|
-
frame.getFileName().includes(sep) &&
|
|
486
|
-
!frame.getFileName().includes('node_modules') &&
|
|
487
|
-
!frame.getFileName().includes('internal')
|
|
488
|
-
);
|
|
489
392
|
}
|
|
490
393
|
|
|
491
394
|
/**
|
|
@@ -493,7 +396,7 @@ function isNotInternalFrame(frame) {
|
|
|
493
396
|
* @param {TestData} testData
|
|
494
397
|
* @returns boolean
|
|
495
398
|
*/
|
|
496
|
-
function
|
|
399
|
+
function isTestShouldBeExcludedFromReport(testData) {
|
|
497
400
|
// const fileName = path.basename(test.location?.file || '');
|
|
498
401
|
const globExcludeFilesPattern = process.env.TESTOMATIO_EXCLUDE_FILES_FROM_REPORT_GLOB_PATTERN;
|
|
499
402
|
if (!globExcludeFilesPattern) return false;
|
|
@@ -503,12 +406,12 @@ function isTestShouldBeExculedFromReport(testData) {
|
|
|
503
406
|
return false;
|
|
504
407
|
}
|
|
505
408
|
|
|
506
|
-
const
|
|
409
|
+
const excludePatternsList = globExcludeFilesPattern.split(';');
|
|
507
410
|
|
|
508
411
|
// as scanning files is time consuming operation, just save the result in variable to avoid multiple scans
|
|
509
412
|
if (!listOfTestFilesToExcludeFromReport) {
|
|
510
413
|
// list of files with relative paths
|
|
511
|
-
listOfTestFilesToExcludeFromReport = glob.sync(
|
|
414
|
+
listOfTestFilesToExcludeFromReport = glob.sync(excludePatternsList, { ignore: '**/node_modules/**' });
|
|
512
415
|
debug('Tests from next files will not be reported:', listOfTestFilesToExcludeFromReport);
|
|
513
416
|
}
|
|
514
417
|
|
|
@@ -8,7 +8,10 @@ class CSharpAdapter extends Adapter {
|
|
|
8
8
|
const exampleMatch = t.title.match(/\((.*?)\)/);
|
|
9
9
|
if (exampleMatch) {
|
|
10
10
|
// Extract parameters as object with numeric keys for API
|
|
11
|
-
const params = exampleMatch[1]
|
|
11
|
+
const params = exampleMatch[1]
|
|
12
|
+
.split(',')
|
|
13
|
+
.map(param => param.trim())
|
|
14
|
+
.filter(param => param !== '');
|
|
12
15
|
t.example = {};
|
|
13
16
|
params.forEach((param, index) => {
|
|
14
17
|
t.example[index] = param;
|
|
@@ -393,13 +393,15 @@ export class NUnitXmlParser {
|
|
|
393
393
|
}
|
|
394
394
|
|
|
395
395
|
// Clean up parameters - remove quotes if they wrap the entire parameter and filter empty ones
|
|
396
|
-
return parameters
|
|
397
|
-
param
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
396
|
+
return parameters
|
|
397
|
+
.map(param => {
|
|
398
|
+
param = param.trim();
|
|
399
|
+
if ((param.startsWith('"') && param.endsWith('"')) || (param.startsWith("'") && param.endsWith("'"))) {
|
|
400
|
+
return param.slice(1, -1);
|
|
401
|
+
}
|
|
402
|
+
return param;
|
|
403
|
+
})
|
|
404
|
+
.filter(p => !!p);
|
|
403
405
|
}
|
|
404
406
|
|
|
405
407
|
/**
|
package/src/pipe/bitbucket.js
CHANGED
|
@@ -44,8 +44,8 @@ export class BitbucketPipe {
|
|
|
44
44
|
baseURL: 'https://api.bitbucket.org/2.0',
|
|
45
45
|
headers: {
|
|
46
46
|
'Content-Type': 'application/json',
|
|
47
|
-
|
|
48
|
-
}
|
|
47
|
+
Authorization: `Bearer ${this.token}`,
|
|
48
|
+
},
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
debug('Bitbucket Pipe: Enabled');
|
|
@@ -186,7 +186,7 @@ export class BitbucketPipe {
|
|
|
186
186
|
const addCommentResponse = await this.client.request({
|
|
187
187
|
method: 'POST',
|
|
188
188
|
url: commentsRequestURL,
|
|
189
|
-
data: { content: { raw: body } }
|
|
189
|
+
data: { content: { raw: body } },
|
|
190
190
|
});
|
|
191
191
|
|
|
192
192
|
const commentID = addCommentResponse.data.id;
|
|
@@ -221,7 +221,7 @@ async function deletePreviousReport(client, commentsRequestURL, hiddenCommentDat
|
|
|
221
221
|
try {
|
|
222
222
|
const response = await client.request({
|
|
223
223
|
method: 'GET',
|
|
224
|
-
url: commentsRequestURL
|
|
224
|
+
url: commentsRequestURL,
|
|
225
225
|
});
|
|
226
226
|
comments = response.data.values;
|
|
227
227
|
} catch (e) {
|
|
@@ -238,7 +238,7 @@ async function deletePreviousReport(client, commentsRequestURL, hiddenCommentDat
|
|
|
238
238
|
const deleteCommentURL = `${commentsRequestURL}/${comment.id}`;
|
|
239
239
|
await client.request({
|
|
240
240
|
method: 'DELETE',
|
|
241
|
-
url: deleteCommentURL
|
|
241
|
+
url: deleteCommentURL,
|
|
242
242
|
});
|
|
243
243
|
} catch (e) {
|
|
244
244
|
console.warn(`Can't delete previously added comment with testomat.io report. Ignored.`);
|
package/src/pipe/debug.js
CHANGED
|
@@ -93,8 +93,7 @@ export class DebugPipe {
|
|
|
93
93
|
const logData = { action: 'addTest', testId: data };
|
|
94
94
|
if (this.store.runId) logData.runId = this.store.runId;
|
|
95
95
|
this.logToFile(logData);
|
|
96
|
-
}
|
|
97
|
-
else this.batch.tests.push(data);
|
|
96
|
+
} else this.batch.tests.push(data);
|
|
98
97
|
|
|
99
98
|
if (!this.batch.intervalFunction) await this.batchUpload();
|
|
100
99
|
}
|
package/src/pipe/gitlab.js
CHANGED
|
@@ -49,7 +49,7 @@ class GitLabPipe {
|
|
|
49
49
|
baseURL: 'https://gitlab.com/api/v4',
|
|
50
50
|
headers: {
|
|
51
51
|
'Content-Type': 'application/json',
|
|
52
|
-
}
|
|
52
|
+
},
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
debug('GitLab Pipe: Enabled');
|
|
@@ -176,7 +176,7 @@ class GitLabPipe {
|
|
|
176
176
|
method: 'POST',
|
|
177
177
|
url: commentsRequestURL,
|
|
178
178
|
params: { access_token: this.token },
|
|
179
|
-
data: { body }
|
|
179
|
+
data: { body },
|
|
180
180
|
});
|
|
181
181
|
|
|
182
182
|
const commentID = addCommentResponse.data.id;
|
|
@@ -212,7 +212,7 @@ async function deletePreviousReport(client, commentsRequestURL, hiddenCommentDat
|
|
|
212
212
|
const response = await client.request({
|
|
213
213
|
method: 'GET',
|
|
214
214
|
url: commentsRequestURL,
|
|
215
|
-
params: { access_token: token }
|
|
215
|
+
params: { access_token: token },
|
|
216
216
|
});
|
|
217
217
|
comments = response.data;
|
|
218
218
|
} catch (e) {
|
|
@@ -230,7 +230,7 @@ async function deletePreviousReport(client, commentsRequestURL, hiddenCommentDat
|
|
|
230
230
|
await client.request({
|
|
231
231
|
method: 'DELETE',
|
|
232
232
|
url: deleteCommentURL,
|
|
233
|
-
params: { access_token: token }
|
|
233
|
+
params: { access_token: token },
|
|
234
234
|
});
|
|
235
235
|
} catch (e) {
|
|
236
236
|
console.warn(`Can't delete previously added comment with testomat.io report. Ignore.`);
|