@testomatio/reporter 2.3.9 → 2.5.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.
- package/README.md +1 -1
- package/lib/bin/cli.js +26 -7
- package/lib/client.js +18 -10
- package/lib/data-storage.d.ts +1 -1
- package/lib/helpers.d.ts +1 -0
- package/lib/helpers.js +4 -0
- package/lib/pipe/coverage.d.ts +82 -0
- package/lib/pipe/coverage.js +373 -0
- package/lib/pipe/index.js +2 -0
- package/lib/pipe/testomatio.d.ts +1 -1
- package/lib/pipe/testomatio.js +25 -4
- package/lib/reporter-functions.d.ts +7 -1
- package/lib/reporter-functions.js +21 -11
- package/lib/reporter.d.ts +21 -14
- package/lib/services/artifacts.d.ts +1 -1
- package/lib/services/key-values.d.ts +1 -1
- package/lib/services/links.d.ts +1 -1
- package/lib/services/logger.d.ts +3 -3
- package/lib/services/logger.js +36 -33
- package/lib/utils/pipe_utils.d.ts +15 -0
- package/lib/utils/pipe_utils.js +44 -2
- package/lib/utils/utils.d.ts +6 -0
- package/lib/utils/utils.js +71 -1
- package/package.json +5 -4
- package/src/bin/cli.js +35 -9
- package/src/client.js +22 -14
- package/src/helpers.js +1 -0
- package/src/pipe/coverage.js +440 -0
- package/src/pipe/index.js +2 -0
- package/src/pipe/testomatio.js +34 -5
- package/src/reporter-functions.js +20 -11
- package/src/services/logger.js +34 -29
- package/src/utils/pipe_utils.js +52 -3
- package/src/utils/utils.js +75 -0
- package/types/types.d.ts +2 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isPlaywright } from './helpers.js';
|
|
1
2
|
import { services } from './services/index.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -7,9 +8,7 @@ import { services } from './services/index.js';
|
|
|
7
8
|
* @returns {void}
|
|
8
9
|
*/
|
|
9
10
|
function saveArtifact(data, context = null) {
|
|
10
|
-
|
|
11
|
-
throw new Error(`This function is not available in Playwright framework.
|
|
12
|
-
/Playwright supports artifacts out of the box`);
|
|
11
|
+
showPlaywrightWarning('artifact', 'Playwright supports artifacts out of the box.');
|
|
13
12
|
if (!data) return;
|
|
14
13
|
services.artifacts.put(data, context);
|
|
15
14
|
}
|
|
@@ -20,20 +19,24 @@ function saveArtifact(data, context = null) {
|
|
|
20
19
|
* @returns {void}
|
|
21
20
|
*/
|
|
22
21
|
function logMessage(...args) {
|
|
23
|
-
if (process.env.IS_PLAYWRIGHT) throw new Error('This function is not available in Playwright framework');
|
|
24
22
|
services.logger._templateLiteralLog(...args);
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
/**
|
|
28
26
|
* Similar to "log" function but marks message in report as a step
|
|
29
27
|
* @param {string} message - step message
|
|
28
|
+
* @param {{[key: string]: any}} [logs] optional key-value object with additional info, e.g. logs
|
|
30
29
|
* @returns {void}
|
|
30
|
+
*
|
|
31
|
+
* Example:
|
|
32
|
+
* step('Get response', { logs: {status: 'success'} });
|
|
31
33
|
*/
|
|
32
|
-
function addStep(message) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
function addStep(message, logs) {
|
|
35
|
+
// this is done because Playwright reporter intercepts console logs and then we gather them and show on Testomat
|
|
36
|
+
// if not console.log, the step message will be lost from reporter
|
|
37
|
+
if (isPlaywright) services.logger._templateLiteralLog(message, logs);
|
|
38
|
+
// all other frameworks
|
|
39
|
+
else services.logger.step(message, logs);
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
/**
|
|
@@ -43,8 +46,7 @@ function addStep(message) {
|
|
|
43
46
|
* @returns {void}
|
|
44
47
|
*/
|
|
45
48
|
function setKeyValue(keyValue, value = null) {
|
|
46
|
-
|
|
47
|
-
throw new Error('This function is not available in Playwright framework. Use test tag instead.');
|
|
49
|
+
showPlaywrightWarning('meta', 'Use test annotations instead.');
|
|
48
50
|
|
|
49
51
|
if (typeof keyValue === 'string') {
|
|
50
52
|
keyValue = { [keyValue]: value };
|
|
@@ -59,6 +61,7 @@ function setKeyValue(keyValue, value = null) {
|
|
|
59
61
|
* @returns {void}
|
|
60
62
|
*/
|
|
61
63
|
function setLabel(key, value = null) {
|
|
64
|
+
showPlaywrightWarning('label', 'Use test tag instead.');
|
|
62
65
|
if (Array.isArray(value)) {
|
|
63
66
|
return value.forEach(label => setLabel(key, label));
|
|
64
67
|
}
|
|
@@ -87,6 +90,12 @@ function linkJira(...jiraIds) {
|
|
|
87
90
|
services.links.put(links);
|
|
88
91
|
}
|
|
89
92
|
|
|
93
|
+
function showPlaywrightWarning(functionName, recommendation) {
|
|
94
|
+
if (isPlaywright) {
|
|
95
|
+
console.warn(`[TESTOMATIO] '${functionName}' function is not supported for Playwright. ${recommendation}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
90
99
|
export default {
|
|
91
100
|
artifact: saveArtifact,
|
|
92
101
|
log: logMessage,
|
package/src/services/logger.js
CHANGED
|
@@ -59,14 +59,10 @@ class Logger {
|
|
|
59
59
|
* @param {...any} values
|
|
60
60
|
*/
|
|
61
61
|
step(strings, ...values) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
logs += values[i];
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
logs = pc.blue(`> ${logs}`);
|
|
62
|
+
// Filter trailing undefined from optional params (e.g., step('message') called without second arg)
|
|
63
|
+
const filteredValues = values.filter(v => v !== undefined);
|
|
64
|
+
const message = this.#formatMessage(strings, ...filteredValues);
|
|
65
|
+
const logs = pc.blue(`> ${message}`);
|
|
70
66
|
dataStorage.putData('log', logs);
|
|
71
67
|
}
|
|
72
68
|
|
|
@@ -87,7 +83,11 @@ class Logger {
|
|
|
87
83
|
for (const arg of args) {
|
|
88
84
|
// ignore empty strings
|
|
89
85
|
if (arg === '') continue;
|
|
90
|
-
if (
|
|
86
|
+
if (arg === undefined) {
|
|
87
|
+
logs.push('undefined');
|
|
88
|
+
} else if (arg === null) {
|
|
89
|
+
logs.push('null');
|
|
90
|
+
} else if (typeof arg === 'string') {
|
|
91
91
|
logs.push(arg);
|
|
92
92
|
} else if (Array.isArray(arg)) {
|
|
93
93
|
logs.push(arg.join(' '));
|
|
@@ -104,37 +104,42 @@ class Logger {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
107
|
+
* Formats a message from either tagged template literal or standard function call.
|
|
108
|
+
* @param {*} strings - Template strings array or first argument
|
|
109
|
+
* @param {...any} args - Template values or additional arguments
|
|
110
|
+
* @returns {string} Formatted message
|
|
111
111
|
*/
|
|
112
|
-
|
|
113
|
-
if (Array.isArray(strings)) strings = strings.filter(item => item !== '').map(item => item.trim());
|
|
112
|
+
#formatMessage(strings, ...args) {
|
|
114
113
|
if (Array.isArray(args)) args = args.filter(item => item !== '');
|
|
115
114
|
|
|
116
|
-
|
|
117
|
-
// this block means tagged template is used (syntax like $`text ${someVar}`)
|
|
115
|
+
// Tagged template syntax: func`text ${someVar}`
|
|
118
116
|
if (Array.isArray(strings) && strings.length === args.length + 1) {
|
|
119
|
-
|
|
117
|
+
return strings.reduce(
|
|
120
118
|
(result, current, index) =>
|
|
121
119
|
result +
|
|
122
120
|
current +
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
121
|
+
(index < args.length
|
|
122
|
+
? args[index] === undefined
|
|
123
|
+
? 'undefined'
|
|
124
|
+
: typeof args[index] === 'string'
|
|
125
|
+
? args[index]
|
|
126
|
+
: this.#stringifyLogs(args[index])
|
|
129
127
|
: ''),
|
|
130
|
-
// initial accumulator value
|
|
131
128
|
'',
|
|
132
129
|
);
|
|
133
|
-
} else {
|
|
134
|
-
// this block means arguments syntax is used (syntax like $('text', someVar))
|
|
135
|
-
// in this case strings represents just a first argument
|
|
136
|
-
logs = this.#stringifyLogs(strings, ...args);
|
|
137
130
|
}
|
|
131
|
+
// Standard function call: func('text', someVar)
|
|
132
|
+
return this.#stringifyLogs(strings, ...args);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Tagged template literal. Allows to use different syntaxes:
|
|
137
|
+
* 1. Tagged template: log`text ${someVar}`
|
|
138
|
+
* 2. Standard: log(`text ${someVar}`)
|
|
139
|
+
* 3. Standard with multiple arguments: log('text', someVar)
|
|
140
|
+
*/
|
|
141
|
+
_templateLiteralLog(strings, ...args) {
|
|
142
|
+
const logs = this.#formatMessage(strings, ...args);
|
|
138
143
|
this.#originalUserLogger.log(logs);
|
|
139
144
|
dataStorage.putData('log', logs);
|
|
140
145
|
}
|
package/src/utils/pipe_utils.js
CHANGED
|
@@ -15,6 +15,7 @@ function setS3Credentials(artifacts) {
|
|
|
15
15
|
if (artifacts.BUCKET) process.env.S3_BUCKET = artifacts.BUCKET;
|
|
16
16
|
if (artifacts.SESSION_TOKEN) process.env.S3_SESSION_TOKEN = artifacts.SESSION_TOKEN;
|
|
17
17
|
if (artifacts.presign) process.env.TESTOMATIO_PRIVATE_ARTIFACTS = '1';
|
|
18
|
+
if (artifacts.stack_artifacts) process.env.TESTOMATIO_STACK_ARTIFACTS = '1';
|
|
18
19
|
// endpoint is not received from the server; and shuld be empty if IAM used (credentails obtained from the testomat)
|
|
19
20
|
process.env.S3_ENDPOINT = artifacts.ENDPOINT || '';
|
|
20
21
|
}
|
|
@@ -25,6 +26,12 @@ function setS3Credentials(artifacts) {
|
|
|
25
26
|
* @returns {Object|null} - An object containing the generated request parameters, or null if the type is invalid.
|
|
26
27
|
*/
|
|
27
28
|
function generateFilterRequestParams(params) {
|
|
29
|
+
// Defensive check: ensure params is an object
|
|
30
|
+
if (!params || typeof params !== 'object') {
|
|
31
|
+
console.error(APP_PREFIX, `Invalid parameters provided. Expected an object, got: ${typeof params}`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
28
35
|
const { type, id, apiKey } = params;
|
|
29
36
|
|
|
30
37
|
if (!type) {
|
|
@@ -53,9 +60,13 @@ function generateFilterRequestParams(params) {
|
|
|
53
60
|
* The object has properties "type" and "id".
|
|
54
61
|
*/
|
|
55
62
|
function parseFilterParams(opts) {
|
|
56
|
-
const [type,
|
|
63
|
+
const [type, ...idParts] = opts.split('=');
|
|
64
|
+
const id = idParts.join('=');
|
|
65
|
+
|
|
57
66
|
const validType = updateFilterType(type);
|
|
58
67
|
|
|
68
|
+
if (!validType) return undefined;
|
|
69
|
+
|
|
59
70
|
return {
|
|
60
71
|
type: validType,
|
|
61
72
|
id,
|
|
@@ -69,6 +80,8 @@ function parseFilterParams(opts) {
|
|
|
69
80
|
* Returns undefined if the type is not valid.
|
|
70
81
|
*/
|
|
71
82
|
function updateFilterType(type) {
|
|
83
|
+
if (!type || typeof type !== 'string') return;
|
|
84
|
+
|
|
72
85
|
let typeLowerCase = type.toLowerCase();
|
|
73
86
|
|
|
74
87
|
const filterTypes = ['tag-name', 'plan', 'label', 'jira-ticket'];
|
|
@@ -86,7 +99,7 @@ function updateFilterType(type) {
|
|
|
86
99
|
];
|
|
87
100
|
|
|
88
101
|
if (!filterTypes.includes(typeLowerCase)) {
|
|
89
|
-
console.log(APP_PREFIX, `❗❗❗ Invalid "
|
|
102
|
+
console.log(APP_PREFIX, `❗❗❗ Invalid filter: "${type}" start settings! Available option list: ${filterTypes}`);
|
|
90
103
|
return;
|
|
91
104
|
}
|
|
92
105
|
|
|
@@ -120,4 +133,40 @@ function fullName(t) {
|
|
|
120
133
|
return line;
|
|
121
134
|
}
|
|
122
135
|
|
|
123
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Parses a comma-separated list of key-value pairs into an options object.
|
|
138
|
+
*
|
|
139
|
+
* The input string should be formatted as `"key1=value1,key2=value2,..."`.
|
|
140
|
+
* Whitespace around keys and values is trimmed. If the input is empty or undefined,
|
|
141
|
+
* an empty object is returned.
|
|
142
|
+
*
|
|
143
|
+
* @param {string} [optionsStr] - A comma-separated string of key=value pairs.
|
|
144
|
+
* @returns {Object} An object mapping option keys to their string values.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* parsePipeOptions('foo=bar,baz=qux');
|
|
148
|
+
* => Returns: { foo: 'bar', baz: 'qux' }
|
|
149
|
+
*/
|
|
150
|
+
function parsePipeOptions(optionsStr) {
|
|
151
|
+
const options = {};
|
|
152
|
+
if (!optionsStr) return options;
|
|
153
|
+
|
|
154
|
+
const pairs = optionsStr.split(',');
|
|
155
|
+
for (const pair of pairs) {
|
|
156
|
+
const [key, value] = pair.split('=');
|
|
157
|
+
if (key && value) {
|
|
158
|
+
options[key.trim()] = value.trim();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return options;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export {
|
|
165
|
+
updateFilterType,
|
|
166
|
+
parseFilterParams,
|
|
167
|
+
generateFilterRequestParams,
|
|
168
|
+
setS3Credentials,
|
|
169
|
+
statusEmoji,
|
|
170
|
+
fullName,
|
|
171
|
+
parsePipeOptions
|
|
172
|
+
};
|
package/src/utils/utils.js
CHANGED
|
@@ -6,6 +6,7 @@ import isValid from 'is-valid-path';
|
|
|
6
6
|
import createDebugMessages from 'debug';
|
|
7
7
|
import os from 'os';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
+
import { execSync } from 'child_process';
|
|
9
10
|
|
|
10
11
|
const debug = createDebugMessages('@testomatio/reporter:util');
|
|
11
12
|
|
|
@@ -58,6 +59,21 @@ const validateSuiteId = suiteId => {
|
|
|
58
59
|
return match ? match[0] : null;
|
|
59
60
|
};
|
|
60
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Gets current git commit SHA
|
|
64
|
+
* @returns {String|null} git commit SHA or null if not available
|
|
65
|
+
*/
|
|
66
|
+
const getGitCommitSha = () => {
|
|
67
|
+
try {
|
|
68
|
+
const sha = execSync('git rev-parse --short HEAD', {
|
|
69
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
70
|
+
}).toString().trim();
|
|
71
|
+
return sha || null;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
61
77
|
const ansiRegExp = () => {
|
|
62
78
|
const pattern = [
|
|
63
79
|
'[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
|
|
@@ -615,6 +631,63 @@ function truncate(s, size = 255) {
|
|
|
615
631
|
return `${str.substring(0, size)}...`;
|
|
616
632
|
}
|
|
617
633
|
|
|
634
|
+
function applyFilter(command, tests) {
|
|
635
|
+
if (!tests || !tests.length) return command;
|
|
636
|
+
|
|
637
|
+
const lower = (command || '').toLowerCase();
|
|
638
|
+
const regexPattern = `(${tests.join('|')})`;
|
|
639
|
+
|
|
640
|
+
if (lower.includes('jest')) {
|
|
641
|
+
return `${command} --testNamePattern ${regexPattern}`;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (lower.includes('cypress')) {
|
|
645
|
+
const grepValue = tests.join(',');
|
|
646
|
+
const baseEnv = {
|
|
647
|
+
grep: grepValue,
|
|
648
|
+
grepFilterSpecs: true,
|
|
649
|
+
grepOmitFiltered: true,
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
if (command.includes('--env')) {
|
|
653
|
+
return command.replace(
|
|
654
|
+
/--env\s+(['"]?)([^\s'"]+)\1/,
|
|
655
|
+
(match, quote, envVal) => {
|
|
656
|
+
const existingEnv = {};
|
|
657
|
+
|
|
658
|
+
if (envVal.startsWith('{') && envVal.endsWith('}')) {
|
|
659
|
+
try {
|
|
660
|
+
Object.assign(existingEnv, JSON.parse(envVal));
|
|
661
|
+
} catch (e) {
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
if (!Object.keys(existingEnv).length) {
|
|
666
|
+
envVal.split(',').forEach((pair) => {
|
|
667
|
+
const [k, v] = pair.split('=');
|
|
668
|
+
if (!k) return;
|
|
669
|
+
|
|
670
|
+
if (v === 'true') existingEnv[k] = true;
|
|
671
|
+
else if (v === 'false') existingEnv[k] = false;
|
|
672
|
+
else existingEnv[k] = v;
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
const merged = { ...existingEnv, ...baseEnv };
|
|
677
|
+
const json = JSON.stringify(merged);
|
|
678
|
+
|
|
679
|
+
return `--env ${json}`;
|
|
680
|
+
},
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
const json = JSON.stringify(baseEnv);
|
|
685
|
+
return `${command} --env ${json}`;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
return `${command} --grep ${regexPattern}`;
|
|
689
|
+
}
|
|
690
|
+
|
|
618
691
|
export {
|
|
619
692
|
ansiRegExp,
|
|
620
693
|
truncate,
|
|
@@ -629,6 +702,7 @@ export {
|
|
|
629
702
|
foundedTestLog,
|
|
630
703
|
formatStep,
|
|
631
704
|
getCurrentDateTime,
|
|
705
|
+
getGitCommitSha,
|
|
632
706
|
getTestomatIdFromTestTitle,
|
|
633
707
|
humanize,
|
|
634
708
|
isValidUrl,
|
|
@@ -640,4 +714,5 @@ export {
|
|
|
640
714
|
testRunnerHelper,
|
|
641
715
|
transformEnvVarToBoolean,
|
|
642
716
|
validateSuiteId,
|
|
717
|
+
applyFilter
|
|
643
718
|
};
|
package/types/types.d.ts
CHANGED
|
@@ -15,8 +15,9 @@ declare module '@testomatio/reporter' {
|
|
|
15
15
|
/**
|
|
16
16
|
* Similar to "log" function but marks message in report as a step
|
|
17
17
|
* @param message - step message
|
|
18
|
+
* @param logs - optional key-value object with additional info (e.g. logs)
|
|
18
19
|
*/
|
|
19
|
-
export function step(message: string): void;
|
|
20
|
+
export function step(message: string, logs?: {[key: string]: any}): void;
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Add key-value pair(s) to the test report
|