@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.
Files changed (62) hide show
  1. package/README.md +3 -2
  2. package/lib/adapter/codecept.js +12 -9
  3. package/lib/bin/cli.js +40 -11
  4. package/lib/bin/reportXml.js +5 -2
  5. package/lib/client.d.ts +1 -11
  6. package/lib/client.js +57 -152
  7. package/lib/data-storage.d.ts +1 -1
  8. package/lib/helpers.d.ts +1 -0
  9. package/lib/helpers.js +4 -0
  10. package/lib/junit-adapter/csharp.d.ts +0 -1
  11. package/lib/junit-adapter/csharp.js +43 -7
  12. package/lib/junit-adapter/nunit-parser.d.ts +82 -0
  13. package/lib/junit-adapter/nunit-parser.js +433 -0
  14. package/lib/pipe/bitbucket.js +5 -5
  15. package/lib/pipe/coverage.d.ts +82 -0
  16. package/lib/pipe/coverage.js +373 -0
  17. package/lib/pipe/gitlab.js +4 -4
  18. package/lib/pipe/index.js +2 -0
  19. package/lib/pipe/testomatio.d.ts +3 -2
  20. package/lib/pipe/testomatio.js +44 -18
  21. package/lib/reporter-functions.js +14 -12
  22. package/lib/reporter.d.ts +31 -21
  23. package/lib/reporter.js +40 -5
  24. package/lib/services/artifacts.d.ts +1 -1
  25. package/lib/services/key-values.d.ts +1 -1
  26. package/lib/services/links.d.ts +1 -1
  27. package/lib/services/logger.d.ts +1 -1
  28. package/lib/uploader.js +4 -0
  29. package/lib/utils/log-formatter.d.ts +28 -0
  30. package/lib/utils/log-formatter.js +127 -0
  31. package/lib/utils/pipe_utils.d.ts +15 -0
  32. package/lib/utils/pipe_utils.js +44 -2
  33. package/lib/utils/utils.d.ts +6 -0
  34. package/lib/utils/utils.js +260 -25
  35. package/lib/xmlReader.d.ts +32 -26
  36. package/lib/xmlReader.js +121 -52
  37. package/package.json +12 -7
  38. package/src/adapter/codecept.js +19 -19
  39. package/src/adapter/mocha.js +1 -1
  40. package/src/adapter/playwright.js +2 -2
  41. package/src/bin/cli.js +51 -13
  42. package/src/bin/reportXml.js +5 -2
  43. package/src/client.js +69 -130
  44. package/src/helpers.js +1 -0
  45. package/src/junit-adapter/csharp.js +48 -6
  46. package/src/junit-adapter/nunit-parser.js +474 -0
  47. package/src/pipe/bitbucket.js +5 -5
  48. package/src/pipe/coverage.js +440 -0
  49. package/src/pipe/debug.js +1 -2
  50. package/src/pipe/gitlab.js +4 -4
  51. package/src/pipe/index.js +2 -0
  52. package/src/pipe/testomatio.js +109 -85
  53. package/src/reporter-functions.js +15 -12
  54. package/src/reporter.js +6 -4
  55. package/src/services/links.js +1 -1
  56. package/src/uploader.js +5 -0
  57. package/src/utils/log-formatter.js +113 -0
  58. package/src/utils/pipe_utils.js +52 -3
  59. package/src/utils/utils.js +277 -22
  60. package/src/xmlReader.js +144 -46
  61. package/types/types.d.ts +364 -0
  62. package/types/vitest.types.d.ts +93 -0
@@ -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:(\/+(?:[A-Za-z]:[\\/]|\/)?[^\s]*?\.(png|avi|webm|jpg|html|txt))/gi;
137
+ const fileMatchRegex = /file:(\/*)([A-Za-z]:[\\/].*?|\/.*?)\.(png|avi|webm|jpg|html|txt)/gi;
120
138
  const fetchFilesFromStackTrace = (stack = '', checkExists = true) => {
121
- const files = Array.from(stack.matchAll(fileMatchRegex))
122
- .map(f => f[1].trim())
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
- // Convert Windows paths to Linux paths for testing purposes
126
- if (f.match(/^[A-Za-z]:[\\\/]/)) {
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 => l.split(' ').find(p => p.includes(':')) || '')
151
- .filter(l => (0, is_valid_path_1.default)(l?.split(':')[0]))
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 => fs_1.default.existsSync(l.split(':')[0]))
156
- .filter(l => fs_1.default.lstatSync(l.split(':')[0]).isFile());
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
- const [file, line] = stackLines[0].split(':');
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
- if (lineIndex === -1)
220
- lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
221
- if (lineIndex === -1)
222
- lineIndex = lines.findIndex(l => l.includes(`${title}(`));
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.toString().trim().length < size) {
475
- return s.toString();
653
+ if (s === undefined || s === null) {
654
+ return '';
476
655
  }
477
- return `${s.toString().substring(0, size)}...`;
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;
@@ -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
- 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
- };
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;