@testomatio/reporter 2.3.9-beta-bin-fix → 2.4.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.
- package/README.md +3 -2
- package/lib/adapter/codecept.js +12 -9
- package/lib/bin/cli.js +40 -11
- package/lib/bin/reportXml.js +5 -2
- package/lib/client.d.ts +1 -11
- package/lib/client.js +57 -152
- package/lib/data-storage.d.ts +1 -1
- package/lib/helpers.d.ts +1 -0
- package/lib/helpers.js +4 -0
- package/lib/junit-adapter/csharp.d.ts +0 -1
- package/lib/junit-adapter/csharp.js +43 -7
- package/lib/junit-adapter/nunit-parser.d.ts +82 -0
- package/lib/junit-adapter/nunit-parser.js +433 -0
- package/lib/pipe/bitbucket.js +5 -5
- package/lib/pipe/coverage.d.ts +82 -0
- package/lib/pipe/coverage.js +373 -0
- package/lib/pipe/gitlab.js +4 -4
- package/lib/pipe/index.js +2 -0
- package/lib/pipe/testomatio.d.ts +3 -2
- package/lib/pipe/testomatio.js +44 -18
- package/lib/reporter-functions.js +14 -12
- package/lib/reporter.d.ts +31 -21
- package/lib/reporter.js +40 -5
- package/lib/services/artifacts.d.ts +1 -1
- package/lib/services/key-values.d.ts +1 -1
- package/lib/services/links.d.ts +1 -1
- package/lib/services/logger.d.ts +1 -1
- package/lib/uploader.js +4 -0
- package/lib/utils/log-formatter.d.ts +28 -0
- package/lib/utils/log-formatter.js +127 -0
- package/lib/utils/pipe_utils.d.ts +15 -0
- package/lib/utils/pipe_utils.js +44 -2
- package/lib/utils/utils.d.ts +6 -0
- package/lib/utils/utils.js +260 -25
- package/lib/xmlReader.d.ts +32 -26
- package/lib/xmlReader.js +121 -52
- package/package.json +12 -7
- 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 +51 -13
- package/src/bin/reportXml.js +5 -2
- package/src/client.js +69 -130
- package/src/helpers.js +1 -0
- package/src/junit-adapter/csharp.js +48 -6
- package/src/junit-adapter/nunit-parser.js +474 -0
- package/src/pipe/bitbucket.js +5 -5
- package/src/pipe/coverage.js +440 -0
- package/src/pipe/debug.js +1 -2
- package/src/pipe/gitlab.js +4 -4
- package/src/pipe/index.js +2 -0
- package/src/pipe/testomatio.js +109 -85
- package/src/reporter-functions.js +15 -12
- package/src/reporter.js +6 -4
- package/src/services/links.js +1 -1
- package/src/uploader.js +5 -0
- package/src/utils/log-formatter.js +113 -0
- package/src/utils/pipe_utils.js +52 -3
- package/src/utils/utils.js +277 -22
- package/src/xmlReader.js +144 -46
- package/types/types.d.ts +364 -0
- package/types/vitest.types.d.ts +93 -0
package/lib/utils/utils.js
CHANGED
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.validateSuiteId = exports.testRunnerHelper = exports.specificTestInfo = exports.parseSuite = exports.isValidUrl = exports.humanize = exports.getTestomatIdFromTestTitle = exports.getCurrentDateTime = exports.foundedTestLog = exports.fileSystem = exports.fetchFilesFromStackTrace = exports.fetchIdFromOutput = exports.fetchIdFromCode = exports.fetchSourceCodeFromStackTrace = exports.fetchSourceCode = exports.isSameTest = exports.ansiRegExp = exports.SUITE_ID_REGEX = exports.TEST_ID_REGEX = void 0;
|
|
39
|
+
exports.validateSuiteId = exports.testRunnerHelper = exports.specificTestInfo = exports.parseSuite = exports.isValidUrl = exports.humanize = exports.getTestomatIdFromTestTitle = exports.getGitCommitSha = exports.getCurrentDateTime = exports.foundedTestLog = exports.fileSystem = exports.fetchFilesFromStackTrace = exports.fetchIdFromOutput = exports.fetchIdFromCode = exports.fetchSourceCodeFromStackTrace = exports.fetchSourceCode = exports.isSameTest = exports.ansiRegExp = exports.SUITE_ID_REGEX = exports.TEST_ID_REGEX = void 0;
|
|
40
40
|
exports.getPackageVersion = getPackageVersion;
|
|
41
41
|
exports.truncate = truncate;
|
|
42
42
|
exports.cleanLatestRunId = cleanLatestRunId;
|
|
@@ -45,6 +45,7 @@ exports.readLatestRunId = readLatestRunId;
|
|
|
45
45
|
exports.removeColorCodes = removeColorCodes;
|
|
46
46
|
exports.storeRunId = storeRunId;
|
|
47
47
|
exports.transformEnvVarToBoolean = transformEnvVarToBoolean;
|
|
48
|
+
exports.applyFilter = applyFilter;
|
|
48
49
|
const url_1 = require("url");
|
|
49
50
|
const path_1 = __importStar(require("path"));
|
|
50
51
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
@@ -53,6 +54,7 @@ const is_valid_path_1 = __importDefault(require("is-valid-path"));
|
|
|
53
54
|
const debug_1 = __importDefault(require("debug"));
|
|
54
55
|
const os_1 = __importDefault(require("os"));
|
|
55
56
|
const url_2 = require("url");
|
|
57
|
+
const child_process_1 = require("child_process");
|
|
56
58
|
const debug = (0, debug_1.default)('@testomatio/reporter:util');
|
|
57
59
|
// Use __dirname directly since we're compiling to CommonJS
|
|
58
60
|
// prettier-ignore
|
|
@@ -98,6 +100,22 @@ const validateSuiteId = suiteId => {
|
|
|
98
100
|
return match ? match[0] : null;
|
|
99
101
|
};
|
|
100
102
|
exports.validateSuiteId = validateSuiteId;
|
|
103
|
+
/**
|
|
104
|
+
* Gets current git commit SHA
|
|
105
|
+
* @returns {String|null} git commit SHA or null if not available
|
|
106
|
+
*/
|
|
107
|
+
const getGitCommitSha = () => {
|
|
108
|
+
try {
|
|
109
|
+
const sha = (0, child_process_1.execSync)('git rev-parse --short HEAD', {
|
|
110
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
111
|
+
}).toString().trim();
|
|
112
|
+
return sha || null;
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
exports.getGitCommitSha = getGitCommitSha;
|
|
101
119
|
const ansiRegExp = () => {
|
|
102
120
|
const pattern = [
|
|
103
121
|
'[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
|
|
@@ -116,19 +134,26 @@ const isValidUrl = s => {
|
|
|
116
134
|
}
|
|
117
135
|
};
|
|
118
136
|
exports.isValidUrl = isValidUrl;
|
|
119
|
-
const fileMatchRegex = /file:(
|
|
137
|
+
const fileMatchRegex = /file:(\/*)([A-Za-z]:[\\/].*?|\/.*?)\.(png|avi|webm|jpg|html|txt)/gi;
|
|
120
138
|
const fetchFilesFromStackTrace = (stack = '', checkExists = true) => {
|
|
121
|
-
|
|
122
|
-
.map(
|
|
139
|
+
let files = Array.from(stack.matchAll(fileMatchRegex))
|
|
140
|
+
.map(match => {
|
|
141
|
+
// match[0] is full match, match[1] is slashes, match[2] is path, match[3] is extension
|
|
142
|
+
const slashes = match[1] || '';
|
|
143
|
+
const path = match[2];
|
|
144
|
+
const extension = match[3];
|
|
145
|
+
return `${slashes}${path}.${extension}`;
|
|
146
|
+
})
|
|
147
|
+
.map(f => f.trim())
|
|
123
148
|
.map(f => f.replace(/^\/+/, '/').replace(/^\/([A-Za-z]:)/, '$1')) // Remove extra slashes, handle Windows paths
|
|
124
149
|
.map(f => {
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
// Convert Windows path to Linux equivalent for test scenarios
|
|
128
|
-
return f.replace(/^[A-Za-z]:[\\\/]/, '/').replace(/\\/g, '/');
|
|
129
|
-
}
|
|
130
|
-
return f;
|
|
150
|
+
// Normalize path separators for cross-platform compatibility
|
|
151
|
+
return f.replace(/\\/g, '/');
|
|
131
152
|
});
|
|
153
|
+
// If we're not checking file existence, remove Windows drive letters for consistency
|
|
154
|
+
if (!checkExists) {
|
|
155
|
+
files = files.map(f => f.replace(/^([A-Za-z]):/, ''));
|
|
156
|
+
}
|
|
132
157
|
debug('Found files in stack trace: ', files);
|
|
133
158
|
return files.filter(f => {
|
|
134
159
|
if (!checkExists)
|
|
@@ -144,19 +169,88 @@ const fetchSourceCodeFromStackTrace = (stack = '') => {
|
|
|
144
169
|
const stackLines = stack
|
|
145
170
|
.split('\n')
|
|
146
171
|
.filter(l => l.includes(':'))
|
|
147
|
-
// .map(l => l.match(/\[(.*?)\]/)?.[1] || l) // minitest format
|
|
148
|
-
// .map(l => l.split(':')[0])
|
|
149
172
|
.map(l => l.trim())
|
|
150
|
-
.map(l =>
|
|
151
|
-
|
|
173
|
+
.map(l => {
|
|
174
|
+
// Remove 'at ' prefix if present
|
|
175
|
+
if (l.startsWith('at ')) {
|
|
176
|
+
return l.substring(3).trim();
|
|
177
|
+
}
|
|
178
|
+
// Find the part that looks like a file path with line number
|
|
179
|
+
const parts = l.split(' ');
|
|
180
|
+
for (const part of parts) {
|
|
181
|
+
// Check if this part has a colon
|
|
182
|
+
if (part.includes(':')) {
|
|
183
|
+
// For Windows paths, we need to handle drive letters (C:, D:, etc.)
|
|
184
|
+
// Split by colon but keep drive letter with the path
|
|
185
|
+
const colonParts = part.split(':');
|
|
186
|
+
let filePath;
|
|
187
|
+
// Check if first part is a Windows drive letter (single letter)
|
|
188
|
+
if (colonParts.length >= 2 && colonParts[0].length === 1 && /[A-Za-z]/.test(colonParts[0])) {
|
|
189
|
+
// Windows path like D:\path\file.php:24
|
|
190
|
+
// Reconstruct as D:\path\file.php
|
|
191
|
+
filePath = colonParts[0] + ':' + colonParts[1];
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
// Unix path like /path/file.php:24
|
|
195
|
+
filePath = colonParts[0];
|
|
196
|
+
}
|
|
197
|
+
// Only consider it valid if the file exists
|
|
198
|
+
if (fs_1.default.existsSync(filePath)) {
|
|
199
|
+
return part;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// If no valid file path found in parts, return the whole line
|
|
204
|
+
// It will be filtered out later if it's not a valid file path
|
|
205
|
+
return parts.find(p => p.includes(':')) || l;
|
|
206
|
+
})
|
|
207
|
+
.filter(l => {
|
|
208
|
+
// Extract file path from line (accounting for Windows drive letters)
|
|
209
|
+
if (!l)
|
|
210
|
+
return false;
|
|
211
|
+
const colonParts = l.split(':');
|
|
212
|
+
let filePath;
|
|
213
|
+
if (colonParts.length >= 2 && colonParts[0].length === 1 && /[A-Za-z]/.test(colonParts[0])) {
|
|
214
|
+
// Windows path
|
|
215
|
+
filePath = colonParts[0] + ':' + colonParts[1];
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
// Unix path
|
|
219
|
+
filePath = colonParts[0];
|
|
220
|
+
}
|
|
221
|
+
return filePath && fs_1.default.existsSync(filePath);
|
|
222
|
+
})
|
|
152
223
|
// // filter out 3rd party libs
|
|
153
224
|
.filter(l => !l?.includes(`vendor${path_1.sep}`))
|
|
154
225
|
.filter(l => !l?.includes(`node_modules${path_1.sep}`))
|
|
155
|
-
.filter(l =>
|
|
156
|
-
|
|
226
|
+
.filter(l => {
|
|
227
|
+
// Extract file path for final check (accounting for Windows drive letters)
|
|
228
|
+
const colonParts = l.split(':');
|
|
229
|
+
let filePath;
|
|
230
|
+
if (colonParts.length >= 2 && colonParts[0].length === 1 && /[A-Za-z]/.test(colonParts[0])) {
|
|
231
|
+
filePath = colonParts[0] + ':' + colonParts[1];
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
filePath = colonParts[0];
|
|
235
|
+
}
|
|
236
|
+
return fs_1.default.lstatSync(filePath).isFile();
|
|
237
|
+
});
|
|
157
238
|
if (!stackLines.length)
|
|
158
239
|
return '';
|
|
159
|
-
|
|
240
|
+
// Extract file and line number (accounting for Windows drive letters)
|
|
241
|
+
const firstLine = stackLines[0];
|
|
242
|
+
const colonParts = firstLine.split(':');
|
|
243
|
+
let file, line;
|
|
244
|
+
if (colonParts.length >= 3 && colonParts[0].length === 1 && /[A-Za-z]/.test(colonParts[0])) {
|
|
245
|
+
// Windows path like D:\path\file.php:24
|
|
246
|
+
file = colonParts[0] + ':' + colonParts[1];
|
|
247
|
+
line = colonParts[2];
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
// Unix path like /path/file.php:24
|
|
251
|
+
file = colonParts[0];
|
|
252
|
+
line = colonParts[1];
|
|
253
|
+
}
|
|
160
254
|
const prepend = 3;
|
|
161
255
|
const source = fetchSourceCode(fs_1.default.readFileSync(file).toString(), { line, prepend, limit: 7 });
|
|
162
256
|
if (!source)
|
|
@@ -174,6 +268,8 @@ exports.fetchSourceCodeFromStackTrace = fetchSourceCodeFromStackTrace;
|
|
|
174
268
|
exports.TEST_ID_REGEX = /@T([\w\d]{8})/;
|
|
175
269
|
exports.SUITE_ID_REGEX = /@S([\w\d]{8})/;
|
|
176
270
|
const fetchIdFromCode = (code, opts = {}) => {
|
|
271
|
+
if (!code)
|
|
272
|
+
return null;
|
|
177
273
|
const comments = code
|
|
178
274
|
.split('\n')
|
|
179
275
|
.map(l => l.trim())
|
|
@@ -216,10 +312,58 @@ const fetchSourceCode = (contents, opts = {}) => {
|
|
|
216
312
|
lineIndex = lines.findIndex(l => l.includes(`${title}(`));
|
|
217
313
|
}
|
|
218
314
|
else if (opts.lang === 'csharp') {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (
|
|
222
|
-
|
|
315
|
+
// Find the method declaration line
|
|
316
|
+
let methodLineIndex = lines.findIndex(l => l.includes(`public void ${title}(`));
|
|
317
|
+
if (methodLineIndex === -1) {
|
|
318
|
+
methodLineIndex = lines.findIndex(l => l.includes(`public async Task ${title}(`));
|
|
319
|
+
}
|
|
320
|
+
if (methodLineIndex === -1) {
|
|
321
|
+
methodLineIndex = lines.findIndex(l => l.includes(`${title}(`));
|
|
322
|
+
}
|
|
323
|
+
// If found, scan upwards to find [TestCase], [Test] attributes and XML comments
|
|
324
|
+
if (methodLineIndex !== -1) {
|
|
325
|
+
lineIndex = methodLineIndex;
|
|
326
|
+
// Scan upwards to find the start of attributes and comments
|
|
327
|
+
for (let i = methodLineIndex - 1; i >= 0; i--) {
|
|
328
|
+
const trimmedLine = lines[i].trim();
|
|
329
|
+
// Include [TestCase], [Test], and other attributes
|
|
330
|
+
if (trimmedLine.startsWith('[')) {
|
|
331
|
+
lineIndex = i;
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
// Include XML documentation comments
|
|
335
|
+
if (trimmedLine.startsWith('///')) {
|
|
336
|
+
lineIndex = i;
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
// Stop at empty lines (with some tolerance)
|
|
340
|
+
if (trimmedLine === '') {
|
|
341
|
+
// Check if next non-empty line is an attribute or comment
|
|
342
|
+
let hasMoreAttributes = false;
|
|
343
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
344
|
+
const nextTrimmed = lines[j].trim();
|
|
345
|
+
if (nextTrimmed === '')
|
|
346
|
+
continue;
|
|
347
|
+
if (nextTrimmed.startsWith('[') || nextTrimmed.startsWith('///')) {
|
|
348
|
+
hasMoreAttributes = true;
|
|
349
|
+
lineIndex = j;
|
|
350
|
+
}
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
if (!hasMoreAttributes)
|
|
354
|
+
break;
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
// Stop at other method declarations or class-level elements
|
|
358
|
+
if (trimmedLine.includes('public ') ||
|
|
359
|
+
trimmedLine.includes('private ') ||
|
|
360
|
+
trimmedLine.includes('protected ') ||
|
|
361
|
+
trimmedLine.includes('internal ')) {
|
|
362
|
+
if (!trimmedLine.startsWith('['))
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
223
367
|
}
|
|
224
368
|
else {
|
|
225
369
|
lineIndex = lines.findIndex(l => l.includes(title));
|
|
@@ -228,11 +372,28 @@ const fetchSourceCode = (contents, opts = {}) => {
|
|
|
228
372
|
if (opts.prepend) {
|
|
229
373
|
lineIndex -= opts.prepend;
|
|
230
374
|
}
|
|
231
|
-
if (lineIndex) {
|
|
375
|
+
if (lineIndex !== -1 && lineIndex !== undefined) {
|
|
232
376
|
const result = [];
|
|
377
|
+
let braceDepth = 0; // Track brace depth for C# methods
|
|
378
|
+
let methodStartFound = false; // Flag to indicate we've found the method opening brace
|
|
233
379
|
for (let i = lineIndex; i < lineIndex + limit; i++) {
|
|
234
380
|
if (lines[i] === undefined)
|
|
235
381
|
continue;
|
|
382
|
+
// Track brace depth for C# to stop after method closes
|
|
383
|
+
if (opts.lang === 'csharp') {
|
|
384
|
+
const line = lines[i];
|
|
385
|
+
// Count opening and closing braces
|
|
386
|
+
const openBraces = (line.match(/\{/g) || []).length;
|
|
387
|
+
const closeBraces = (line.match(/\}/g) || []).length;
|
|
388
|
+
if (openBraces > 0)
|
|
389
|
+
methodStartFound = true;
|
|
390
|
+
braceDepth += openBraces - closeBraces;
|
|
391
|
+
// If we've started the method and depth returns to 0, method is complete
|
|
392
|
+
if (methodStartFound && braceDepth === 0 && closeBraces > 0) {
|
|
393
|
+
// Don't include the closing brace - just break
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
236
397
|
if (i > lineIndex + 2 && !opts.prepend) {
|
|
237
398
|
// annotation
|
|
238
399
|
if (opts.lang === 'php' && lines[i].trim().startsWith('#['))
|
|
@@ -271,6 +432,24 @@ const fetchSourceCode = (contents, opts = {}) => {
|
|
|
271
432
|
break;
|
|
272
433
|
if (opts.lang === 'java' && lines[i].includes(' class '))
|
|
273
434
|
break;
|
|
435
|
+
// For C#, additional checks if brace tracking didn't stop us
|
|
436
|
+
if (opts.lang === 'csharp') {
|
|
437
|
+
const trimmed = lines[i].trim();
|
|
438
|
+
// Stop at attribute that marks beginning of next test (but not if we're still in the current method)
|
|
439
|
+
if (trimmed.match(/^\[(Test|TestCase|Theory|Fact)/) && methodStartFound && braceDepth === 0)
|
|
440
|
+
break;
|
|
441
|
+
// Stop at XML documentation comments that belong to next method
|
|
442
|
+
if (trimmed.startsWith('///') && methodStartFound && braceDepth === 0)
|
|
443
|
+
break;
|
|
444
|
+
// Stop at another method declaration (but not if we're still in the current method)
|
|
445
|
+
if (trimmed.match(/^\s*(public|private|protected|internal)\s+(\w+|async\s+\w+)\s+\w+\s*\(/) &&
|
|
446
|
+
methodStartFound &&
|
|
447
|
+
braceDepth === 0)
|
|
448
|
+
break;
|
|
449
|
+
// Stop at class declaration
|
|
450
|
+
if (trimmed.includes(' class ') && trimmed.includes('public'))
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
274
453
|
}
|
|
275
454
|
result.push(lines[i]);
|
|
276
455
|
}
|
|
@@ -471,10 +650,62 @@ function transformEnvVarToBoolean(value) {
|
|
|
471
650
|
return Boolean(value);
|
|
472
651
|
}
|
|
473
652
|
function truncate(s, size = 255) {
|
|
474
|
-
if (s
|
|
475
|
-
return
|
|
653
|
+
if (s === undefined || s === null) {
|
|
654
|
+
return '';
|
|
476
655
|
}
|
|
477
|
-
|
|
656
|
+
const str = s.toString();
|
|
657
|
+
if (str.trim().length < size) {
|
|
658
|
+
return str;
|
|
659
|
+
}
|
|
660
|
+
return `${str.substring(0, size)}...`;
|
|
661
|
+
}
|
|
662
|
+
function applyFilter(command, tests) {
|
|
663
|
+
if (!tests || !tests.length)
|
|
664
|
+
return command;
|
|
665
|
+
const lower = (command || '').toLowerCase();
|
|
666
|
+
const regexPattern = `(${tests.join('|')})`;
|
|
667
|
+
if (lower.includes('jest')) {
|
|
668
|
+
return `${command} --testNamePattern ${regexPattern}`;
|
|
669
|
+
}
|
|
670
|
+
if (lower.includes('cypress')) {
|
|
671
|
+
const grepValue = tests.join(',');
|
|
672
|
+
const baseEnv = {
|
|
673
|
+
grep: grepValue,
|
|
674
|
+
grepFilterSpecs: true,
|
|
675
|
+
grepOmitFiltered: true,
|
|
676
|
+
};
|
|
677
|
+
if (command.includes('--env')) {
|
|
678
|
+
return command.replace(/--env\s+(['"]?)([^\s'"]+)\1/, (match, quote, envVal) => {
|
|
679
|
+
const existingEnv = {};
|
|
680
|
+
if (envVal.startsWith('{') && envVal.endsWith('}')) {
|
|
681
|
+
try {
|
|
682
|
+
Object.assign(existingEnv, JSON.parse(envVal));
|
|
683
|
+
}
|
|
684
|
+
catch (e) {
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
if (!Object.keys(existingEnv).length) {
|
|
688
|
+
envVal.split(',').forEach((pair) => {
|
|
689
|
+
const [k, v] = pair.split('=');
|
|
690
|
+
if (!k)
|
|
691
|
+
return;
|
|
692
|
+
if (v === 'true')
|
|
693
|
+
existingEnv[k] = true;
|
|
694
|
+
else if (v === 'false')
|
|
695
|
+
existingEnv[k] = false;
|
|
696
|
+
else
|
|
697
|
+
existingEnv[k] = v;
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
const merged = { ...existingEnv, ...baseEnv };
|
|
701
|
+
const json = JSON.stringify(merged);
|
|
702
|
+
return `--env ${json}`;
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
const json = JSON.stringify(baseEnv);
|
|
706
|
+
return `${command} --env ${json}`;
|
|
707
|
+
}
|
|
708
|
+
return `${command} --grep ${regexPattern}`;
|
|
478
709
|
}
|
|
479
710
|
|
|
480
711
|
module.exports.getPackageVersion = getPackageVersion;
|
|
@@ -493,12 +724,16 @@ module.exports.storeRunId = storeRunId;
|
|
|
493
724
|
|
|
494
725
|
module.exports.transformEnvVarToBoolean = transformEnvVarToBoolean;
|
|
495
726
|
|
|
727
|
+
module.exports.applyFilter = applyFilter;
|
|
728
|
+
|
|
496
729
|
module.exports.getTestomatIdFromTestTitle = getTestomatIdFromTestTitle;
|
|
497
730
|
|
|
498
731
|
module.exports.parseSuite = parseSuite;
|
|
499
732
|
|
|
500
733
|
module.exports.validateSuiteId = validateSuiteId;
|
|
501
734
|
|
|
735
|
+
module.exports.getGitCommitSha = getGitCommitSha;
|
|
736
|
+
|
|
502
737
|
module.exports.ansiRegExp = ansiRegExp;
|
|
503
738
|
|
|
504
739
|
module.exports.isValidUrl = isValidUrl;
|
package/lib/xmlReader.d.ts
CHANGED
|
@@ -19,25 +19,11 @@ declare class XmlReader {
|
|
|
19
19
|
tests: any[];
|
|
20
20
|
stats: {};
|
|
21
21
|
uploader: S3Uploader;
|
|
22
|
+
enhancedNunit: boolean;
|
|
23
|
+
groupParameterized: boolean;
|
|
22
24
|
version: any;
|
|
23
25
|
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
|
-
};
|
|
26
|
+
parse(fileName: any): any;
|
|
41
27
|
processJUnit(jsonSuite: any): {
|
|
42
28
|
create_tests: boolean;
|
|
43
29
|
duration: number;
|
|
@@ -49,15 +35,14 @@ declare class XmlReader {
|
|
|
49
35
|
tests: any[];
|
|
50
36
|
tests_count: number;
|
|
51
37
|
};
|
|
52
|
-
processNUnit(jsonSuite: any):
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
};
|
|
38
|
+
processNUnit(jsonSuite: any): any;
|
|
39
|
+
/**
|
|
40
|
+
* Check if the XML is actually NUnit format (has test-suite hierarchy)
|
|
41
|
+
* @param {Object} jsonSuite - Parsed XML suite object
|
|
42
|
+
* @returns {boolean} - True if this is NUnit XML format
|
|
43
|
+
*/
|
|
44
|
+
isNUnitXml(jsonSuite: any): boolean;
|
|
45
|
+
processNUnitEnhanced(jsonSuite: any): any;
|
|
61
46
|
processTRX(jsonSuite: any): {
|
|
62
47
|
status: string;
|
|
63
48
|
create_tests: boolean;
|
|
@@ -67,6 +52,27 @@ declare class XmlReader {
|
|
|
67
52
|
failed_count: number;
|
|
68
53
|
tests: any;
|
|
69
54
|
};
|
|
55
|
+
_parseTRXTestDefinition(td: any): {
|
|
56
|
+
title: any;
|
|
57
|
+
example: any;
|
|
58
|
+
file: string;
|
|
59
|
+
description: any;
|
|
60
|
+
suite_title: any;
|
|
61
|
+
id: any;
|
|
62
|
+
};
|
|
63
|
+
_parseTRXTestResult(td: any, tests: any): {
|
|
64
|
+
suite_title: any;
|
|
65
|
+
title: any;
|
|
66
|
+
file: any;
|
|
67
|
+
description: any;
|
|
68
|
+
code: any;
|
|
69
|
+
run_time: number;
|
|
70
|
+
stack: any;
|
|
71
|
+
files: any;
|
|
72
|
+
create: boolean;
|
|
73
|
+
overwrite: boolean;
|
|
74
|
+
};
|
|
75
|
+
_mapTRXStatus(outcome: any): string;
|
|
70
76
|
processXUnit(assemblies: any): {
|
|
71
77
|
status: string;
|
|
72
78
|
create_tests: boolean;
|