@testomatio/reporter 2.3.7-beta.8-stack-artifacts → 2.3.7-rc.1
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 +13 -3
- package/lib/bin/startTest.js +3 -3
- package/lib/client.d.ts +1 -1
- package/lib/client.js +8 -8
- package/lib/pipe/testomatio.d.ts +2 -1
- package/lib/pipe/testomatio.js +3 -2
- package/lib/template/testomatio.hbs +1366 -1026
- package/lib/utils/utils.js +7 -3
- package/package.json +8 -4
- package/src/bin/cli.js +1 -1
- package/src/bin/reportXml.js +5 -2
- package/src/bin/startTest.js +5 -5
- package/src/client.js +8 -8
- package/src/junit-adapter/csharp.js +45 -6
- package/src/junit-adapter/nunit-parser.js +462 -0
- package/src/pipe/testomatio.js +1 -1
- package/src/template/testomatio.hbs +1366 -1026
- package/src/uploader.js +5 -0
- package/src/utils/utils.js +213 -22
- package/src/xmlReader.js +131 -45
- package/types/types.d.ts +364 -0
- package/types/vitest.types.d.ts +93 -0
package/lib/utils/utils.js
CHANGED
|
@@ -471,10 +471,14 @@ function transformEnvVarToBoolean(value) {
|
|
|
471
471
|
return Boolean(value);
|
|
472
472
|
}
|
|
473
473
|
function truncate(s, size = 255) {
|
|
474
|
-
if (s
|
|
475
|
-
return
|
|
474
|
+
if (s === undefined || s === null) {
|
|
475
|
+
return '';
|
|
476
|
+
}
|
|
477
|
+
const str = s.toString();
|
|
478
|
+
if (str.trim().length < size) {
|
|
479
|
+
return str;
|
|
476
480
|
}
|
|
477
|
-
return `${
|
|
481
|
+
return `${str.substring(0, size)}...`;
|
|
478
482
|
}
|
|
479
483
|
|
|
480
484
|
module.exports.getPackageVersion = getPackageVersion;
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testomatio/reporter",
|
|
3
|
-
"version": "2.3.7-
|
|
3
|
+
"version": "2.3.7-rc.1",
|
|
4
4
|
"description": "Testomatio Reporter Client",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18"
|
|
7
7
|
},
|
|
8
|
-
"
|
|
8
|
+
"main": "lib/reporter.js",
|
|
9
|
+
"module": "src/reporter.js",
|
|
10
|
+
"types": "types/types.d.ts",
|
|
9
11
|
"repository": "git@github.com:testomatio/reporter.git",
|
|
10
12
|
"author": "Michael Bodnarchuk <davert@testomat.io>,Koushik Mohan <koushikmohan1996@gmail.com>",
|
|
11
13
|
"license": "MIT",
|
|
@@ -45,7 +47,8 @@
|
|
|
45
47
|
"bin",
|
|
46
48
|
"lib",
|
|
47
49
|
"src",
|
|
48
|
-
"testcafe"
|
|
50
|
+
"testcafe",
|
|
51
|
+
"types"
|
|
49
52
|
],
|
|
50
53
|
"scripts": {
|
|
51
54
|
"clear-exportdir": "rm -rf export/",
|
|
@@ -57,7 +60,8 @@
|
|
|
57
60
|
"test": "mocha 'tests/unit/**/*_test.js'",
|
|
58
61
|
"test:playwright": "mocha tests/adapter/playwright.test.js",
|
|
59
62
|
"test:codecept": "mocha tests/adapter/codecept.test.js tests/adapter/codecept_comprehensive.test.js tests/adapter/codecept_steps_sections.test.js",
|
|
60
|
-
"test:
|
|
63
|
+
"test:vitest": "mocha tests/adapter/vitest.test.js",
|
|
64
|
+
"test:frameworks": "npm run test:playwright && npm run test:codecept && npm run test:vitest",
|
|
61
65
|
"test:all": "npm run test && npm run test:frameworks",
|
|
62
66
|
"test:adapters": "mocha tests/adapter/*.test.js",
|
|
63
67
|
"test:codecept:bug948": "mocha tests/adapter/codecept_aftersuite_failure.test.js",
|
package/src/bin/cli.js
CHANGED
|
@@ -158,7 +158,7 @@ program
|
|
|
158
158
|
.option('--lang <lang>', 'Language used (python, ruby, java)')
|
|
159
159
|
.option('--timelimit <time>', 'default time limit in seconds to kill a stuck process')
|
|
160
160
|
.action(async (pattern, opts) => {
|
|
161
|
-
if (!pattern.endsWith('.xml')) {
|
|
161
|
+
if (!pattern.endsWith('.xml') && !pattern.includes('*')) {
|
|
162
162
|
pattern += '.xml';
|
|
163
163
|
}
|
|
164
164
|
let { javaTests, lang } = opts;
|
package/src/bin/reportXml.js
CHANGED
|
@@ -23,7 +23,7 @@ program
|
|
|
23
23
|
.option('--timelimit <time>', 'default time limit in seconds to kill a stuck process')
|
|
24
24
|
.option('--env-file <envfile>', 'Load environment variables from env file')
|
|
25
25
|
.action(async (pattern, opts) => {
|
|
26
|
-
if (!pattern.endsWith('.xml')) {
|
|
26
|
+
if (!pattern.endsWith('.xml') && !pattern.includes('*')) {
|
|
27
27
|
pattern += '.xml';
|
|
28
28
|
}
|
|
29
29
|
let { javaTests, lang } = opts;
|
|
@@ -34,7 +34,10 @@ program
|
|
|
34
34
|
}
|
|
35
35
|
lang = lang?.toLowerCase();
|
|
36
36
|
if (javaTests === true || (lang === 'java' && !javaTests)) javaTests = 'src/test/java';
|
|
37
|
-
const runReader = new XmlReader({
|
|
37
|
+
const runReader = new XmlReader({
|
|
38
|
+
javaTests,
|
|
39
|
+
lang,
|
|
40
|
+
});
|
|
38
41
|
const files = glob.sync(pattern, { cwd: opts.dir || process.cwd() });
|
|
39
42
|
if (!files.length) {
|
|
40
43
|
console.log(APP_PREFIX, `Report can't be created. No XML files found 😥`);
|
package/src/bin/startTest.js
CHANGED
|
@@ -18,7 +18,7 @@ const newArgs = ['run'];
|
|
|
18
18
|
let i = 0;
|
|
19
19
|
while (i < args.length) {
|
|
20
20
|
const arg = args[i];
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
if (arg === '-c' || arg === '--command') {
|
|
23
23
|
// Map -c/--command to positional argument for run command
|
|
24
24
|
i++;
|
|
@@ -33,7 +33,7 @@ while (i < args.length) {
|
|
|
33
33
|
// Map --launch to start command
|
|
34
34
|
newArgs[0] = 'start';
|
|
35
35
|
} else if (arg === '--finish') {
|
|
36
|
-
// Map --finish to finish command
|
|
36
|
+
// Map --finish to finish command
|
|
37
37
|
newArgs[0] = 'finish';
|
|
38
38
|
} else {
|
|
39
39
|
// Pass through other arguments
|
|
@@ -45,9 +45,9 @@ while (i < args.length) {
|
|
|
45
45
|
// Execute the main CLI with mapped arguments
|
|
46
46
|
|
|
47
47
|
const child = spawn(process.execPath, [cliPath, ...newArgs], {
|
|
48
|
-
stdio: 'inherit'
|
|
48
|
+
stdio: 'inherit',
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
child.on('exit',
|
|
51
|
+
child.on('exit', code => {
|
|
52
52
|
process.exit(code);
|
|
53
|
-
});
|
|
53
|
+
});
|
package/src/client.js
CHANGED
|
@@ -170,12 +170,12 @@ class Client {
|
|
|
170
170
|
title,
|
|
171
171
|
suite_title,
|
|
172
172
|
} = testData;
|
|
173
|
-
|
|
173
|
+
let steps = originalSteps;
|
|
174
174
|
|
|
175
175
|
const uploadedFiles = [];
|
|
176
176
|
const stackArtifactsEnabled = transformEnvVarToBoolean(process.env.TESTOMATIO_STACK_ARTIFACTS);
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
|
|
179
179
|
const {
|
|
180
180
|
time = 0,
|
|
181
181
|
example = null,
|
|
@@ -210,18 +210,18 @@ class Client {
|
|
|
210
210
|
|
|
211
211
|
let fullLogs = this.formatLogs({ error: errorFormatted, steps, logs: testData.logs });
|
|
212
212
|
|
|
213
|
-
if (stackArtifactsEnabled) {
|
|
214
|
-
const timestamp = +new Date;
|
|
213
|
+
if (stackArtifactsEnabled && fullLogs?.trim()?.length > 0) {
|
|
215
214
|
uploadedFiles.push(
|
|
216
215
|
this.uploader.uploadFileAsBuffer(
|
|
217
216
|
Buffer.from(stripColors(fullLogs), 'utf8'),
|
|
218
|
-
[this.runId, rid, `logs_${
|
|
217
|
+
[this.runId, rid, `logs_${+new Date}.log`]
|
|
219
218
|
)
|
|
220
219
|
);
|
|
221
220
|
fullLogs = '';
|
|
221
|
+
steps = null;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
|
|
224
|
+
|
|
225
225
|
if (!this.pipes || !this.pipes.length)
|
|
226
226
|
this.pipes = await pipesFactory(this.paramsForPipesFactory || {}, this.pipeStore);
|
|
227
227
|
|
|
@@ -336,7 +336,7 @@ class Client {
|
|
|
336
336
|
const uploadedArtifacts = this.uploader.successfulUploads.map(file => ({
|
|
337
337
|
relativePath: file.path.replace(process.cwd(), ''),
|
|
338
338
|
link: file.link,
|
|
339
|
-
sizePretty: prettyBytes(file.size, { round: 0 }).toString(),
|
|
339
|
+
sizePretty: file.size == null ? 'unknown' : prettyBytes(file.size, { round: 0 }).toString(),
|
|
340
340
|
}));
|
|
341
341
|
|
|
342
342
|
uploadedArtifacts.forEach(upload => {
|
|
@@ -358,7 +358,7 @@ class Client {
|
|
|
358
358
|
);
|
|
359
359
|
const failedUploads = this.uploader.failedUploads.map(file => ({
|
|
360
360
|
relativePath: file.path.replace(process.cwd(), ''),
|
|
361
|
-
sizePretty: prettyBytes(file.size, { round: 0 }).toString(),
|
|
361
|
+
sizePretty: file.size == null ? 'unknown' : prettyBytes(file.size, { round: 0 }).toString(),
|
|
362
362
|
}));
|
|
363
363
|
|
|
364
364
|
const pathPadding = Math.max(...failedUploads.map(upload => upload.relativePath.length)) + 1;
|
|
@@ -3,18 +3,50 @@ import Adapter from './adapter.js';
|
|
|
3
3
|
|
|
4
4
|
class CSharpAdapter extends Adapter {
|
|
5
5
|
formatTest(t) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
// Extract example from title if not already present
|
|
7
|
+
if (!t.example) {
|
|
8
|
+
const exampleMatch = t.title.match(/\((.*?)\)/);
|
|
9
|
+
if (exampleMatch) {
|
|
10
|
+
// Extract parameters as object with numeric keys for API
|
|
11
|
+
const params = exampleMatch[1].split(',').map(param => param.trim());
|
|
12
|
+
t.example = {};
|
|
13
|
+
params.forEach((param, index) => {
|
|
14
|
+
t.example[index] = param;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Remove parameters from title to avoid duplicates in Test Suite
|
|
20
|
+
// The example field will be used for grouping on import
|
|
21
|
+
t.title = t.title.replace(/\(.*?\)/, '').trim();
|
|
22
|
+
|
|
9
23
|
const suite = t.suite_title.split('.');
|
|
10
24
|
t.suite_title = suite.pop();
|
|
11
25
|
t.file = namespaceToFileName(t.file);
|
|
12
|
-
t.title = title.trim();
|
|
13
26
|
return t;
|
|
14
27
|
}
|
|
15
28
|
|
|
16
29
|
getFilePath(t) {
|
|
17
|
-
|
|
30
|
+
if (!t.file) return null;
|
|
31
|
+
|
|
32
|
+
// Normalize path separators for cross-platform compatibility
|
|
33
|
+
let filePath = t.file.replace(/\\/g, '/');
|
|
34
|
+
|
|
35
|
+
// If file already has .cs extension, use it directly
|
|
36
|
+
if (filePath.endsWith('.cs')) {
|
|
37
|
+
// Make relative path if it's absolute
|
|
38
|
+
if (path.isAbsolute(filePath)) {
|
|
39
|
+
// Try to find project-relative path
|
|
40
|
+
const cwd = process.cwd().replace(/\\/g, '/');
|
|
41
|
+
if (filePath.startsWith(cwd)) {
|
|
42
|
+
filePath = path.relative(cwd, filePath).replace(/\\/g, '/');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return filePath;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Convert namespace path to file path
|
|
49
|
+
const fileName = namespaceToFileName(filePath);
|
|
18
50
|
return fileName;
|
|
19
51
|
}
|
|
20
52
|
}
|
|
@@ -22,7 +54,14 @@ class CSharpAdapter extends Adapter {
|
|
|
22
54
|
export default CSharpAdapter;
|
|
23
55
|
|
|
24
56
|
function namespaceToFileName(fileName) {
|
|
57
|
+
if (!fileName) return '';
|
|
58
|
+
|
|
59
|
+
// If already a .cs file path, clean it up
|
|
60
|
+
if (fileName.endsWith('.cs')) {
|
|
61
|
+
return fileName.replace(/\\/g, '/');
|
|
62
|
+
}
|
|
63
|
+
|
|
25
64
|
const fileParts = fileName.split('.');
|
|
26
65
|
fileParts[fileParts.length - 1] = fileParts[fileParts.length - 1]?.replace(/\$.*/, '');
|
|
27
|
-
return `${fileParts.join(
|
|
66
|
+
return `${fileParts.join('/')}.cs`;
|
|
28
67
|
}
|