@testomatio/reporter 2.8.1 → 2.8.3
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/bin/cli.js +22 -12
- package/lib/pipe/coverage.js +4 -4
- package/lib/utils/log.js +2 -1
- package/lib/utils/pipe_utils.d.ts +10 -0
- package/lib/utils/pipe_utils.js +23 -0
- package/package.json +1 -1
- package/src/bin/cli.js +22 -14
- package/src/pipe/coverage.js +4 -9
- package/src/utils/log.js +2 -1
- package/src/utils/pipe_utils.js +28 -7
package/lib/bin/cli.js
CHANGED
|
@@ -19,14 +19,14 @@ const filesize_1 = require("filesize");
|
|
|
19
19
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
20
20
|
const replay_js_1 = __importDefault(require("../replay.js"));
|
|
21
21
|
const log_js_1 = require("../utils/log.js");
|
|
22
|
+
const pipe_utils_js_1 = require("../utils/pipe_utils.js");
|
|
22
23
|
const debug = (0, debug_1.default)('@testomatio/reporter:cli');
|
|
23
24
|
const version = (0, utils_js_1.getPackageVersion)();
|
|
24
|
-
console.log(picocolors_1.default.cyan(picocolors_1.default.bold(` 🤩 Testomat.io Reporter v${version}`)));
|
|
25
25
|
const program = new commander_1.Command();
|
|
26
26
|
program
|
|
27
27
|
.version(version)
|
|
28
28
|
.option('--env-file <envfile>', 'Load environment variables from env file')
|
|
29
|
-
.hook('preAction', thisCommand => {
|
|
29
|
+
.hook('preAction', (thisCommand, actionCommand) => {
|
|
30
30
|
const opts = thisCommand.opts();
|
|
31
31
|
if (opts.envFile) {
|
|
32
32
|
dotenv_1.default.config({ path: opts.envFile });
|
|
@@ -34,6 +34,15 @@ program
|
|
|
34
34
|
else {
|
|
35
35
|
dotenv_1.default.config();
|
|
36
36
|
}
|
|
37
|
+
// --filter-list produces a machine-readable test list on stdout, so route
|
|
38
|
+
// logs to stderr and skip the banner to keep stdout clean for piping.
|
|
39
|
+
const subOpts = actionCommand.opts();
|
|
40
|
+
if (subOpts.filterList || subOpts.format) {
|
|
41
|
+
process.env.TESTOMATIO_LOG_STDERR = '1';
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.log(picocolors_1.default.cyan(picocolors_1.default.bold(` 🤩 Testomat.io Reporter v${version}`)));
|
|
45
|
+
}
|
|
37
46
|
});
|
|
38
47
|
program
|
|
39
48
|
.command('start')
|
|
@@ -77,6 +86,7 @@ program
|
|
|
77
86
|
.argument('[command]', 'Test runner command')
|
|
78
87
|
.option('--filter <filter>', 'Additional execution filter')
|
|
79
88
|
.option('--filter-list <filter>', 'Get a list of all tests by filter before running')
|
|
89
|
+
.option('--format <format>', 'Machine-readable output format for --filter-list (grep, json, newline, ids)')
|
|
80
90
|
.option('--kind <type>', 'Specify run type: automated, manual, or mixed')
|
|
81
91
|
.action(async (command, opts) => {
|
|
82
92
|
const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config_js_1.config.TESTOMATIO;
|
|
@@ -86,7 +96,7 @@ program
|
|
|
86
96
|
log_js_1.log.info('Filtering tests...');
|
|
87
97
|
// Example of use: npx @testomatio/reporter run "npx jest" --filter "testomatio:tag-name=frontend"
|
|
88
98
|
// Example of use: npx @testomatio/reporter run "npx jest" --filter "coverage:file=coverage.yml"
|
|
89
|
-
// Example of use: npx @testomatio/reporter run
|
|
99
|
+
// Example of use: npx @testomatio/reporter run --filter-list "coverage:file=coverage.yml" --format grep
|
|
90
100
|
const [pipe, ...optsArray] = opts?.filter ? opts?.filter.split(':') : opts?.filterList.split(':');
|
|
91
101
|
const pipeOptions = optsArray.join(':');
|
|
92
102
|
const prepareRunParams = { pipe, pipeOptions };
|
|
@@ -99,19 +109,19 @@ program
|
|
|
99
109
|
log_js_1.log.info(picocolors_1.default.yellow('No tests found.'));
|
|
100
110
|
return;
|
|
101
111
|
}
|
|
102
|
-
const pattern = `(${tests.join('|')})`;
|
|
103
|
-
const filteredCommand = (0, utils_js_1.applyFilter)(command, tests);
|
|
104
|
-
debug(`Execution pattern: "${pattern}"`);
|
|
105
112
|
if (opts.filterList) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
const out = (0, pipe_utils_js_1.formatFilterListIds)(tests, opts.format || 'ids');
|
|
114
|
+
if (out)
|
|
115
|
+
console.log(out);
|
|
116
|
+
// Show the runnable-command hint only in interactive mode (no explicit --format).
|
|
117
|
+
// When --format is set the user is scripting and doesn't need stderr noise.
|
|
118
|
+
if (command && !opts.format) {
|
|
119
|
+
log_js_1.log.info(picocolors_1.default.green(`Full Running Command: ${(0, utils_js_1.applyFilter)(command, tests)}`));
|
|
120
|
+
}
|
|
111
121
|
return;
|
|
112
122
|
}
|
|
113
123
|
if (command && command.split) {
|
|
114
|
-
command =
|
|
124
|
+
command = (0, utils_js_1.applyFilter)(command, tests);
|
|
115
125
|
}
|
|
116
126
|
}
|
|
117
127
|
catch (err) {
|
package/lib/pipe/coverage.js
CHANGED
|
@@ -54,7 +54,7 @@ class CoveragePipe {
|
|
|
54
54
|
this.branch = options?.diff || process.env.COVERAGE_BRANCH || this.#GIT.default_branch;
|
|
55
55
|
this.isBranchDefault = !options.diff && !process.env.COVERAGE_BRANCH;
|
|
56
56
|
if (this.isBranchDefault) {
|
|
57
|
-
|
|
57
|
+
log_js_1.log.info(`🟡 No "diff" branch provided. That's why we use default one = "${this.branch}".\n` +
|
|
58
58
|
'👉 You can set it via --filter "coverage:file=coverage.yml,diff=your-branch"');
|
|
59
59
|
}
|
|
60
60
|
// Client config section
|
|
@@ -136,7 +136,7 @@ class CoveragePipe {
|
|
|
136
136
|
const tests = await this.#getTestomatioTestsByParam(tagType, tag);
|
|
137
137
|
if (!tests)
|
|
138
138
|
return [];
|
|
139
|
-
|
|
139
|
+
log_js_1.log.info(`✅ We found ${tests.length === 1 ? 'one entry' : `${tests.length} (test/suite) entries`}` +
|
|
140
140
|
' in Testomat.io service side.');
|
|
141
141
|
tests.forEach(testId => this.tests.add(testId));
|
|
142
142
|
}
|
|
@@ -276,7 +276,7 @@ class CoveragePipe {
|
|
|
276
276
|
log_js_1.log.error(err.message);
|
|
277
277
|
return undefined;
|
|
278
278
|
}
|
|
279
|
-
log_js_1.log.
|
|
279
|
+
log_js_1.log.warn(`We will use '${cmd}' Git command.`);
|
|
280
280
|
try {
|
|
281
281
|
// For clear unit testing process -> Like test_defaultGitChangedFile = todomvc-tests/edit-todos_test.js
|
|
282
282
|
if (this.isDefaultGitChanges) {
|
|
@@ -285,7 +285,7 @@ class CoveragePipe {
|
|
|
285
285
|
else {
|
|
286
286
|
this.changedFiles = this.#getChangedFilesFromGit(cmd);
|
|
287
287
|
if (this.changedFiles.length === 0) {
|
|
288
|
-
|
|
288
|
+
log_js_1.log.info('ℹ️ No files changed in the latest Git commit. Skipping coverage processing.');
|
|
289
289
|
return undefined;
|
|
290
290
|
}
|
|
291
291
|
}
|
package/lib/utils/log.js
CHANGED
|
@@ -46,7 +46,8 @@ function shouldLog(messageLevel) {
|
|
|
46
46
|
*/
|
|
47
47
|
function info(...args) {
|
|
48
48
|
if (shouldLog(exports.LOG_LEVELS.INFO)) {
|
|
49
|
-
console.log
|
|
49
|
+
const fn = process.env.TESTOMATIO_LOG_STDERR === '1' ? console.error : console.log;
|
|
50
|
+
fn(constants_js_1.APP_PREFIX, ...args);
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
/**
|
|
@@ -54,3 +54,13 @@ export function fullName(t: object): string;
|
|
|
54
54
|
* => Returns: { foo: 'bar', baz: 'qux' }
|
|
55
55
|
*/
|
|
56
56
|
export function parsePipeOptions(optionsStr?: string): any;
|
|
57
|
+
/**
|
|
58
|
+
* Format a list of test IDs for `--filter-list` machine-readable output.
|
|
59
|
+
* Used when the CLI `--format` option is passed,
|
|
60
|
+
* e.g. `--filter-list "coverage:file=..." --format grep`.
|
|
61
|
+
*
|
|
62
|
+
* @param {string[]} ids
|
|
63
|
+
* @param {'grep'|'json'|'newline'|'ids'} format
|
|
64
|
+
* @returns {string} Empty string if no ids; otherwise the formatted output.
|
|
65
|
+
*/
|
|
66
|
+
export function formatFilterListIds(ids: string[], format: "grep" | "json" | "newline" | "ids"): string;
|
package/lib/utils/pipe_utils.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.setS3Credentials = setS3Credentials;
|
|
|
7
7
|
exports.statusEmoji = statusEmoji;
|
|
8
8
|
exports.fullName = fullName;
|
|
9
9
|
exports.parsePipeOptions = parsePipeOptions;
|
|
10
|
+
exports.formatFilterListIds = formatFilterListIds;
|
|
10
11
|
const log_js_1 = require("./log.js");
|
|
11
12
|
/**
|
|
12
13
|
* Set S3 credentials from the provided artifacts object.
|
|
@@ -161,6 +162,26 @@ function parsePipeOptions(optionsStr) {
|
|
|
161
162
|
}
|
|
162
163
|
return options;
|
|
163
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Format a list of test IDs for `--filter-list` machine-readable output.
|
|
167
|
+
* Used when the CLI `--format` option is passed,
|
|
168
|
+
* e.g. `--filter-list "coverage:file=..." --format grep`.
|
|
169
|
+
*
|
|
170
|
+
* @param {string[]} ids
|
|
171
|
+
* @param {'grep'|'json'|'newline'|'ids'} format
|
|
172
|
+
* @returns {string} Empty string if no ids; otherwise the formatted output.
|
|
173
|
+
*/
|
|
174
|
+
function formatFilterListIds(ids, format) {
|
|
175
|
+
if (!ids || ids.length === 0)
|
|
176
|
+
return '';
|
|
177
|
+
switch (format) {
|
|
178
|
+
case 'grep': return `(${ids.join('|')})`;
|
|
179
|
+
case 'json': return JSON.stringify(ids);
|
|
180
|
+
case 'newline': return ids.join('\n');
|
|
181
|
+
case 'ids':
|
|
182
|
+
default: return ids.join(',');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
164
185
|
|
|
165
186
|
module.exports.updateFilterType = updateFilterType;
|
|
166
187
|
|
|
@@ -175,3 +196,5 @@ module.exports.statusEmoji = statusEmoji;
|
|
|
175
196
|
module.exports.fullName = fullName;
|
|
176
197
|
|
|
177
198
|
module.exports.parsePipeOptions = parsePipeOptions;
|
|
199
|
+
|
|
200
|
+
module.exports.formatFilterListIds = formatFilterListIds;
|
package/package.json
CHANGED
package/src/bin/cli.js
CHANGED
|
@@ -15,22 +15,31 @@ import { filesize as prettyBytes } from 'filesize';
|
|
|
15
15
|
import dotenv from 'dotenv';
|
|
16
16
|
import Replay from '../replay.js';
|
|
17
17
|
import { log } from '../utils/log.js';
|
|
18
|
+
import { formatFilterListIds } from '../utils/pipe_utils.js';
|
|
18
19
|
|
|
19
20
|
const debug = createDebugMessages('@testomatio/reporter:cli');
|
|
20
21
|
const version = getPackageVersion();
|
|
21
|
-
console.log(pc.cyan(pc.bold(` 🤩 Testomat.io Reporter v${version}`)));
|
|
22
22
|
const program = new Command();
|
|
23
23
|
|
|
24
24
|
program
|
|
25
25
|
.version(version)
|
|
26
26
|
.option('--env-file <envfile>', 'Load environment variables from env file')
|
|
27
|
-
.hook('preAction', thisCommand => {
|
|
27
|
+
.hook('preAction', (thisCommand, actionCommand) => {
|
|
28
28
|
const opts = thisCommand.opts();
|
|
29
29
|
if (opts.envFile) {
|
|
30
30
|
dotenv.config({ path: opts.envFile });
|
|
31
31
|
} else {
|
|
32
32
|
dotenv.config();
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
// --filter-list produces a machine-readable test list on stdout, so route
|
|
36
|
+
// logs to stderr and skip the banner to keep stdout clean for piping.
|
|
37
|
+
const subOpts = actionCommand.opts();
|
|
38
|
+
if (subOpts.filterList || subOpts.format) {
|
|
39
|
+
process.env.TESTOMATIO_LOG_STDERR = '1';
|
|
40
|
+
} else {
|
|
41
|
+
console.log(pc.cyan(pc.bold(` 🤩 Testomat.io Reporter v${version}`)));
|
|
42
|
+
}
|
|
34
43
|
});
|
|
35
44
|
|
|
36
45
|
program
|
|
@@ -83,6 +92,7 @@ program
|
|
|
83
92
|
.argument('[command]', 'Test runner command')
|
|
84
93
|
.option('--filter <filter>', 'Additional execution filter')
|
|
85
94
|
.option('--filter-list <filter>', 'Get a list of all tests by filter before running')
|
|
95
|
+
.option('--format <format>', 'Machine-readable output format for --filter-list (grep, json, newline, ids)')
|
|
86
96
|
.option('--kind <type>', 'Specify run type: automated, manual, or mixed')
|
|
87
97
|
.action(async (command, opts) => {
|
|
88
98
|
const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config.TESTOMATIO;
|
|
@@ -93,7 +103,7 @@ program
|
|
|
93
103
|
log.info('Filtering tests...');
|
|
94
104
|
// Example of use: npx @testomatio/reporter run "npx jest" --filter "testomatio:tag-name=frontend"
|
|
95
105
|
// Example of use: npx @testomatio/reporter run "npx jest" --filter "coverage:file=coverage.yml"
|
|
96
|
-
// Example of use: npx @testomatio/reporter run
|
|
106
|
+
// Example of use: npx @testomatio/reporter run --filter-list "coverage:file=coverage.yml" --format grep
|
|
97
107
|
const [pipe, ...optsArray] = opts?.filter ? opts?.filter.split(':') : opts?.filterList.split(':');
|
|
98
108
|
const pipeOptions = optsArray.join(':');
|
|
99
109
|
|
|
@@ -110,21 +120,19 @@ program
|
|
|
110
120
|
return;
|
|
111
121
|
}
|
|
112
122
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
log.info(`Grep string:`);
|
|
122
|
-
log.info(`${tests.join(', ')}`);
|
|
123
|
+
if (opts.filterList) {
|
|
124
|
+
const out = formatFilterListIds(tests, opts.format || 'ids');
|
|
125
|
+
if (out) console.log(out);
|
|
126
|
+
// Show the runnable-command hint only in interactive mode (no explicit --format).
|
|
127
|
+
// When --format is set the user is scripting and doesn't need stderr noise.
|
|
128
|
+
if (command && !opts.format) {
|
|
129
|
+
log.info(pc.green(`Full Running Command: ${applyFilter(command, tests)}`));
|
|
130
|
+
}
|
|
123
131
|
return;
|
|
124
132
|
}
|
|
125
133
|
|
|
126
134
|
if (command && command.split) {
|
|
127
|
-
command =
|
|
135
|
+
command = applyFilter(command, tests);
|
|
128
136
|
}
|
|
129
137
|
}
|
|
130
138
|
catch (err) {
|
package/src/pipe/coverage.js
CHANGED
|
@@ -57,8 +57,7 @@ class CoveragePipe { // or Changes for the future???
|
|
|
57
57
|
this.isBranchDefault = !options.diff && !process.env.COVERAGE_BRANCH;
|
|
58
58
|
|
|
59
59
|
if (this.isBranchDefault) {
|
|
60
|
-
|
|
61
|
-
APP_PREFIX,
|
|
60
|
+
log.info(
|
|
62
61
|
`🟡 No "diff" branch provided. That's why we use default one = "${this.branch}".\n` +
|
|
63
62
|
'👉 You can set it via --filter "coverage:file=coverage.yml,diff=your-branch"'
|
|
64
63
|
);
|
|
@@ -154,8 +153,7 @@ class CoveragePipe { // or Changes for the future???
|
|
|
154
153
|
|
|
155
154
|
if (!tests) return [];
|
|
156
155
|
|
|
157
|
-
|
|
158
|
-
APP_PREFIX,
|
|
156
|
+
log.info(
|
|
159
157
|
`✅ We found ${tests.length === 1 ? 'one entry' : `${tests.length} (test/suite) entries`}` +
|
|
160
158
|
' in Testomat.io service side.'
|
|
161
159
|
);
|
|
@@ -324,7 +322,7 @@ class CoveragePipe { // or Changes for the future???
|
|
|
324
322
|
return undefined;
|
|
325
323
|
}
|
|
326
324
|
|
|
327
|
-
log.
|
|
325
|
+
log.warn( `We will use '${cmd}' Git command.`);
|
|
328
326
|
|
|
329
327
|
try {
|
|
330
328
|
// For clear unit testing process -> Like test_defaultGitChangedFile = todomvc-tests/edit-todos_test.js
|
|
@@ -335,10 +333,7 @@ class CoveragePipe { // or Changes for the future???
|
|
|
335
333
|
this.changedFiles = this.#getChangedFilesFromGit(cmd);
|
|
336
334
|
|
|
337
335
|
if (this.changedFiles.length === 0) {
|
|
338
|
-
|
|
339
|
-
APP_PREFIX,
|
|
340
|
-
'ℹ️ No files changed in the latest Git commit. Skipping coverage processing.'
|
|
341
|
-
);
|
|
336
|
+
log.info('ℹ️ No files changed in the latest Git commit. Skipping coverage processing.');
|
|
342
337
|
|
|
343
338
|
return undefined;
|
|
344
339
|
}
|
package/src/utils/log.js
CHANGED
|
@@ -42,7 +42,8 @@ export function shouldLog(messageLevel) {
|
|
|
42
42
|
*/
|
|
43
43
|
export function info(...args) {
|
|
44
44
|
if (shouldLog(LOG_LEVELS.INFO)) {
|
|
45
|
-
console.log
|
|
45
|
+
const fn = process.env.TESTOMATIO_LOG_STDERR === '1' ? console.error : console.log;
|
|
46
|
+
fn(APP_PREFIX, ...args);
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
|
package/src/utils/pipe_utils.js
CHANGED
|
@@ -161,12 +161,33 @@ function parsePipeOptions(optionsStr) {
|
|
|
161
161
|
return options;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
164
|
+
/**
|
|
165
|
+
* Format a list of test IDs for `--filter-list` machine-readable output.
|
|
166
|
+
* Used when the CLI `--format` option is passed,
|
|
167
|
+
* e.g. `--filter-list "coverage:file=..." --format grep`.
|
|
168
|
+
*
|
|
169
|
+
* @param {string[]} ids
|
|
170
|
+
* @param {'grep'|'json'|'newline'|'ids'} format
|
|
171
|
+
* @returns {string} Empty string if no ids; otherwise the formatted output.
|
|
172
|
+
*/
|
|
173
|
+
function formatFilterListIds(ids, format) {
|
|
174
|
+
if (!ids || ids.length === 0) return '';
|
|
175
|
+
switch (format) {
|
|
176
|
+
case 'grep': return `(${ids.join('|')})`;
|
|
177
|
+
case 'json': return JSON.stringify(ids);
|
|
178
|
+
case 'newline': return ids.join('\n');
|
|
179
|
+
case 'ids':
|
|
180
|
+
default: return ids.join(',');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export {
|
|
185
|
+
updateFilterType,
|
|
186
|
+
parseFilterParams,
|
|
187
|
+
generateFilterRequestParams,
|
|
188
|
+
setS3Credentials,
|
|
189
|
+
statusEmoji,
|
|
170
190
|
fullName,
|
|
171
|
-
parsePipeOptions
|
|
191
|
+
parsePipeOptions,
|
|
192
|
+
formatFilterListIds,
|
|
172
193
|
};
|