@testomatio/reporter 2.3.7-beta.2-xml-import → 2.3.7-beta.4-stack-artifacts
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 +1 -1
- package/lib/bin/cli.js +1 -1
- package/lib/bin/reportXml.js +2 -5
- package/lib/bin/startTest.js +3 -3
- package/lib/client.js +48 -25
- package/lib/junit-adapter/csharp.d.ts +1 -0
- package/lib/junit-adapter/csharp.js +7 -40
- package/lib/pipe/debug.js +1 -1
- package/lib/pipe/testomatio.js +15 -19
- package/lib/reporter.d.ts +19 -9
- package/lib/reporter.js +40 -5
- package/lib/template/testomatio.hbs +1026 -1366
- package/lib/uploader.js +0 -4
- package/lib/utils/utils.js +11 -90
- package/lib/xmlReader.d.ts +26 -32
- package/lib/xmlReader.js +50 -106
- package/package.json +1 -1
- package/src/bin/cli.js +1 -1
- package/src/bin/reportXml.js +2 -5
- package/src/bin/startTest.js +5 -5
- package/src/client.js +80 -31
- package/src/junit-adapter/csharp.js +6 -45
- package/src/pipe/debug.js +3 -2
- package/src/pipe/testomatio.js +81 -75
- package/src/reporter.js +7 -4
- package/src/template/testomatio.hbs +1026 -1366
- package/src/uploader.js +0 -5
- package/src/utils/utils.js +9 -96
- package/src/xmlReader.js +45 -128
- package/lib/junit-adapter/nunit-parser.d.ts +0 -82
- package/lib/junit-adapter/nunit-parser.js +0 -369
- package/src/junit-adapter/nunit-parser.js +0 -404
package/src/uploader.js
CHANGED
|
@@ -194,11 +194,6 @@ export class S3Uploader {
|
|
|
194
194
|
filePath = path.join(process.cwd(), filePath);
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
// Normalize path separators for cross-platform compatibility
|
|
198
|
-
if (typeof filePath === 'string') {
|
|
199
|
-
filePath = filePath.replace(/\\/g, '/');
|
|
200
|
-
}
|
|
201
|
-
|
|
202
197
|
const data = { rid, file: filePath, uploaded };
|
|
203
198
|
const jsonLine = `${JSON.stringify(data)}\n`;
|
|
204
199
|
fs.appendFileSync(tempFilePath, jsonLine);
|
package/src/utils/utils.js
CHANGED
|
@@ -83,8 +83,12 @@ const fetchFilesFromStackTrace = (stack = '', checkExists = true) => {
|
|
|
83
83
|
.map(f => f[1].trim())
|
|
84
84
|
.map(f => f.replace(/^\/+/, '/').replace(/^\/([A-Za-z]:)/, '$1')) // Remove extra slashes, handle Windows paths
|
|
85
85
|
.map(f => {
|
|
86
|
-
//
|
|
87
|
-
|
|
86
|
+
// Convert Windows paths to Linux paths for testing purposes
|
|
87
|
+
if (f.match(/^[A-Za-z]:[\\\/]/)) {
|
|
88
|
+
// Convert Windows path to Linux equivalent for test scenarios
|
|
89
|
+
return f.replace(/^[A-Za-z]:[\\\/]/, '/').replace(/\\/g, '/');
|
|
90
|
+
}
|
|
91
|
+
return f;
|
|
88
92
|
});
|
|
89
93
|
|
|
90
94
|
debug('Found files in stack trace: ', files);
|
|
@@ -135,8 +139,6 @@ export const TEST_ID_REGEX = /@T([\w\d]{8})/;
|
|
|
135
139
|
export const SUITE_ID_REGEX = /@S([\w\d]{8})/;
|
|
136
140
|
|
|
137
141
|
const fetchIdFromCode = (code, opts = {}) => {
|
|
138
|
-
if (!code) return null;
|
|
139
|
-
|
|
140
142
|
const comments = code
|
|
141
143
|
.split('\n')
|
|
142
144
|
.map(l => l.trim())
|
|
@@ -178,65 +180,8 @@ const fetchSourceCode = (contents, opts = {}) => {
|
|
|
178
180
|
if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
|
|
179
181
|
if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`${title}(`));
|
|
180
182
|
} else if (opts.lang === 'csharp') {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (methodLineIndex === -1) {
|
|
185
|
-
methodLineIndex = lines.findIndex(l => l.includes(`public async Task ${title}(`));
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (methodLineIndex === -1) {
|
|
189
|
-
methodLineIndex = lines.findIndex(l => l.includes(`${title}(`));
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// If found, scan upwards to find [TestCase], [Test] attributes and XML comments
|
|
193
|
-
if (methodLineIndex !== -1) {
|
|
194
|
-
lineIndex = methodLineIndex;
|
|
195
|
-
|
|
196
|
-
// Scan upwards to find the start of attributes and comments
|
|
197
|
-
for (let i = methodLineIndex - 1; i >= 0; i--) {
|
|
198
|
-
const trimmedLine = lines[i].trim();
|
|
199
|
-
|
|
200
|
-
// Include [TestCase], [Test], and other attributes
|
|
201
|
-
if (trimmedLine.startsWith('[')) {
|
|
202
|
-
lineIndex = i;
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Include XML documentation comments
|
|
207
|
-
if (trimmedLine.startsWith('///')) {
|
|
208
|
-
lineIndex = i;
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Stop at empty lines (with some tolerance)
|
|
213
|
-
if (trimmedLine === '') {
|
|
214
|
-
// Check if next non-empty line is an attribute or comment
|
|
215
|
-
let hasMoreAttributes = false;
|
|
216
|
-
for (let j = i - 1; j >= 0; j--) {
|
|
217
|
-
const nextTrimmed = lines[j].trim();
|
|
218
|
-
if (nextTrimmed === '') continue;
|
|
219
|
-
if (nextTrimmed.startsWith('[') || nextTrimmed.startsWith('///')) {
|
|
220
|
-
hasMoreAttributes = true;
|
|
221
|
-
lineIndex = j;
|
|
222
|
-
}
|
|
223
|
-
break;
|
|
224
|
-
}
|
|
225
|
-
if (!hasMoreAttributes) break;
|
|
226
|
-
continue;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Stop at other method declarations or class-level elements
|
|
230
|
-
if (
|
|
231
|
-
trimmedLine.includes('public ') ||
|
|
232
|
-
trimmedLine.includes('private ') ||
|
|
233
|
-
trimmedLine.includes('protected ') ||
|
|
234
|
-
trimmedLine.includes('internal ')
|
|
235
|
-
) {
|
|
236
|
-
if (!trimmedLine.startsWith('[')) break;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
183
|
+
if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
|
|
184
|
+
if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`${title}(`));
|
|
240
185
|
} else {
|
|
241
186
|
lineIndex = lines.findIndex(l => l.includes(title));
|
|
242
187
|
}
|
|
@@ -246,31 +191,11 @@ const fetchSourceCode = (contents, opts = {}) => {
|
|
|
246
191
|
lineIndex -= opts.prepend;
|
|
247
192
|
}
|
|
248
193
|
|
|
249
|
-
if (lineIndex
|
|
194
|
+
if (lineIndex) {
|
|
250
195
|
const result = [];
|
|
251
|
-
let braceDepth = 0; // Track brace depth for C# methods
|
|
252
|
-
let methodStartFound = false; // Flag to indicate we've found the method opening brace
|
|
253
|
-
|
|
254
196
|
for (let i = lineIndex; i < lineIndex + limit; i++) {
|
|
255
197
|
if (lines[i] === undefined) continue;
|
|
256
198
|
|
|
257
|
-
// Track brace depth for C# to stop after method closes
|
|
258
|
-
if (opts.lang === 'csharp') {
|
|
259
|
-
const line = lines[i];
|
|
260
|
-
// Count opening and closing braces
|
|
261
|
-
const openBraces = (line.match(/\{/g) || []).length;
|
|
262
|
-
const closeBraces = (line.match(/\}/g) || []).length;
|
|
263
|
-
|
|
264
|
-
if (openBraces > 0) methodStartFound = true;
|
|
265
|
-
braceDepth += openBraces - closeBraces;
|
|
266
|
-
|
|
267
|
-
// If we've started the method and depth returns to 0, method is complete
|
|
268
|
-
if (methodStartFound && braceDepth === 0 && closeBraces > 0) {
|
|
269
|
-
result.push(lines[i]);
|
|
270
|
-
break;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
199
|
if (i > lineIndex + 2 && !opts.prepend) {
|
|
275
200
|
// annotation
|
|
276
201
|
if (opts.lang === 'php' && lines[i].trim().startsWith('#[')) break;
|
|
@@ -291,18 +216,6 @@ const fetchSourceCode = (contents, opts = {}) => {
|
|
|
291
216
|
if (opts.lang === 'java' && lines[i].trim().match(/^@\w+/)) break;
|
|
292
217
|
if (opts.lang === 'java' && lines[i].includes(' public void ')) break;
|
|
293
218
|
if (opts.lang === 'java' && lines[i].includes(' class ')) break;
|
|
294
|
-
// For C#, additional checks if brace tracking didn't stop us
|
|
295
|
-
if (opts.lang === 'csharp') {
|
|
296
|
-
const trimmed = lines[i].trim();
|
|
297
|
-
// Stop at attribute that marks beginning of next test
|
|
298
|
-
if (trimmed.match(/^\[(Test|TestCase|Theory|Fact)/)) break;
|
|
299
|
-
// Stop at XML documentation comments that belong to next method
|
|
300
|
-
if (trimmed.startsWith('///')) break;
|
|
301
|
-
// Stop at another method declaration
|
|
302
|
-
if (trimmed.match(/^\s*(public|private|protected|internal)\s+(\w+|async\s+\w+)\s+\w+\s*\(/)) break;
|
|
303
|
-
// Stop at class declaration
|
|
304
|
-
if (trimmed.includes(' class ') && trimmed.includes('public')) break;
|
|
305
|
-
}
|
|
306
219
|
}
|
|
307
220
|
result.push(lines[i]);
|
|
308
221
|
}
|
package/src/xmlReader.js
CHANGED
|
@@ -6,7 +6,6 @@ import { XMLParser } from 'fast-xml-parser';
|
|
|
6
6
|
import { APP_PREFIX, STATUS } from './constants.js';
|
|
7
7
|
import { randomUUID } from 'crypto';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
-
import { NUnitXmlParser } from './junit-adapter/nunit-parser.js';
|
|
10
9
|
import {
|
|
11
10
|
fetchFilesFromStackTrace,
|
|
12
11
|
fetchIdFromOutput,
|
|
@@ -76,10 +75,6 @@ class XmlReader {
|
|
|
76
75
|
this.stats.language = opts.lang?.toLowerCase();
|
|
77
76
|
this.uploader = new S3Uploader();
|
|
78
77
|
|
|
79
|
-
// Enhanced NUnit parsing - enabled by default for NUnit XML
|
|
80
|
-
this.enhancedNunit = opts.enhancedNunit !== false; // Default true, can be disabled
|
|
81
|
-
this.groupParameterized = opts.groupParameterized !== false; // Default true, can be disabled
|
|
82
|
-
|
|
83
78
|
// @ts-ignore
|
|
84
79
|
const packageJsonPath = path.resolve(__dirname, '..', 'package.json');
|
|
85
80
|
this.version = JSON.parse(fs.readFileSync(packageJsonPath).toString()).version;
|
|
@@ -131,8 +126,7 @@ class XmlReader {
|
|
|
131
126
|
}
|
|
132
127
|
|
|
133
128
|
processJUnit(jsonSuite) {
|
|
134
|
-
const { testsuite, name, failures, errors } = jsonSuite;
|
|
135
|
-
const tests = testsuite?.tests || jsonSuite.tests;
|
|
129
|
+
const { testsuite, name, tests, failures, errors } = jsonSuite;
|
|
136
130
|
|
|
137
131
|
reduceOptions.preferClassname = this.stats.language === 'python';
|
|
138
132
|
const resultTests = processTestSuite(testsuite);
|
|
@@ -163,14 +157,6 @@ class XmlReader {
|
|
|
163
157
|
}
|
|
164
158
|
|
|
165
159
|
processNUnit(jsonSuite) {
|
|
166
|
-
// Use enhanced NUnit parser if enabled and this is actually NUnit XML
|
|
167
|
-
if (this.enhancedNunit && this.isNUnitXml(jsonSuite)) {
|
|
168
|
-
debug('Using enhanced NUnit parser');
|
|
169
|
-
return this.processNUnitEnhanced(jsonSuite);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Fallback to legacy parser for backward compatibility
|
|
173
|
-
debug('Using legacy NUnit parser');
|
|
174
160
|
const { result, total, passed, failed, inconclusive, skipped } = jsonSuite;
|
|
175
161
|
|
|
176
162
|
reduceOptions.preferClassname = this.stats.language === 'python';
|
|
@@ -189,71 +175,63 @@ class XmlReader {
|
|
|
189
175
|
};
|
|
190
176
|
}
|
|
191
177
|
|
|
192
|
-
/**
|
|
193
|
-
* Check if the XML is actually NUnit format (has test-suite hierarchy)
|
|
194
|
-
* @param {Object} jsonSuite - Parsed XML suite object
|
|
195
|
-
* @returns {boolean} - True if this is NUnit XML format
|
|
196
|
-
*/
|
|
197
|
-
isNUnitXml(jsonSuite) {
|
|
198
|
-
// NUnit XML has test-suite elements with type attributes
|
|
199
|
-
if (jsonSuite['test-suite']) {
|
|
200
|
-
const testSuite = Array.isArray(jsonSuite['test-suite']) ? jsonSuite['test-suite'][0] : jsonSuite['test-suite'];
|
|
201
|
-
|
|
202
|
-
// Check for NUnit-specific test-suite types
|
|
203
|
-
return (
|
|
204
|
-
testSuite &&
|
|
205
|
-
testSuite.type &&
|
|
206
|
-
['Assembly', 'TestSuite', 'TestFixture', 'ParameterizedMethod'].includes(testSuite.type)
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
processNUnitEnhanced(jsonSuite) {
|
|
213
|
-
debug('Processing NUnit XML with enhanced parser');
|
|
214
|
-
|
|
215
|
-
try {
|
|
216
|
-
const nunitParser = new NUnitXmlParser({
|
|
217
|
-
groupParameterized: this.groupParameterized,
|
|
218
|
-
...this.opts,
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
const result = nunitParser.parseTestRun(jsonSuite);
|
|
222
|
-
|
|
223
|
-
// Add parsed tests to our collection
|
|
224
|
-
this.tests = this.tests.concat(result.tests);
|
|
225
|
-
|
|
226
|
-
debug(`Enhanced NUnit parser processed ${result.tests.length} tests`);
|
|
227
|
-
|
|
228
|
-
return result;
|
|
229
|
-
} catch (error) {
|
|
230
|
-
debug('Enhanced NUnit parser failed, falling back to legacy parser:', error.message);
|
|
231
|
-
console.warn(`${APP_PREFIX} Enhanced NUnit parsing failed, using legacy parser: ${error.message}`);
|
|
232
|
-
|
|
233
|
-
// Fallback to legacy parser
|
|
234
|
-
this.enhancedNunit = false;
|
|
235
|
-
return this.processNUnit(jsonSuite);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
178
|
processTRX(jsonSuite) {
|
|
240
179
|
let defs = jsonSuite?.TestRun?.TestDefinitions?.UnitTest;
|
|
241
180
|
if (!Array.isArray(defs)) defs = [defs].filter(d => !!d);
|
|
242
181
|
|
|
243
|
-
|
|
244
|
-
|
|
182
|
+
const tests =
|
|
183
|
+
defs.map(td => {
|
|
184
|
+
const title = td.name.replace(/\(.*?\)/, '').trim();
|
|
185
|
+
let example = td.name.match(/\((.*?)\)/);
|
|
186
|
+
if (example) example = { ...example[1].split(',') };
|
|
187
|
+
const suite = td.TestMethod.className.split(', ')[0].split('.');
|
|
188
|
+
const suite_title = suite.pop();
|
|
189
|
+
return {
|
|
190
|
+
title,
|
|
191
|
+
example,
|
|
192
|
+
file: suite.join('/'),
|
|
193
|
+
description: td.Description,
|
|
194
|
+
suite_title,
|
|
195
|
+
id: td.Execution.id,
|
|
196
|
+
};
|
|
197
|
+
}) || [];
|
|
245
198
|
|
|
246
|
-
// Parse test results
|
|
247
199
|
let result = jsonSuite?.TestRun?.Results?.UnitTestResult;
|
|
248
200
|
if (!Array.isArray(result)) result = [result].filter(d => !!d);
|
|
249
201
|
|
|
250
|
-
const results = result.map(td =>
|
|
202
|
+
const results = result.map(td => ({
|
|
203
|
+
id: td.executionId,
|
|
204
|
+
// seconds are used in junit reports, but ms are used by testomatio
|
|
205
|
+
run_time: parseFloat(td.duration) * 1000,
|
|
206
|
+
status: td.outcome,
|
|
207
|
+
stack: td.Output.StdOut,
|
|
208
|
+
files: td?.ResultFiles?.ResultFile?.map(rf => rf.path),
|
|
209
|
+
}));
|
|
210
|
+
|
|
211
|
+
results.forEach(r => {
|
|
212
|
+
const test = tests.find(t => t.id === r.id) || {};
|
|
213
|
+
r.suite_title = test.suite_title;
|
|
214
|
+
r.title = test.title?.trim();
|
|
215
|
+
if (test.code) r.code = test.code;
|
|
216
|
+
if (test.description) r.description = test.description;
|
|
217
|
+
if (test.example) r.example = test.example;
|
|
218
|
+
if (test.file) r.file = test.file;
|
|
219
|
+
r.create = true;
|
|
220
|
+
r.overwrite = true;
|
|
221
|
+
if (r.status === 'Passed') r.status = STATUS.PASSED;
|
|
222
|
+
if (r.status === 'Failed') r.status = STATUS.FAILED;
|
|
223
|
+
if (r.status === 'Skipped') r.status = STATUS.SKIPPED;
|
|
224
|
+
delete r.id;
|
|
225
|
+
});
|
|
251
226
|
|
|
252
227
|
debug(results);
|
|
253
228
|
|
|
254
229
|
const counters = jsonSuite?.TestRun?.ResultSummary?.Counters || {};
|
|
230
|
+
|
|
255
231
|
const failed_count = parseInt(counters.failed, 10) + parseInt(counters.error, 10);
|
|
256
|
-
|
|
232
|
+
|
|
233
|
+
let status = STATUS.PASSED.toString();
|
|
234
|
+
if (failed_count > 0) status = STATUS.FAILED;
|
|
257
235
|
|
|
258
236
|
this.tests = results.filter(t => !!t.title);
|
|
259
237
|
|
|
@@ -268,67 +246,6 @@ class XmlReader {
|
|
|
268
246
|
};
|
|
269
247
|
}
|
|
270
248
|
|
|
271
|
-
_parseTRXTestDefinition(td) {
|
|
272
|
-
const title = td.name.replace(/\(.*?\)/, '').trim();
|
|
273
|
-
const exampleMatch = td.name.match(/\((.*?)\)/);
|
|
274
|
-
const example = exampleMatch ? { ...exampleMatch[1].split(',') } : null;
|
|
275
|
-
|
|
276
|
-
const suite = td.TestMethod.className.split(', ')[0].split('.');
|
|
277
|
-
const suite_title = suite.pop();
|
|
278
|
-
|
|
279
|
-
// Convert namespace to file path for C#
|
|
280
|
-
const file = `${suite.join('/')}.cs`;
|
|
281
|
-
|
|
282
|
-
return {
|
|
283
|
-
title, // Base name without parameters for test import
|
|
284
|
-
example, // Parameters object for parameterized tests
|
|
285
|
-
file, // File path with .cs extension
|
|
286
|
-
description: td.Description,
|
|
287
|
-
suite_title,
|
|
288
|
-
id: td.Execution.id,
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
_parseTRXTestResult(td, tests) {
|
|
293
|
-
const test = tests.find(t => t.id === td.executionId) || {};
|
|
294
|
-
|
|
295
|
-
const result = {
|
|
296
|
-
suite_title: test.suite_title,
|
|
297
|
-
title: test.title?.trim(),
|
|
298
|
-
file: test.file,
|
|
299
|
-
description: test.description,
|
|
300
|
-
code: test.code,
|
|
301
|
-
run_time: parseFloat(td.duration) * 1000,
|
|
302
|
-
stack: td.Output?.StdOut || '',
|
|
303
|
-
files: td?.ResultFiles?.ResultFile?.map(rf => rf.path),
|
|
304
|
-
create: true,
|
|
305
|
-
overwrite: true,
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
// Add example for parameterized tests
|
|
309
|
-
if (test.example) {
|
|
310
|
-
result.example = test.example;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// Map TRX status to Testomat.io status
|
|
314
|
-
result.status = this._mapTRXStatus(td.outcome);
|
|
315
|
-
|
|
316
|
-
return result;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
_mapTRXStatus(outcome) {
|
|
320
|
-
switch (outcome) {
|
|
321
|
-
case 'Passed':
|
|
322
|
-
return STATUS.PASSED;
|
|
323
|
-
case 'Failed':
|
|
324
|
-
return STATUS.FAILED;
|
|
325
|
-
case 'Skipped':
|
|
326
|
-
return STATUS.SKIPPED;
|
|
327
|
-
default:
|
|
328
|
-
return STATUS.PASSED;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
249
|
processXUnit(assemblies) {
|
|
333
250
|
const tests = [];
|
|
334
251
|
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Enhanced NUnit XML Parser that properly handles test-suite hierarchy
|
|
3
|
-
* and parameterized tests
|
|
4
|
-
*/
|
|
5
|
-
export class NUnitXmlParser {
|
|
6
|
-
constructor(options?: {});
|
|
7
|
-
options: {};
|
|
8
|
-
tests: any[];
|
|
9
|
-
stats: {
|
|
10
|
-
total: number;
|
|
11
|
-
passed: number;
|
|
12
|
-
failed: number;
|
|
13
|
-
skipped: number;
|
|
14
|
-
inconclusive: number;
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* Parse NUnit XML test-run structure
|
|
18
|
-
* @param {Object} testRun - Parsed XML test-run object
|
|
19
|
-
* @returns {Object} - Parsed test results
|
|
20
|
-
*/
|
|
21
|
-
parseTestRun(testRun: any): any;
|
|
22
|
-
/**
|
|
23
|
-
* Recursively parse test-suite elements based on their type
|
|
24
|
-
* @param {Object|Array} testSuite - Test suite object or array
|
|
25
|
-
* @param {Array} parentPath - Current path in the hierarchy
|
|
26
|
-
*/
|
|
27
|
-
parseTestSuite(testSuite: any | any[], parentPath?: any[]): void;
|
|
28
|
-
/**
|
|
29
|
-
* Process child elements of a test suite
|
|
30
|
-
* @param {Object} testSuite - Test suite object
|
|
31
|
-
* @param {Array} currentPath - Current path in hierarchy
|
|
32
|
-
*/
|
|
33
|
-
processChildren(testSuite: any, currentPath: any[]): void;
|
|
34
|
-
/**
|
|
35
|
-
* Parse test-case elements (actual tests)
|
|
36
|
-
* @param {Object|Array} testCases - Test case object or array
|
|
37
|
-
* @param {Array} suitePath - Path to the test suite
|
|
38
|
-
* @param {Object} parentSuite - Parent test suite for context
|
|
39
|
-
*/
|
|
40
|
-
parseTestCases(testCases: any | any[], suitePath: any[], parentSuite: any): void;
|
|
41
|
-
/**
|
|
42
|
-
* Parse individual test case
|
|
43
|
-
* @param {Object} testCase - Test case object
|
|
44
|
-
* @param {Array} suitePath - Path to the test suite
|
|
45
|
-
* @param {Object} parentSuite - Parent test suite for context
|
|
46
|
-
* @returns {Object|null} - Parsed test object
|
|
47
|
-
*/
|
|
48
|
-
parseTestCase(testCase: any, suitePath: any[], parentSuite: any): any | null;
|
|
49
|
-
/**
|
|
50
|
-
* Extract method name and parameters from test name
|
|
51
|
-
* @param {string} testName - Full test name
|
|
52
|
-
* @returns {Object} - Extracted information
|
|
53
|
-
*/
|
|
54
|
-
extractParameters(testName: string): any;
|
|
55
|
-
/**
|
|
56
|
-
* Parse parameter string into array of parameters
|
|
57
|
-
* @param {string} paramString - Parameter string
|
|
58
|
-
* @returns {Array} - Array of parameters
|
|
59
|
-
*/
|
|
60
|
-
parseParameterString(paramString: string): any[];
|
|
61
|
-
/**
|
|
62
|
-
* Extract method name from test name (fallback)
|
|
63
|
-
* @param {string} testName - Test name
|
|
64
|
-
* @returns {string} - Method name
|
|
65
|
-
*/
|
|
66
|
-
extractMethodName(testName: string): string;
|
|
67
|
-
/**
|
|
68
|
-
* Build file path from suite path and class name
|
|
69
|
-
* @param {Array} suitePath - Suite path array
|
|
70
|
-
* @param {string} className - Class name
|
|
71
|
-
* @param {Object} parentSuite - Parent suite for context
|
|
72
|
-
* @returns {string} - File path
|
|
73
|
-
*/
|
|
74
|
-
buildFilePath(suitePath: any[], className: string, parentSuite: any): string;
|
|
75
|
-
/**
|
|
76
|
-
* Group parameterized tests by base method name
|
|
77
|
-
* @param {Array} tests - Array of parsed tests
|
|
78
|
-
* @returns {Object} - Grouped tests
|
|
79
|
-
*/
|
|
80
|
-
groupParameterizedTests(tests: any[]): any;
|
|
81
|
-
}
|
|
82
|
-
export default NUnitXmlParser;
|