@testomatio/reporter 2.3.7-beta.1-xml-import → 2.3.7-beta.100
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/lib/adapter/codecept.js +22 -2
- package/lib/bin/cli.js +13 -3
- package/lib/bin/reportXml.js +1 -4
- package/lib/bin/startTest.js +3 -3
- package/lib/bin/uploadArtifacts.js +0 -0
- package/lib/client.d.ts +1 -1
- package/lib/client.js +32 -23
- package/lib/junit-adapter/csharp.d.ts +1 -0
- package/lib/junit-adapter/csharp.js +7 -36
- package/lib/pipe/debug.js +1 -1
- package/lib/pipe/testomatio.d.ts +2 -1
- package/lib/pipe/testomatio.js +17 -21
- package/lib/reporter.d.ts +19 -9
- package/lib/reporter.js +40 -5
- package/lib/template/testomatio.hbs +1366 -1026
- package/lib/uploader.js +0 -4
- package/lib/utils/utils.d.ts +1 -0
- package/lib/utils/utils.js +23 -35
- package/lib/xmlReader.d.ts +26 -11
- package/lib/xmlReader.js +1 -50
- package/package.json +8 -4
- package/src/adapter/codecept.js +27 -3
- package/src/bin/cli.js +1 -1
- package/src/bin/reportXml.js +1 -1
- package/src/bin/startTest.js +5 -5
- package/src/client.js +55 -27
- package/src/junit-adapter/csharp.js +11 -6
- package/src/junit-adapter/nunit-parser.js +83 -12
- package/src/pipe/debug.js +3 -2
- package/src/pipe/testomatio.js +81 -77
- package/src/reporter.js +7 -4
- package/src/template/testomatio.hbs +1366 -1026
- package/src/utils/utils.js +205 -32
- package/src/xmlReader.js +70 -45
- package/types/types.d.ts +364 -0
- package/types/vitest.types.d.ts +93 -0
- package/lib/junit-adapter/nunit-parser.d.ts +0 -82
- package/lib/junit-adapter/nunit-parser.js +0 -357
package/lib/adapter/codecept.js
CHANGED
|
@@ -110,6 +110,25 @@ function CodeceptReporter(config) {
|
|
|
110
110
|
output.stepShift = 2;
|
|
111
111
|
index_js_1.services.setContext(null);
|
|
112
112
|
});
|
|
113
|
+
// mark as failed all tests inside the failed hook
|
|
114
|
+
event.dispatcher.on(event.hook.failed, hook => {
|
|
115
|
+
if (hook.name !== 'BeforeSuiteHook')
|
|
116
|
+
return;
|
|
117
|
+
const suite = hook.runnable.parent;
|
|
118
|
+
if (!suite)
|
|
119
|
+
return;
|
|
120
|
+
const error = hook?.ctx?.currentTest?.err;
|
|
121
|
+
for (const test of suite.tests) {
|
|
122
|
+
client.addTestRun('failed', {
|
|
123
|
+
...stripExampleFromTitle(test.title),
|
|
124
|
+
rid: test.uid,
|
|
125
|
+
test_id: (0, utils_js_1.getTestomatIdFromTestTitle)(test.title),
|
|
126
|
+
suite_title: stripTagsFromTitle(suite.title),
|
|
127
|
+
error,
|
|
128
|
+
time: hook?.runnable?.duration,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
});
|
|
113
132
|
event.dispatcher.on(event.suite.before, suite => {
|
|
114
133
|
data_storage_js_1.dataStorage.setContext(suite.fullTitle());
|
|
115
134
|
});
|
|
@@ -379,7 +398,7 @@ function formatCodeceptStep(step) {
|
|
|
379
398
|
if (!step)
|
|
380
399
|
return null;
|
|
381
400
|
const category = step.constructor.name === 'HelperStep' ? 'framework' : 'user';
|
|
382
|
-
const title =
|
|
401
|
+
const title = (0, utils_js_1.truncate)(step); // Use built-in toString
|
|
383
402
|
const duration = step.duration || 0; // Use built-in duration
|
|
384
403
|
const formattedStep = {
|
|
385
404
|
category,
|
|
@@ -403,10 +422,11 @@ function formatHookStep(step) {
|
|
|
403
422
|
if (step.actor && step.name) {
|
|
404
423
|
title = `${step.actor} ${step.name}`;
|
|
405
424
|
if (step.args && step.args.length > 0) {
|
|
406
|
-
const argsStr = step.args.map(arg => JSON.stringify(arg)).join(', ');
|
|
425
|
+
const argsStr = step.args.map(arg => (0, utils_js_1.truncate)(JSON.stringify(arg))).join(', ');
|
|
407
426
|
title += ` ${argsStr}`;
|
|
408
427
|
}
|
|
409
428
|
}
|
|
429
|
+
title = (0, utils_js_1.truncate)(title);
|
|
410
430
|
return {
|
|
411
431
|
category: 'hook',
|
|
412
432
|
title,
|
package/lib/bin/cli.js
CHANGED
|
@@ -37,12 +37,17 @@ program
|
|
|
37
37
|
program
|
|
38
38
|
.command('start')
|
|
39
39
|
.description('Start a new run and return its ID')
|
|
40
|
-
.
|
|
40
|
+
.option('--kind <type>', 'Specify run type: automated, manual, or mixed')
|
|
41
|
+
.action(async (opts) => {
|
|
41
42
|
(0, utils_js_1.cleanLatestRunId)();
|
|
42
43
|
console.log('Starting a new Run on Testomat.io...');
|
|
43
44
|
const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config_js_1.config.TESTOMATIO;
|
|
44
45
|
const client = new client_js_1.default({ apiKey });
|
|
45
|
-
|
|
46
|
+
const createRunParams = {};
|
|
47
|
+
if (opts.kind) {
|
|
48
|
+
createRunParams.kind = opts.kind;
|
|
49
|
+
}
|
|
50
|
+
client.createRun(createRunParams).then(() => {
|
|
46
51
|
console.log(process.env.runId);
|
|
47
52
|
process.exit(0);
|
|
48
53
|
});
|
|
@@ -70,6 +75,7 @@ program
|
|
|
70
75
|
.description('Run tests with the specified command')
|
|
71
76
|
.argument('<command>', 'Test runner command')
|
|
72
77
|
.option('--filter <filter>', 'Additional execution filter')
|
|
78
|
+
.option('--kind <type>', 'Specify run type: automated, manual, or mixed')
|
|
73
79
|
.action(async (command, opts) => {
|
|
74
80
|
const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config_js_1.config.TESTOMATIO;
|
|
75
81
|
const title = process.env.TESTOMATIO_TITLE;
|
|
@@ -108,8 +114,12 @@ program
|
|
|
108
114
|
process.exit(code);
|
|
109
115
|
});
|
|
110
116
|
};
|
|
117
|
+
const createRunParams = {};
|
|
118
|
+
if (opts.kind) {
|
|
119
|
+
createRunParams.kind = opts.kind;
|
|
120
|
+
}
|
|
111
121
|
if (apiKey) {
|
|
112
|
-
await client.createRun().then(runTests);
|
|
122
|
+
await client.createRun(createRunParams).then(runTests);
|
|
113
123
|
}
|
|
114
124
|
else {
|
|
115
125
|
await runTests();
|
package/lib/bin/reportXml.js
CHANGED
|
@@ -37,10 +37,7 @@ program
|
|
|
37
37
|
lang = lang?.toLowerCase();
|
|
38
38
|
if (javaTests === true || (lang === 'java' && !javaTests))
|
|
39
39
|
javaTests = 'src/test/java';
|
|
40
|
-
const runReader = new xmlReader_js_1.default({
|
|
41
|
-
javaTests,
|
|
42
|
-
lang,
|
|
43
|
-
});
|
|
40
|
+
const runReader = new xmlReader_js_1.default({ javaTests, lang });
|
|
44
41
|
const files = glob_1.glob.sync(pattern, { cwd: opts.dir || process.cwd() });
|
|
45
42
|
if (!files.length) {
|
|
46
43
|
console.log(constants_js_1.APP_PREFIX, `Report can't be created. No XML files found 😥`);
|
package/lib/bin/startTest.js
CHANGED
|
@@ -35,7 +35,7 @@ while (i < args.length) {
|
|
|
35
35
|
newArgs[0] = 'start';
|
|
36
36
|
}
|
|
37
37
|
else if (arg === '--finish') {
|
|
38
|
-
// Map --finish to finish command
|
|
38
|
+
// Map --finish to finish command
|
|
39
39
|
newArgs[0] = 'finish';
|
|
40
40
|
}
|
|
41
41
|
else {
|
|
@@ -46,8 +46,8 @@ while (i < args.length) {
|
|
|
46
46
|
}
|
|
47
47
|
// Execute the main CLI with mapped arguments
|
|
48
48
|
const child = (0, node_child_process_1.spawn)(process.execPath, [cliPath, ...newArgs], {
|
|
49
|
-
stdio: 'inherit'
|
|
49
|
+
stdio: 'inherit',
|
|
50
50
|
});
|
|
51
|
-
child.on('exit',
|
|
51
|
+
child.on('exit', code => {
|
|
52
52
|
process.exit(code);
|
|
53
53
|
});
|
|
File without changes
|
package/lib/client.d.ts
CHANGED
package/lib/client.js
CHANGED
|
@@ -51,7 +51,9 @@ const node_url_1 = require("node:url");
|
|
|
51
51
|
const uploader_js_1 = require("./uploader.js");
|
|
52
52
|
const utils_js_1 = require("./utils/utils.js");
|
|
53
53
|
const filesize_1 = require("filesize");
|
|
54
|
+
const util_1 = require("util");
|
|
54
55
|
const debug = (0, debug_1.default)('@testomatio/reporter:client');
|
|
56
|
+
const stripColors = util_1.stripVTControlCharacters || ((str) => str?.replace(/\x1b\[[0-9;]*m/g, '') || '');
|
|
55
57
|
// removed __dirname usage, because:
|
|
56
58
|
// 1. replaced with ESM syntax (import.meta.url), but it throws an error on tsc compilation;
|
|
57
59
|
// 2. got error "__dirname already defined" in compiles js code (cjs dir)
|
|
@@ -129,7 +131,7 @@ class Client {
|
|
|
129
131
|
*
|
|
130
132
|
* @returns {Promise<any>} - resolves to Run id which should be used to update / add test
|
|
131
133
|
*/
|
|
132
|
-
async createRun(params) {
|
|
134
|
+
async createRun(params = {}) {
|
|
133
135
|
if (!this.pipes || !this.pipes.length)
|
|
134
136
|
this.pipes = await (0, index_js_1.pipesFactory)(params || this.paramsForPipesFactory || {}, this.pipeStore);
|
|
135
137
|
debug('Creating run...');
|
|
@@ -137,7 +139,7 @@ class Client {
|
|
|
137
139
|
if (!this.pipes?.filter(p => p.isEnabled).length)
|
|
138
140
|
return Promise.resolve();
|
|
139
141
|
this.queue = this.queue
|
|
140
|
-
.then(() => Promise.all(this.pipes.map(p => p.createRun())))
|
|
142
|
+
.then(() => Promise.all(this.pipes.map(p => p.createRun(params))))
|
|
141
143
|
.catch(err => console.log(constants_js_1.APP_PREFIX, err))
|
|
142
144
|
.then(() => {
|
|
143
145
|
const runId = this.pipeStore?.runId;
|
|
@@ -158,17 +160,6 @@ class Client {
|
|
|
158
160
|
* @returns {Promise<PipeResult[]>}
|
|
159
161
|
*/
|
|
160
162
|
async addTestRun(status, testData) {
|
|
161
|
-
if (!this.pipes || !this.pipes.length)
|
|
162
|
-
this.pipes = await (0, index_js_1.pipesFactory)(this.paramsForPipesFactory || {}, this.pipeStore);
|
|
163
|
-
// all pipes disabled, skipping
|
|
164
|
-
if (!this.pipes?.filter(p => p.isEnabled).length)
|
|
165
|
-
return [];
|
|
166
|
-
if (isTestShouldBeExculedFromReport(testData))
|
|
167
|
-
return [];
|
|
168
|
-
if (status === constants_js_1.STATUS.SKIPPED && process.env.TESTOMATIO_EXCLUDE_SKIPPED) {
|
|
169
|
-
debug('Skipping test from report', testData?.title);
|
|
170
|
-
return []; // do not log skipped tests
|
|
171
|
-
}
|
|
172
163
|
if (!testData)
|
|
173
164
|
testData = {
|
|
174
165
|
title: 'Unknown test',
|
|
@@ -181,9 +172,12 @@ class Client {
|
|
|
181
172
|
/**
|
|
182
173
|
* @type {TestData}
|
|
183
174
|
*/
|
|
184
|
-
const { rid, error = null,
|
|
175
|
+
const { rid, error = null, steps: originalSteps, title, suite_title, } = testData;
|
|
176
|
+
let steps = originalSteps;
|
|
177
|
+
const uploadedFiles = [];
|
|
178
|
+
const stackArtifactsEnabled = (0, utils_js_1.transformEnvVarToBoolean)(process.env.TESTOMATIO_STACK_ARTIFACTS);
|
|
179
|
+
const { time = 0, example = null, files = [], filesBuffers = [], code = null, file, suite_id, test_id, timestamp, links, manuallyAttachedArtifacts, overwrite, tags, } = testData;
|
|
185
180
|
let { message = '', meta = {} } = testData;
|
|
186
|
-
// stringify meta values and limit keys and values length to 255
|
|
187
181
|
meta = Object.entries(meta)
|
|
188
182
|
.filter(([, value]) => value !== null && value !== undefined)
|
|
189
183
|
.reduce((acc, [key, value]) => {
|
|
@@ -191,19 +185,34 @@ class Client {
|
|
|
191
185
|
acc[key] = value;
|
|
192
186
|
return acc;
|
|
193
187
|
}, {});
|
|
194
|
-
// Get links from storage using the test context
|
|
195
188
|
const testContext = suite_title ? `${suite_title} ${title}` : title;
|
|
196
189
|
let errorFormatted = '';
|
|
197
190
|
if (error) {
|
|
198
191
|
errorFormatted += this.formatError(error) || '';
|
|
199
192
|
message = error?.message;
|
|
200
193
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
194
|
+
let fullLogs = this.formatLogs({ error: errorFormatted, steps, logs: testData.logs });
|
|
195
|
+
if (stackArtifactsEnabled && fullLogs?.trim()?.length > 0) {
|
|
196
|
+
uploadedFiles.push(this.uploader.uploadFileAsBuffer(Buffer.from(stripColors(fullLogs), 'utf8'), [this.runId, rid, `logs_${+new Date}.log`]));
|
|
197
|
+
fullLogs = '';
|
|
198
|
+
steps = null;
|
|
199
|
+
}
|
|
200
|
+
if (!this.pipes || !this.pipes.length)
|
|
201
|
+
this.pipes = await (0, index_js_1.pipesFactory)(this.paramsForPipesFactory || {}, this.pipeStore);
|
|
202
|
+
if (!this.pipes?.filter(p => p.isEnabled).length) {
|
|
203
|
+
if (uploadedFiles.length > 0) {
|
|
204
|
+
await Promise.all(uploadedFiles);
|
|
205
|
+
}
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
if (isTestShouldBeExculedFromReport(testData))
|
|
209
|
+
return [];
|
|
210
|
+
if (status === constants_js_1.STATUS.SKIPPED && process.env.TESTOMATIO_EXCLUDE_SKIPPED) {
|
|
211
|
+
debug('Skipping test from report', testData?.title);
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
204
214
|
if (manuallyAttachedArtifacts?.length)
|
|
205
215
|
files.push(...manuallyAttachedArtifacts);
|
|
206
|
-
const uploadedFiles = [];
|
|
207
216
|
for (let f of files) {
|
|
208
217
|
if (!f)
|
|
209
218
|
continue; // f === null
|
|
@@ -285,7 +294,7 @@ class Client {
|
|
|
285
294
|
const uploadedArtifacts = this.uploader.successfulUploads.map(file => ({
|
|
286
295
|
relativePath: file.path.replace(process.cwd(), ''),
|
|
287
296
|
link: file.link,
|
|
288
|
-
sizePretty: (0, filesize_1.filesize)(file.size, { round: 0 }).toString(),
|
|
297
|
+
sizePretty: file.size == null ? 'unknown' : (0, filesize_1.filesize)(file.size, { round: 0 }).toString(),
|
|
289
298
|
}));
|
|
290
299
|
uploadedArtifacts.forEach(upload => {
|
|
291
300
|
debug(`🟢Uploaded artifact`, `${upload.relativePath},`, 'size:', `${upload.sizePretty},`, 'link:', `${upload.link}`);
|
|
@@ -295,7 +304,7 @@ class Client {
|
|
|
295
304
|
console.log(constants_js_1.APP_PREFIX, `🗄️ ${this.uploader.failedUploads.length} artifacts 🔴${picocolors_1.default.bold('failed')} to upload`);
|
|
296
305
|
const failedUploads = this.uploader.failedUploads.map(file => ({
|
|
297
306
|
relativePath: file.path.replace(process.cwd(), ''),
|
|
298
|
-
sizePretty: (0, filesize_1.filesize)(file.size, { round: 0 }).toString(),
|
|
307
|
+
sizePretty: file.size == null ? 'unknown' : (0, filesize_1.filesize)(file.size, { round: 0 }).toString(),
|
|
299
308
|
}));
|
|
300
309
|
const pathPadding = Math.max(...failedUploads.map(upload => upload.relativePath.length)) + 1;
|
|
301
310
|
failedUploads.forEach(upload => {
|
|
@@ -329,7 +338,7 @@ class Client {
|
|
|
329
338
|
*/
|
|
330
339
|
formatLogs({ error, steps, logs }) {
|
|
331
340
|
error = error?.trim();
|
|
332
|
-
logs = logs?.trim();
|
|
341
|
+
logs = logs?.trim().split('\n').map(l => (0, utils_js_1.truncate)(l)).join('\n');
|
|
333
342
|
if (Array.isArray(steps)) {
|
|
334
343
|
steps = steps
|
|
335
344
|
.map(step => (0, utils_js_1.formatStep)(step))
|
|
@@ -7,53 +7,24 @@ const path_1 = __importDefault(require("path"));
|
|
|
7
7
|
const adapter_js_1 = __importDefault(require("./adapter.js"));
|
|
8
8
|
class CSharpAdapter extends adapter_js_1.default {
|
|
9
9
|
formatTest(t) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
const exampleMatch = t.title.match(/\((.*?)\)/);
|
|
15
|
-
if (exampleMatch) {
|
|
16
|
-
// Keep as array for consistency with NUnit XML processing
|
|
17
|
-
t.example = exampleMatch[1].split(',').map(param => param.trim());
|
|
18
|
-
}
|
|
19
|
-
t.title = title.trim();
|
|
20
|
-
}
|
|
10
|
+
const title = t.title.replace(/\(.*?\)/, '').trim();
|
|
11
|
+
const example = t.title.match(/\((.*?)\)/);
|
|
12
|
+
if (example)
|
|
13
|
+
t.example = { ...example[1].split(',') };
|
|
21
14
|
const suite = t.suite_title.split('.');
|
|
22
15
|
t.suite_title = suite.pop();
|
|
23
16
|
t.file = namespaceToFileName(t.file);
|
|
17
|
+
t.title = title.trim();
|
|
24
18
|
return t;
|
|
25
19
|
}
|
|
26
20
|
getFilePath(t) {
|
|
27
|
-
|
|
28
|
-
return null;
|
|
29
|
-
// Normalize path separators for cross-platform compatibility
|
|
30
|
-
let filePath = t.file.replace(/\\/g, '/');
|
|
31
|
-
// If file already has .cs extension, use it directly
|
|
32
|
-
if (filePath.endsWith('.cs')) {
|
|
33
|
-
// Make relative path if it's absolute
|
|
34
|
-
if (path_1.default.isAbsolute(filePath)) {
|
|
35
|
-
// Try to find project-relative path
|
|
36
|
-
const cwd = process.cwd().replace(/\\/g, '/');
|
|
37
|
-
if (filePath.startsWith(cwd)) {
|
|
38
|
-
filePath = path_1.default.relative(cwd, filePath).replace(/\\/g, '/');
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return filePath;
|
|
42
|
-
}
|
|
43
|
-
// Convert namespace path to file path
|
|
44
|
-
const fileName = namespaceToFileName(filePath);
|
|
21
|
+
const fileName = namespaceToFileName(t.file);
|
|
45
22
|
return fileName;
|
|
46
23
|
}
|
|
47
24
|
}
|
|
48
25
|
module.exports = CSharpAdapter;
|
|
49
26
|
function namespaceToFileName(fileName) {
|
|
50
|
-
if (!fileName)
|
|
51
|
-
return '';
|
|
52
|
-
// If already a .cs file path, clean it up
|
|
53
|
-
if (fileName.endsWith('.cs')) {
|
|
54
|
-
return fileName.replace(/\\/g, '/');
|
|
55
|
-
}
|
|
56
27
|
const fileParts = fileName.split('.');
|
|
57
28
|
fileParts[fileParts.length - 1] = fileParts[fileParts.length - 1]?.replace(/\$.*/, '');
|
|
58
|
-
return `${fileParts.join(
|
|
29
|
+
return `${fileParts.join(path_1.default.sep)}.cs`;
|
|
59
30
|
}
|
package/lib/pipe/debug.js
CHANGED
|
@@ -18,7 +18,7 @@ class DebugPipe {
|
|
|
18
18
|
this.isEnabled = !!process.env.TESTOMATIO_DEBUG || !!process.env.DEBUG;
|
|
19
19
|
if (this.isEnabled) {
|
|
20
20
|
this.batch = {
|
|
21
|
-
isEnabled: this.params.isBatchEnabled ??
|
|
21
|
+
isEnabled: this.params.isBatchEnabled ?? !process.env.TESTOMATIO_DISABLE_BATCH_UPLOAD ?? true,
|
|
22
22
|
intervalFunction: null,
|
|
23
23
|
intervalTime: 5000,
|
|
24
24
|
tests: [],
|
package/lib/pipe/testomatio.d.ts
CHANGED
|
@@ -47,11 +47,12 @@ declare class TestomatioPipe implements Pipe {
|
|
|
47
47
|
prepareRun(opts: any): Promise<string[]>;
|
|
48
48
|
/**
|
|
49
49
|
* Creates a new run on Testomat.io
|
|
50
|
-
* @param {{isBatchEnabled?: boolean}} params
|
|
50
|
+
* @param {{isBatchEnabled?: boolean, kind?: string}} params
|
|
51
51
|
* @returns Promise<void>
|
|
52
52
|
*/
|
|
53
53
|
createRun(params?: {
|
|
54
54
|
isBatchEnabled?: boolean;
|
|
55
|
+
kind?: string;
|
|
55
56
|
}): Promise<void>;
|
|
56
57
|
runUrl: string;
|
|
57
58
|
runPublicUrl: any;
|
package/lib/pipe/testomatio.js
CHANGED
|
@@ -23,7 +23,7 @@ if (process.env.TESTOMATIO_RUN)
|
|
|
23
23
|
class TestomatioPipe {
|
|
24
24
|
constructor(params, store) {
|
|
25
25
|
this.batch = {
|
|
26
|
-
isEnabled: params?.isBatchEnabled ??
|
|
26
|
+
isEnabled: params?.isBatchEnabled ?? !process.env.TESTOMATIO_DISABLE_BATCH_UPLOAD ?? true,
|
|
27
27
|
intervalFunction: null, // will be created in createRun by setInterval function
|
|
28
28
|
intervalTime: 5000, // how often tests are sent
|
|
29
29
|
tests: [], // array of tests in batch
|
|
@@ -60,7 +60,7 @@ class TestomatioPipe {
|
|
|
60
60
|
retry: constants_js_1.REPORTER_REQUEST_RETRIES.retriesPerRequest,
|
|
61
61
|
retryDelay: constants_js_1.REPORTER_REQUEST_RETRIES.retryTimeout,
|
|
62
62
|
httpMethodsToRetry: ['GET', 'PUT', 'HEAD', 'OPTIONS', 'DELETE', 'POST'],
|
|
63
|
-
shouldRetry: error => {
|
|
63
|
+
shouldRetry: (error) => {
|
|
64
64
|
if (!error.response)
|
|
65
65
|
return false;
|
|
66
66
|
switch (error.response?.status) {
|
|
@@ -73,8 +73,8 @@ class TestomatioPipe {
|
|
|
73
73
|
break;
|
|
74
74
|
}
|
|
75
75
|
return error.response?.status >= 401; // Retry on 401+ and 5xx
|
|
76
|
-
}
|
|
77
|
-
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
78
|
});
|
|
79
79
|
this.isEnabled = true;
|
|
80
80
|
// do not finish this run (for parallel testing)
|
|
@@ -148,7 +148,7 @@ class TestomatioPipe {
|
|
|
148
148
|
}
|
|
149
149
|
/**
|
|
150
150
|
* Creates a new run on Testomat.io
|
|
151
|
-
* @param {{isBatchEnabled?: boolean}} params
|
|
151
|
+
* @param {{isBatchEnabled?: boolean, kind?: string}} params
|
|
152
152
|
* @returns Promise<void>
|
|
153
153
|
*/
|
|
154
154
|
async createRun(params = {}) {
|
|
@@ -184,6 +184,7 @@ class TestomatioPipe {
|
|
|
184
184
|
label: this.label,
|
|
185
185
|
shared_run: this.sharedRun,
|
|
186
186
|
shared_run_timeout: this.sharedRunTimeout,
|
|
187
|
+
kind: params.kind,
|
|
187
188
|
}).filter(([, value]) => !!value));
|
|
188
189
|
debug(' >>>>>> Run params', JSON.stringify(runParams, null, 2));
|
|
189
190
|
if (this.runId) {
|
|
@@ -193,7 +194,7 @@ class TestomatioPipe {
|
|
|
193
194
|
method: 'PUT',
|
|
194
195
|
url: `/api/reporter/${this.runId}`,
|
|
195
196
|
data: runParams,
|
|
196
|
-
responseType: 'json'
|
|
197
|
+
responseType: 'json'
|
|
197
198
|
});
|
|
198
199
|
if (resp.data.artifacts)
|
|
199
200
|
(0, pipe_utils_js_1.setS3Credentials)(resp.data.artifacts);
|
|
@@ -206,7 +207,7 @@ class TestomatioPipe {
|
|
|
206
207
|
url: '/api/reporter',
|
|
207
208
|
data: runParams,
|
|
208
209
|
maxContentLength: Infinity,
|
|
209
|
-
responseType: 'json'
|
|
210
|
+
responseType: 'json'
|
|
210
211
|
});
|
|
211
212
|
this.runId = resp.data.uid;
|
|
212
213
|
this.runUrl = `${this.url}/${resp.data.url.split('/').splice(3).join('/')}`;
|
|
@@ -259,17 +260,15 @@ class TestomatioPipe {
|
|
|
259
260
|
this.#formatData(data);
|
|
260
261
|
const json = json_cycle_1.default.stringify(data);
|
|
261
262
|
debug('Adding test', json);
|
|
262
|
-
return this.client
|
|
263
|
-
.request({
|
|
263
|
+
return this.client.request({
|
|
264
264
|
method: 'POST',
|
|
265
265
|
url: `/api/reporter/${this.runId}/testrun`,
|
|
266
266
|
data: json,
|
|
267
267
|
headers: {
|
|
268
268
|
'Content-Type': 'application/json',
|
|
269
269
|
},
|
|
270
|
-
maxContentLength: Infinity
|
|
271
|
-
})
|
|
272
|
-
.catch(err => {
|
|
270
|
+
maxContentLength: Infinity
|
|
271
|
+
}).catch(err => {
|
|
273
272
|
this.requestFailures++;
|
|
274
273
|
this.notReportedTestsCount++;
|
|
275
274
|
if (err.response) {
|
|
@@ -314,21 +313,19 @@ class TestomatioPipe {
|
|
|
314
313
|
// get tests from batch and clear batch
|
|
315
314
|
const testsToSend = this.batch.tests.splice(0);
|
|
316
315
|
debug('📨 Batch upload', testsToSend.length, 'tests');
|
|
317
|
-
return this.client
|
|
318
|
-
.request({
|
|
316
|
+
return this.client.request({
|
|
319
317
|
method: 'POST',
|
|
320
318
|
url: `/api/reporter/${this.runId}/testrun`,
|
|
321
319
|
data: {
|
|
322
320
|
api_key: this.apiKey,
|
|
323
321
|
tests: testsToSend,
|
|
324
|
-
batch_index: this.batch.batchIndex
|
|
322
|
+
batch_index: this.batch.batchIndex
|
|
325
323
|
},
|
|
326
324
|
headers: {
|
|
327
325
|
'Content-Type': 'application/json',
|
|
328
326
|
},
|
|
329
|
-
maxContentLength: Infinity
|
|
330
|
-
})
|
|
331
|
-
.catch(err => {
|
|
327
|
+
maxContentLength: Infinity
|
|
328
|
+
}).catch(err => {
|
|
332
329
|
this.requestFailures++;
|
|
333
330
|
this.notReportedTestsCount += testsToSend.length;
|
|
334
331
|
if (err.response) {
|
|
@@ -412,9 +409,8 @@ class TestomatioPipe {
|
|
|
412
409
|
status_event,
|
|
413
410
|
detach: params.detach,
|
|
414
411
|
tests: params.tests,
|
|
415
|
-
}
|
|
412
|
+
}
|
|
416
413
|
});
|
|
417
|
-
debug(constants_js_1.APP_PREFIX, '✅ Testrun finished');
|
|
418
414
|
if (this.runUrl) {
|
|
419
415
|
console.log(constants_js_1.APP_PREFIX, '📊 Report Saved. Report URL:', picocolors_1.default.magenta(this.runUrl));
|
|
420
416
|
}
|
|
@@ -425,7 +421,7 @@ class TestomatioPipe {
|
|
|
425
421
|
if (this.runUrl && this.proceed) {
|
|
426
422
|
const notFinishedMessage = picocolors_1.default.yellow(picocolors_1.default.bold('Run was not finished because of $TESTOMATIO_PROCEED'));
|
|
427
423
|
console.log(constants_js_1.APP_PREFIX, `📊 ${notFinishedMessage}. Report URL: ${picocolors_1.default.magenta(this.runUrl)}`);
|
|
428
|
-
console.log(constants_js_1.APP_PREFIX, `🛬 Run to finish it: TESTOMATIO_RUN=${this.runId} npx
|
|
424
|
+
console.log(constants_js_1.APP_PREFIX, `🛬 Run to finish it: TESTOMATIO_RUN=${this.runId} npx @testomatio/reporter finish`);
|
|
429
425
|
}
|
|
430
426
|
if (this.hasUnmatchedTests) {
|
|
431
427
|
console.log('');
|
package/lib/reporter.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export { Client };
|
|
2
|
+
export const STATUS: {
|
|
3
|
+
PASSED: string;
|
|
4
|
+
FAILED: string;
|
|
5
|
+
SKIPPED: string;
|
|
6
|
+
FINISHED: string;
|
|
7
|
+
};
|
|
1
8
|
export const artifact: (data: string | {
|
|
2
9
|
path: string;
|
|
3
10
|
type: string;
|
|
@@ -80,7 +87,7 @@ export const label: (key: string, value?: string | null) => void;
|
|
|
80
87
|
export const linkTest: (...testIds: string[]) => void;
|
|
81
88
|
export const linkJira: (...jiraIds: string[]) => void;
|
|
82
89
|
declare namespace _default {
|
|
83
|
-
let testomatioLogger: {
|
|
90
|
+
export let testomatioLogger: {
|
|
84
91
|
"__#13@#originalUserLogger": {
|
|
85
92
|
assert(condition?: boolean, ...data: any[]): void;
|
|
86
93
|
assert(value: any, message?: string, ...optionalParams: any[]): void;
|
|
@@ -148,13 +155,13 @@ declare namespace _default {
|
|
|
148
155
|
}): void;
|
|
149
156
|
prettyObjects: boolean;
|
|
150
157
|
};
|
|
151
|
-
let artifact: (data: string | {
|
|
158
|
+
export let artifact: (data: string | {
|
|
152
159
|
path: string;
|
|
153
160
|
type: string;
|
|
154
161
|
name: string;
|
|
155
162
|
}, context?: any) => void;
|
|
156
|
-
let log: (...args: any[]) => void;
|
|
157
|
-
let logger: {
|
|
163
|
+
export let log: (...args: any[]) => void;
|
|
164
|
+
export let logger: {
|
|
158
165
|
"__#13@#originalUserLogger": {
|
|
159
166
|
assert(condition?: boolean, ...data: any[]): void;
|
|
160
167
|
assert(value: any, message?: string, ...optionalParams: any[]): void;
|
|
@@ -222,13 +229,15 @@ declare namespace _default {
|
|
|
222
229
|
}): void;
|
|
223
230
|
prettyObjects: boolean;
|
|
224
231
|
};
|
|
225
|
-
let meta: (keyValue: {
|
|
232
|
+
export let meta: (keyValue: {
|
|
226
233
|
[key: string]: string;
|
|
227
234
|
} | string, value?: string | null) => void;
|
|
228
|
-
let step: (message: string) => void;
|
|
229
|
-
let label: (key: string, value?: string | null) => void;
|
|
230
|
-
let linkTest: (...testIds: string[]) => void;
|
|
231
|
-
let linkJira: (...jiraIds: string[]) => void;
|
|
235
|
+
export let step: (message: string) => void;
|
|
236
|
+
export let label: (key: string, value?: string | null) => void;
|
|
237
|
+
export let linkTest: (...testIds: string[]) => void;
|
|
238
|
+
export let linkJira: (...jiraIds: string[]) => void;
|
|
239
|
+
export { Client as TestomatioClient };
|
|
240
|
+
export { STATUS };
|
|
232
241
|
}
|
|
233
242
|
export default _default;
|
|
234
243
|
export type ArtifactFunction = typeof import("./reporter-functions.js").default.artifact;
|
|
@@ -237,3 +246,4 @@ export type LoggerService = typeof import("./services/index.js").services.logger
|
|
|
237
246
|
export type MetaFunction = typeof import("./reporter-functions.js").default.keyValue;
|
|
238
247
|
export type StepFunction = typeof import("./reporter-functions.js").default.step;
|
|
239
248
|
export type LabelFunction = typeof import("./reporter-functions.js").default.label;
|
|
249
|
+
import Client from './client.js';
|
package/lib/reporter.js
CHANGED
|
@@ -1,13 +1,48 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
5
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.linkJira = exports.linkTest = exports.label = exports.step = exports.meta = exports.logger = exports.log = exports.artifact = void 0;
|
|
7
|
-
|
|
8
|
-
|
|
39
|
+
exports.linkJira = exports.linkTest = exports.label = exports.step = exports.meta = exports.logger = exports.log = exports.artifact = exports.STATUS = exports.Client = void 0;
|
|
40
|
+
const client_js_1 = __importDefault(require("./client.js"));
|
|
41
|
+
exports.Client = client_js_1.default;
|
|
42
|
+
const TestomatioConstants = __importStar(require("./constants.js"));
|
|
9
43
|
const index_js_1 = require("./services/index.js");
|
|
10
44
|
const reporter_functions_js_1 = __importDefault(require("./reporter-functions.js"));
|
|
45
|
+
exports.STATUS = TestomatioConstants.STATUS;
|
|
11
46
|
exports.artifact = reporter_functions_js_1.default.artifact;
|
|
12
47
|
exports.log = reporter_functions_js_1.default.log;
|
|
13
48
|
exports.logger = index_js_1.services.logger;
|
|
@@ -37,6 +72,6 @@ module.exports = {
|
|
|
37
72
|
label: reporter_functions_js_1.default.label,
|
|
38
73
|
linkTest: reporter_functions_js_1.default.linkTest,
|
|
39
74
|
linkJira: reporter_functions_js_1.default.linkJira,
|
|
40
|
-
|
|
41
|
-
|
|
75
|
+
TestomatioClient: client_js_1.default,
|
|
76
|
+
STATUS: exports.STATUS,
|
|
42
77
|
};
|