@testomatio/reporter 2.6.0-beta.1.allure → 2.6.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 +9 -11
- package/lib/adapter/playwright.d.ts +2 -0
- package/lib/adapter/playwright.js +29 -5
- package/lib/adapter/utils/playwright.d.ts +25 -0
- package/lib/adapter/utils/playwright.js +123 -0
- package/lib/adapter/vitest.js +2 -1
- package/lib/bin/cli.js +36 -36
- package/lib/data-storage.d.ts +1 -1
- package/lib/data-storage.js +1 -0
- package/lib/junit-adapter/index.js +0 -4
- package/lib/pipe/coverage.js +63 -5
- package/lib/pipe/debug.js +1 -2
- package/lib/pipe/github.js +15 -0
- package/lib/pipe/html.d.ts +2 -3
- package/lib/pipe/html.js +745 -37
- package/lib/pipe/testomatio.js +83 -36
- package/lib/reporter-functions.d.ts +36 -11
- package/lib/reporter-functions.js +72 -22
- package/lib/reporter.d.ts +90 -38
- package/lib/services/artifacts.d.ts +1 -1
- package/lib/services/key-values.d.ts +1 -1
- package/lib/services/links.d.ts +5 -3
- package/lib/services/links.js +1 -1
- package/lib/services/logger.d.ts +1 -1
- package/lib/template/testomatio-old.hbs +1421 -0
- package/lib/template/testomatio.hbs +3200 -1157
- package/lib/utils/log-formatter.d.ts +1 -2
- package/lib/utils/log-formatter.js +8 -4
- package/lib/utils/utils.js +0 -9
- package/package.json +2 -2
- package/src/adapter/playwright.js +32 -6
- package/src/adapter/utils/playwright.js +121 -0
- package/src/adapter/vitest.js +2 -1
- package/src/bin/cli.js +39 -47
- package/src/data-storage.js +1 -0
- package/src/junit-adapter/index.js +0 -4
- package/src/pipe/coverage.js +90 -32
- package/src/pipe/debug.js +1 -2
- package/src/pipe/github.js +14 -0
- package/src/pipe/html.js +844 -38
- package/src/pipe/testomatio.js +98 -53
- package/src/reporter-functions.js +73 -25
- package/src/services/links.js +1 -1
- package/src/template/testomatio-old.hbs +1421 -0
- package/src/template/testomatio.hbs +3200 -1157
- package/src/utils/log-formatter.js +9 -4
- package/src/utils/utils.js +0 -5
- package/types/types.d.ts +30 -6
- package/lib/allureReader.d.ts +0 -65
- package/lib/allureReader.js +0 -448
- package/lib/junit-adapter/kotlin.d.ts +0 -5
- package/lib/junit-adapter/kotlin.js +0 -46
- package/lib/services/labels.d.ts +0 -0
- package/lib/services/labels.js +0 -0
- package/src/allureReader.js +0 -523
- package/src/junit-adapter/kotlin.js +0 -48
- package/src/services/labels.js +0 -1
|
@@ -25,5 +25,4 @@ export function formatError(error: Error & {
|
|
|
25
25
|
actual?: any;
|
|
26
26
|
expected?: any;
|
|
27
27
|
}, message?: string): string;
|
|
28
|
-
export
|
|
29
|
-
import { stripVTControlCharacters } from 'util';
|
|
28
|
+
export function stripColors(str: string): string;
|
|
@@ -114,10 +114,14 @@ function formatError(error, message) {
|
|
|
114
114
|
* @returns {boolean}
|
|
115
115
|
*/
|
|
116
116
|
function isNotInternalFrame(frame) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
const fileName = frame.getFileName();
|
|
118
|
+
if (!fileName)
|
|
119
|
+
return false;
|
|
120
|
+
const isFileUrl = fileName.startsWith('file://');
|
|
121
|
+
const hasPathSeparator = fileName.includes(path_1.sep) || fileName.includes('/') || isFileUrl;
|
|
122
|
+
return (hasPathSeparator &&
|
|
123
|
+
!fileName.includes('node_modules') &&
|
|
124
|
+
!fileName.includes('internal'));
|
|
121
125
|
}
|
|
122
126
|
|
|
123
127
|
module.exports.formatLogs = formatLogs;
|
package/lib/utils/utils.js
CHANGED
|
@@ -311,15 +311,6 @@ const fetchSourceCode = (contents, opts = {}) => {
|
|
|
311
311
|
if (lineIndex === -1)
|
|
312
312
|
lineIndex = lines.findIndex(l => l.includes(`${title}(`));
|
|
313
313
|
}
|
|
314
|
-
else if (opts.lang === 'kotlin') {
|
|
315
|
-
lineIndex = lines.findIndex(l => l.includes(`fun test${title}`));
|
|
316
|
-
if (lineIndex === -1)
|
|
317
|
-
lineIndex = lines.findIndex(l => l.includes(`@DisplayName("${title}`));
|
|
318
|
-
if (lineIndex === -1)
|
|
319
|
-
lineIndex = lines.findIndex(l => l.includes(`fun ${title}`));
|
|
320
|
-
if (lineIndex === -1)
|
|
321
|
-
lineIndex = lines.findIndex(l => l.includes(`${title}(`));
|
|
322
|
-
}
|
|
323
314
|
else if (opts.lang === 'csharp') {
|
|
324
315
|
// Find the method declaration line
|
|
325
316
|
let methodLineIndex = lines.findIndex(l => l.includes(`public void ${title}(`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testomatio/reporter",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"description": "Testomatio Reporter Client",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18"
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"csv-writer": "^1.6.0",
|
|
25
25
|
"debug": "4.3.4",
|
|
26
26
|
"dotenv": "^16.0.1",
|
|
27
|
-
"fast-xml-parser": "^
|
|
27
|
+
"fast-xml-parser": "^5.3.4",
|
|
28
28
|
"file-url": "3.0.0",
|
|
29
29
|
"filesize": "^10.1.6",
|
|
30
30
|
"gaxios": ">=6.0 || >=7.0.0-rc.4 || <8",
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import pc from 'picocolors';
|
|
2
1
|
import crypto from 'crypto';
|
|
3
2
|
import os from 'os';
|
|
4
3
|
import path from 'path';
|
|
@@ -10,6 +9,8 @@ import { getTestomatIdFromTestTitle, fileSystem } from '../utils/utils.js';
|
|
|
10
9
|
import { services } from '../services/index.js';
|
|
11
10
|
import { dataStorage } from '../data-storage.js';
|
|
12
11
|
import { extensionMap } from '../utils/constants.js';
|
|
12
|
+
import pc from 'picocolors';
|
|
13
|
+
import { fetchLinksFromLogs } from './utils/playwright.js';
|
|
13
14
|
|
|
14
15
|
const reportTestPromises = [];
|
|
15
16
|
|
|
@@ -41,6 +42,16 @@ class PlaywrightReporter {
|
|
|
41
42
|
|
|
42
43
|
const { title } = test;
|
|
43
44
|
const { error, duration } = result;
|
|
45
|
+
const pwAttachments = (result.attachments || []).filter(a => a.body || a.path);
|
|
46
|
+
|
|
47
|
+
const files = pwAttachments
|
|
48
|
+
.map(att => ({
|
|
49
|
+
path: this.#getArtifactPath(att),
|
|
50
|
+
title: att.name || title,
|
|
51
|
+
type: att.contentType,
|
|
52
|
+
}))
|
|
53
|
+
.filter(f => f.path);
|
|
54
|
+
|
|
44
55
|
const suite_title = test.parent ? test.parent?.title : path.basename(test?.location?.file);
|
|
45
56
|
|
|
46
57
|
const steps = [];
|
|
@@ -55,13 +66,26 @@ class PlaywrightReporter {
|
|
|
55
66
|
const tags = extractTags(test);
|
|
56
67
|
|
|
57
68
|
const fullTestTitle = getTestContextName(test);
|
|
69
|
+
|
|
58
70
|
let logs = '';
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
// get links along with filtered logs (liks related logs removed)
|
|
72
|
+
const { stdout: filteredStdout, links, meta } = fetchLinksFromLogs(result.stdout);
|
|
73
|
+
if (filteredStdout?.length || result.stderr?.length) {
|
|
74
|
+
logs = `\n\n${pc.bold('Logs:')}\n${pc.red(result.stderr.join(''))}\n${filteredStdout.join('')}`;
|
|
61
75
|
}
|
|
76
|
+
|
|
77
|
+
/*
|
|
78
|
+
All services fucntions work different for Playwright.
|
|
79
|
+
We don't have access to test title (as result, to test id) when calling this functions inside a test.
|
|
80
|
+
Thus, when user calls services functions inside a test, we just log this data to console.
|
|
81
|
+
Playwright intercepts the console.log on it's end and we just get this data from it.
|
|
82
|
+
Thus, we have a tiny drawback: all data from services functions inside a test will be logged to console.
|
|
83
|
+
And this requires a condition to be added for each service function – if its Playwright, then log to console.
|
|
84
|
+
|
|
85
|
+
"get" method of services will not return data for Playwright, we should parse stdout.
|
|
86
|
+
*/
|
|
62
87
|
const manuallyAttachedArtifacts = services.artifacts.get(fullTestTitle);
|
|
63
88
|
const testMeta = services.keyValues.get(fullTestTitle);
|
|
64
|
-
const links = services.links.get(fullTestTitle);
|
|
65
89
|
const rid = test.id || test.testId || uuidv4();
|
|
66
90
|
|
|
67
91
|
/**
|
|
@@ -102,12 +126,14 @@ class PlaywrightReporter {
|
|
|
102
126
|
logs,
|
|
103
127
|
links,
|
|
104
128
|
manuallyAttachedArtifacts,
|
|
129
|
+
files: files.length ? files : undefined,
|
|
105
130
|
meta: {
|
|
106
131
|
browser: project.browser,
|
|
107
132
|
isMobile: project.isMobile,
|
|
108
133
|
project: project.name,
|
|
109
134
|
projectDependencies: project.dependencies?.length ? project.dependencies : null,
|
|
110
135
|
...testMeta,
|
|
136
|
+
...meta,
|
|
111
137
|
...project.metadata, // metadata has any type (in playwright), but we will stringify it in client.js
|
|
112
138
|
...test.annotations?.reduce((acc, annotation) => {
|
|
113
139
|
acc[annotation.type] = annotation.description;
|
|
@@ -120,7 +146,7 @@ class PlaywrightReporter {
|
|
|
120
146
|
this.uploads.push({
|
|
121
147
|
rid: `${rid}-${project.name}`,
|
|
122
148
|
title: test.title,
|
|
123
|
-
files:
|
|
149
|
+
files: pwAttachments,
|
|
124
150
|
file: test.location?.file,
|
|
125
151
|
});
|
|
126
152
|
// remove empty uploads
|
|
@@ -289,4 +315,4 @@ function getTestContextName(test) {
|
|
|
289
315
|
}
|
|
290
316
|
|
|
291
317
|
export default PlaywrightReporter;
|
|
292
|
-
export { extractTags };
|
|
318
|
+
export { extractTags, fetchLinksFromLogs };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import createDebugMessages from 'debug';
|
|
2
|
+
const debug = createDebugMessages('@testomatio/reporter:adapter-playwright-utils');
|
|
3
|
+
|
|
4
|
+
export const playwrightLogsMarkers = {
|
|
5
|
+
label: '[TESTOMATIO-LABEL]',
|
|
6
|
+
meta: '[TESTOMATIO-META]',
|
|
7
|
+
linkTest: '[TESTOMATIO-LINK-TEST]',
|
|
8
|
+
linkJira: '[TESTOMATIO-LINK-JIRA]',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Fetches links from stdout. Returns links and filtered stdout (without data containing markers)
|
|
13
|
+
*
|
|
14
|
+
* @param {(string | Buffer)[]} stdout
|
|
15
|
+
* @returns {{
|
|
16
|
+
* links: { [key: 'test' | 'jira' | 'label']: string }[],
|
|
17
|
+
* meta: { [key: string]: any },
|
|
18
|
+
* stdout: (string | Buffer)[]
|
|
19
|
+
* }}
|
|
20
|
+
*/
|
|
21
|
+
export function fetchLinksFromLogs(stdout) {
|
|
22
|
+
const links = [];
|
|
23
|
+
const meta = {};
|
|
24
|
+
|
|
25
|
+
const markers = [
|
|
26
|
+
{ key: playwrightLogsMarkers.linkTest, type: 'test' },
|
|
27
|
+
{ key: playwrightLogsMarkers.linkJira, type: 'jira' },
|
|
28
|
+
{ key: playwrightLogsMarkers.label, type: 'label' },
|
|
29
|
+
{ key: playwrightLogsMarkers.meta, type: 'meta' },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const filteredStdout = [];
|
|
33
|
+
|
|
34
|
+
stdout.forEach(entry => {
|
|
35
|
+
if (typeof entry !== 'string') {
|
|
36
|
+
filteredStdout.push(entry);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// check if entry contains any of markers
|
|
41
|
+
if (!markers.some(m => entry.includes(m.key))) {
|
|
42
|
+
filteredStdout.push(entry);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const newEntryLines = [];
|
|
47
|
+
entry.split('\n').forEach(line => {
|
|
48
|
+
line = line.trim();
|
|
49
|
+
let hasMarker = false;
|
|
50
|
+
for (const marker of markers) {
|
|
51
|
+
// links (test/jira/label) stored as array of objects
|
|
52
|
+
if (line.includes(marker.key)) {
|
|
53
|
+
hasMarker = true;
|
|
54
|
+
try {
|
|
55
|
+
const rawData = line.split(marker.key)[1]?.trim();
|
|
56
|
+
if (!rawData) continue;
|
|
57
|
+
|
|
58
|
+
let data;
|
|
59
|
+
try {
|
|
60
|
+
data = JSON.parse(rawData);
|
|
61
|
+
} catch (e) {
|
|
62
|
+
// Try to extract JSON from the beginning of the string (to handle trailing text)
|
|
63
|
+
const jsonMatch = rawData.match(/^\s*(\[.*?\]|\{.*?\})/);
|
|
64
|
+
if (jsonMatch) {
|
|
65
|
+
try {
|
|
66
|
+
data = JSON.parse(jsonMatch[1]);
|
|
67
|
+
} catch (jsonError) {
|
|
68
|
+
// If JSON extraction fails, skip this entry
|
|
69
|
+
debug('Error parsing links from string:', line, '\n', jsonError);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
// No JSON found, skip this entry
|
|
74
|
+
debug('No valid JSON found in:', line);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (marker.type === 'meta') {
|
|
80
|
+
// meta stored as an object, thus make it similar to links
|
|
81
|
+
Object.assign(meta, data);
|
|
82
|
+
} else {
|
|
83
|
+
const ids = Array.isArray(data) ? data : [data];
|
|
84
|
+
links.push(
|
|
85
|
+
...ids
|
|
86
|
+
// filter non-truthy ids
|
|
87
|
+
.filter(id => !!id)
|
|
88
|
+
.map(id => {
|
|
89
|
+
// If id is already an object with the marker type key, return it as is
|
|
90
|
+
if (typeof id === 'object' && id !== null && marker.type in id) {
|
|
91
|
+
return id;
|
|
92
|
+
}
|
|
93
|
+
// Otherwise, wrap it with the marker type key
|
|
94
|
+
return {
|
|
95
|
+
// marker type is either 'test' or 'jira' or 'label'
|
|
96
|
+
[marker.type]: id,
|
|
97
|
+
};
|
|
98
|
+
}),
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
} catch (e) {
|
|
102
|
+
debug('Error parsing links from string:', line, '\n', e);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (!hasMarker && line) {
|
|
107
|
+
newEntryLines.push(line);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (newEntryLines.length) {
|
|
112
|
+
filteredStdout.push(newEntryLines.join('\n'));
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
stdout: filteredStdout,
|
|
118
|
+
links,
|
|
119
|
+
meta,
|
|
120
|
+
};
|
|
121
|
+
}
|
package/src/adapter/vitest.js
CHANGED
|
@@ -101,7 +101,7 @@ class VitestReporter {
|
|
|
101
101
|
*
|
|
102
102
|
* @param {VitestTest} test
|
|
103
103
|
*
|
|
104
|
-
* @returns {TestData & {status:
|
|
104
|
+
* @returns {TestData & {status: 'passed' | 'failed' | 'skipped'}}
|
|
105
105
|
*/
|
|
106
106
|
#getDataFromTest(test) {
|
|
107
107
|
return {
|
|
@@ -109,6 +109,7 @@ class VitestReporter {
|
|
|
109
109
|
file: test.file.name,
|
|
110
110
|
logs: test.logs ? transformLogsToString(test.logs) : '',
|
|
111
111
|
meta: test.meta,
|
|
112
|
+
// @ts-ignore - STATUS values are string literals but type system sees them as string
|
|
112
113
|
status: getTestStatus(test),
|
|
113
114
|
suite_title: test.suite.name || test.file?.name,
|
|
114
115
|
test_id: getTestomatIdFromTestTitle(test.name),
|
package/src/bin/cli.js
CHANGED
|
@@ -6,7 +6,6 @@ import { glob } from 'glob';
|
|
|
6
6
|
import createDebugMessages from 'debug';
|
|
7
7
|
import TestomatClient from '../client.js';
|
|
8
8
|
import XmlReader from '../xmlReader.js';
|
|
9
|
-
import AllureReader from '../allureReader.js';
|
|
10
9
|
import { APP_PREFIX, STATUS } from '../constants.js';
|
|
11
10
|
import { cleanLatestRunId, getPackageVersion, applyFilter } from '../utils/utils.js';
|
|
12
11
|
import { config } from '../config.js';
|
|
@@ -16,7 +15,7 @@ import { filesize as prettyBytes } from 'filesize';
|
|
|
16
15
|
import dotenv from 'dotenv';
|
|
17
16
|
import Replay from '../replay.js';
|
|
18
17
|
|
|
19
|
-
const debug = createDebugMessages('@testomatio/reporter:
|
|
18
|
+
const debug = createDebugMessages('@testomatio/reporter:cli');
|
|
20
19
|
const version = getPackageVersion();
|
|
21
20
|
console.log(pc.cyan(pc.bold(` 🤩 Testomat.io Reporter v${version}`)));
|
|
22
21
|
const program = new Command();
|
|
@@ -80,22 +79,17 @@ program
|
|
|
80
79
|
.command('run')
|
|
81
80
|
.alias('test')
|
|
82
81
|
.description('Run tests with the specified command')
|
|
83
|
-
.argument('
|
|
82
|
+
.argument('[command]', 'Test runner command')
|
|
84
83
|
.option('--filter <filter>', 'Additional execution filter')
|
|
85
84
|
.option('--filter-list <filter>', 'Get a list of all tests by filter before running')
|
|
86
85
|
.option('--kind <type>', 'Specify run type: automated, manual, or mixed')
|
|
87
86
|
.action(async (command, opts) => {
|
|
88
87
|
const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config.TESTOMATIO;
|
|
89
88
|
const title = process.env.TESTOMATIO_TITLE;
|
|
90
|
-
|
|
91
|
-
if (!command || !command.split) {
|
|
92
|
-
console.log(APP_PREFIX, `No command provided. Use -c option to launch a test runner.`);
|
|
93
|
-
return process.exit(255);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
89
|
const client = new TestomatClient({ apiKey, title });
|
|
97
90
|
|
|
98
91
|
if (opts.filter || opts.filterList) {
|
|
92
|
+
console.log(APP_PREFIX,'Filtering tests...');
|
|
99
93
|
// Example of use: npx @testomatio/reporter run "npx jest" --filter "testomatio:tag-name=frontend"
|
|
100
94
|
// Example of use: npx @testomatio/reporter run "npx jest" --filter "coverage:file=coverage.yml"
|
|
101
95
|
// Example of use: npx @testomatio/reporter run "npx jest" --filter-list "coverage:file=coverage.yml"
|
|
@@ -103,6 +97,9 @@ program
|
|
|
103
97
|
const pipeOptions = optsArray.join(':');
|
|
104
98
|
|
|
105
99
|
const prepareRunParams = { pipe, pipeOptions };
|
|
100
|
+
if (opts.filterList) {
|
|
101
|
+
client.pipeStore.filterList = true;
|
|
102
|
+
}
|
|
106
103
|
|
|
107
104
|
try {
|
|
108
105
|
const tests = await client.prepareRun(prepareRunParams);
|
|
@@ -117,19 +114,48 @@ program
|
|
|
117
114
|
|
|
118
115
|
debug(`Execution pattern: "${pattern}"`);
|
|
119
116
|
|
|
120
|
-
if
|
|
117
|
+
if(opts.filterList) {
|
|
121
118
|
console.log(APP_PREFIX, pc.blue(`Matched test/suite IDs: ${tests.join(', ')}`));
|
|
122
|
-
console.log(APP_PREFIX, pc.green(`Full Running Command: ${filteredCommand}`));
|
|
119
|
+
if (command) console.log(APP_PREFIX, pc.green(`Full Running Command: ${filteredCommand}`));
|
|
123
120
|
return;
|
|
124
121
|
}
|
|
125
122
|
|
|
126
|
-
command
|
|
127
|
-
|
|
123
|
+
if (command && command.split) {
|
|
124
|
+
command = filteredCommand;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
128
|
console.log(APP_PREFIX, err.message || err);
|
|
129
129
|
return;
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
// just create a run (wich tests which match filters) without executing tests
|
|
134
|
+
if (!command || !command.split) {
|
|
135
|
+
const createRunParams = {};
|
|
136
|
+
if (title) {
|
|
137
|
+
createRunParams.title = title;
|
|
138
|
+
}
|
|
139
|
+
if (opts.kind) {
|
|
140
|
+
createRunParams.kind = opts.kind;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (apiKey) {
|
|
144
|
+
await client.createRun(createRunParams);
|
|
145
|
+
const runId = process.env.TESTOMATIO_RUN || process.env.runId;
|
|
146
|
+
if (client.pipeStore.runUrl) console.log(APP_PREFIX, `📊 Report URL: ${pc.magenta(client.pipeStore.runUrl)}`);
|
|
147
|
+
|
|
148
|
+
if (opts.kind !== 'manual') {
|
|
149
|
+
console.log(APP_PREFIX, `No command passed, so you need to run tests yourself:`);
|
|
150
|
+
console.log(APP_PREFIX, `TESTOMATIO_RUN=${runId} <command>`);
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
console.log(APP_PREFIX, '⚠️ No API key provided. Cannot create run without TESTOMATIO key.');
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
return process.exit(0);
|
|
157
|
+
}
|
|
158
|
+
|
|
133
159
|
console.log(APP_PREFIX, `🚀 Running`, pc.green(command));
|
|
134
160
|
|
|
135
161
|
const runTests = async () => {
|
|
@@ -237,40 +263,6 @@ program
|
|
|
237
263
|
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
238
264
|
});
|
|
239
265
|
|
|
240
|
-
program
|
|
241
|
-
.command('allure')
|
|
242
|
-
.description('Parse Allure result files and upload to Testomat.io')
|
|
243
|
-
.argument('<pattern>', 'Allure result directory pattern')
|
|
244
|
-
.option('-d, --dir <dir>', 'Project directory')
|
|
245
|
-
.option('--timelimit <time>', 'default time limit in seconds to kill a stuck process')
|
|
246
|
-
.option('--with-package', 'Keep full package path in file names (default: strip package prefix)')
|
|
247
|
-
.action(async (pattern, opts) => {
|
|
248
|
-
const runReader = new AllureReader({ withPackage: opts.withPackage });
|
|
249
|
-
|
|
250
|
-
let timeoutTimer;
|
|
251
|
-
if (opts.timelimit) {
|
|
252
|
-
timeoutTimer = setTimeout(
|
|
253
|
-
() => {
|
|
254
|
-
console.log(
|
|
255
|
-
`⚠️ Reached timeout of ${opts.timelimit}s. Exiting... (Exit code is 0 to not fail the pipeline)`,
|
|
256
|
-
);
|
|
257
|
-
process.exit(0);
|
|
258
|
-
},
|
|
259
|
-
parseInt(opts.timelimit, 10) * 1000,
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
try {
|
|
264
|
-
await runReader.parse(pattern);
|
|
265
|
-
await runReader.createRun();
|
|
266
|
-
await runReader.uploadData();
|
|
267
|
-
} catch (err) {
|
|
268
|
-
console.log(APP_PREFIX, 'Error uploading Allure results:', err);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
272
|
-
});
|
|
273
|
-
|
|
274
266
|
program
|
|
275
267
|
.command('upload-artifacts')
|
|
276
268
|
.description('Upload artifacts to Testomat.io')
|
package/src/data-storage.js
CHANGED
|
@@ -139,6 +139,7 @@ class DataStorage {
|
|
|
139
139
|
const testDataAsText = fs.readFileSync(filepath, 'utf-8');
|
|
140
140
|
if (testDataAsText) debug('<=', dataType, 'file', context, testDataAsText);
|
|
141
141
|
const testDataArr = testDataAsText?.split(os.EOL) || [];
|
|
142
|
+
debug('<=', dataType, 'file', context, testDataArr);
|
|
142
143
|
return testDataArr;
|
|
143
144
|
}
|
|
144
145
|
// debug(`No ${this.dataType} data for ${context} in <file> storage`);
|
|
@@ -4,7 +4,6 @@ import JavaAdapter from './java.js';
|
|
|
4
4
|
import PythonAdapter from './python.js';
|
|
5
5
|
import RubyAdapter from './ruby.js';
|
|
6
6
|
import CSharpAdapter from './csharp.js';
|
|
7
|
-
import KotlinAdapter from './kotlin.js';
|
|
8
7
|
|
|
9
8
|
function AdapterFactory(lang, opts) {
|
|
10
9
|
if (lang === 'java') {
|
|
@@ -22,9 +21,6 @@ function AdapterFactory(lang, opts) {
|
|
|
22
21
|
if (lang === 'c#' || lang === 'csharp') {
|
|
23
22
|
return new CSharpAdapter(opts);
|
|
24
23
|
}
|
|
25
|
-
if (lang === 'kotlin') {
|
|
26
|
-
return new KotlinAdapter(opts);
|
|
27
|
-
}
|
|
28
24
|
|
|
29
25
|
return new Adapter(opts);
|
|
30
26
|
}
|