@testomatio/reporter 2.0.0-beta-esm → 2.0.1-beta-esm
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.d.ts +2 -0
- package/lib/adapter/codecept.js +31 -24
- package/lib/adapter/cucumber/current.d.ts +14 -0
- package/lib/adapter/cucumber/legacy.d.ts +0 -0
- package/lib/adapter/cucumber.d.ts +2 -0
- package/lib/adapter/cypress-plugin/index.d.ts +2 -0
- package/lib/adapter/cypress-plugin/index.js +11 -9
- package/lib/adapter/jasmine.d.ts +11 -0
- package/lib/adapter/jest.d.ts +13 -0
- package/lib/adapter/mocha.d.ts +2 -0
- package/lib/adapter/mocha.js +4 -3
- package/lib/adapter/playwright.d.ts +14 -0
- package/lib/adapter/playwright.js +58 -33
- package/lib/adapter/vitest.d.ts +35 -0
- package/lib/adapter/vitest.js +6 -6
- package/lib/adapter/webdriver.d.ts +24 -0
- package/lib/adapter/webdriver.js +34 -6
- package/lib/bin/cli.d.ts +2 -0
- package/lib/bin/cli.js +228 -0
- package/lib/bin/reportXml.d.ts +2 -0
- package/lib/bin/reportXml.js +11 -9
- package/lib/bin/startTest.d.ts +2 -0
- package/lib/bin/startTest.js +9 -5
- package/lib/bin/uploadArtifacts.d.ts +2 -0
- package/lib/bin/uploadArtifacts.js +81 -0
- package/lib/client.d.ts +76 -0
- package/lib/client.js +111 -45
- package/lib/config.d.ts +1 -0
- package/lib/constants.d.ts +25 -0
- package/lib/constants.js +5 -1
- package/lib/data-storage.d.ts +34 -0
- package/lib/data-storage.js +2 -2
- package/lib/junit-adapter/adapter.d.ts +9 -0
- package/lib/junit-adapter/csharp.d.ts +4 -0
- package/lib/junit-adapter/index.d.ts +3 -0
- package/lib/junit-adapter/java.d.ts +5 -0
- package/lib/junit-adapter/javascript.d.ts +4 -0
- package/lib/junit-adapter/python.d.ts +5 -0
- package/lib/junit-adapter/ruby.d.ts +4 -0
- package/lib/output.d.ts +11 -0
- package/lib/package.json +3 -1
- package/lib/pipe/bitbucket.d.ts +23 -0
- package/lib/pipe/bitbucket.js +2 -2
- package/lib/pipe/csv.d.ts +47 -0
- package/lib/pipe/csv.js +2 -2
- package/lib/pipe/debug.d.ts +29 -0
- package/lib/pipe/debug.js +108 -0
- package/lib/pipe/github.d.ts +30 -0
- package/lib/pipe/github.js +2 -2
- package/lib/pipe/gitlab.d.ts +23 -0
- package/lib/pipe/gitlab.js +2 -2
- package/lib/pipe/html.d.ts +34 -0
- package/lib/pipe/html.js +8 -1
- package/lib/pipe/index.d.ts +1 -0
- package/lib/pipe/index.js +3 -3
- package/lib/pipe/testomatio.d.ts +70 -0
- package/lib/pipe/testomatio.js +50 -30
- package/lib/reporter-functions.d.ts +34 -0
- package/lib/reporter-functions.js +17 -7
- package/lib/reporter.d.ts +232 -0
- package/lib/reporter.js +19 -33
- package/lib/services/artifacts.d.ts +33 -0
- package/lib/services/index.d.ts +9 -0
- package/lib/services/key-values.d.ts +27 -0
- package/lib/services/key-values.js +1 -1
- package/lib/services/logger.d.ts +64 -0
- package/lib/template/testomatio.hbs +651 -1366
- package/lib/uploader.d.ts +60 -0
- package/lib/uploader.js +312 -0
- package/lib/utils/pipe_utils.d.ts +41 -0
- package/lib/utils/pipe_utils.js +3 -5
- package/lib/utils/utils.d.ts +45 -0
- package/lib/utils/utils.js +69 -2
- package/lib/xmlReader.d.ts +92 -0
- package/lib/xmlReader.js +22 -12
- package/package.json +15 -9
- package/src/adapter/codecept.js +30 -24
- package/src/adapter/cypress-plugin/index.js +5 -3
- package/src/adapter/mocha.cjs +1 -1
- package/src/adapter/mocha.js +4 -3
- package/src/adapter/playwright.js +59 -31
- package/src/adapter/vitest.js +6 -6
- package/src/adapter/webdriver.js +41 -10
- package/src/bin/cli.js +280 -0
- package/src/bin/reportXml.js +15 -8
- package/src/bin/startTest.js +7 -3
- package/src/bin/uploadArtifacts.js +90 -0
- package/src/client.js +137 -56
- package/src/constants.js +5 -1
- package/src/data-storage.js +2 -2
- package/src/pipe/bitbucket.js +2 -2
- package/src/pipe/csv.js +3 -3
- package/src/pipe/debug.js +104 -0
- package/src/pipe/github.js +2 -3
- package/src/pipe/gitlab.js +6 -6
- package/src/pipe/html.js +11 -3
- package/src/pipe/index.js +5 -7
- package/src/pipe/testomatio.js +72 -67
- package/src/reporter-functions.js +18 -7
- package/src/reporter.cjs_decprecated +21 -0
- package/src/reporter.js +20 -11
- package/src/services/key-values.js +1 -1
- package/src/services/logger.js +4 -2
- package/src/template/testomatio.hbs +651 -1366
- package/src/uploader.js +371 -0
- package/src/utils/pipe_utils.js +4 -12
- package/src/utils/utils.js +48 -6
- package/src/xmlReader.js +26 -15
- package/lib/adapter/jasmine/jasmine.js +0 -63
- package/lib/adapter/mocha/mocha.js +0 -125
- package/lib/fileUploader.js +0 -245
- package/lib/utils/chalk.js +0 -10
- package/src/fileUploader.js +0 -307
- package/src/reporter.cjs +0 -22
- package/src/utils/chalk.js +0 -13
package/src/adapter/webdriver.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// eslint-disable-next-line
|
|
2
2
|
import WDIOReporter, { RunnerStats } from '@wdio/reporter';
|
|
3
|
-
|
|
4
3
|
import TestomatClient from '../client.js';
|
|
5
|
-
import { getTestomatIdFromTestTitle } from '../utils/utils.js';
|
|
4
|
+
import { getTestomatIdFromTestTitle, fileSystem } from '../utils/utils.js';
|
|
5
|
+
import { services } from '../services/index.js';
|
|
6
|
+
import { TESTOMAT_TMP_STORAGE_DIR } from '../constants.js';
|
|
6
7
|
|
|
7
8
|
class WebdriverReporter extends WDIOReporter {
|
|
8
9
|
constructor(options) {
|
|
@@ -23,8 +24,8 @@ class WebdriverReporter extends WDIOReporter {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
|
-
*
|
|
27
|
-
* @param {RunnerStats} runData
|
|
27
|
+
*
|
|
28
|
+
* @param {RunnerStats} runData
|
|
28
29
|
*/
|
|
29
30
|
async onRunnerEnd(runData) {
|
|
30
31
|
this._isSynchronising = true;
|
|
@@ -33,20 +34,35 @@ class WebdriverReporter extends WDIOReporter {
|
|
|
33
34
|
|
|
34
35
|
this._isSynchronising = false;
|
|
35
36
|
|
|
36
|
-
// NOTE: new functionality; may break everything
|
|
37
|
+
// NOTE: new functionality; may break everything
|
|
37
38
|
// also this may require additional status mapping
|
|
38
39
|
await this.client.updateRunStatus(runData.failures ? 'failed' : 'passed');
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
onRunnerStart() {
|
|
43
|
+
// clear dir with artifacts/logs
|
|
44
|
+
//
|
|
45
|
+
fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
onTestStart(test) {
|
|
49
|
+
services.setContext(test.fullTitle);
|
|
50
|
+
}
|
|
51
|
+
|
|
41
52
|
onTestEnd(test) {
|
|
53
|
+
test.suite = test.parent;
|
|
54
|
+
const logs = getTestLogs(test.fullTitle);
|
|
55
|
+
// TODO: FIX: artifacts for some reason leads to empty report on Testomat.io
|
|
56
|
+
// const artifacts = services.artifacts.get(test.fullTitle);
|
|
57
|
+
// const keyValues = services.keyValues.get(test.fullTitle);
|
|
58
|
+
test.logs = logs;
|
|
59
|
+
// test.artifacts = artifacts;
|
|
60
|
+
// test.meta = keyValues;
|
|
61
|
+
|
|
42
62
|
this._addTestPromises.push(this.addTest(test));
|
|
43
63
|
}
|
|
44
64
|
|
|
45
65
|
// wdio-cucumber does not trigger onTestEnd hook, thus, using this one
|
|
46
|
-
/**
|
|
47
|
-
*
|
|
48
|
-
* @returns
|
|
49
|
-
*/
|
|
50
66
|
onSuiteEnd(scerario) {
|
|
51
67
|
if (scerario.type === 'scenario') {
|
|
52
68
|
this._addTestPromises.push(this.addBddScenario(scerario));
|
|
@@ -66,7 +82,10 @@ class WebdriverReporter extends WDIOReporter {
|
|
|
66
82
|
.map(el => Buffer.from(el.result.value, 'base64'));
|
|
67
83
|
|
|
68
84
|
await this.client.addTestRun(state, {
|
|
85
|
+
manuallyAttachedArtifacts: test.artifacts,
|
|
69
86
|
error,
|
|
87
|
+
logs: test.logs,
|
|
88
|
+
meta: test.meta,
|
|
70
89
|
title,
|
|
71
90
|
test_id: testId,
|
|
72
91
|
time: duration,
|
|
@@ -75,7 +94,7 @@ class WebdriverReporter extends WDIOReporter {
|
|
|
75
94
|
}
|
|
76
95
|
|
|
77
96
|
/**
|
|
78
|
-
* @param {import('../../types').WebdriverIOScenario} scenario
|
|
97
|
+
* @param {import('../../types/types.js').WebdriverIOScenario} scenario
|
|
79
98
|
*/
|
|
80
99
|
addBddScenario(scenario) {
|
|
81
100
|
if (!this.client) return;
|
|
@@ -108,4 +127,16 @@ class WebdriverReporter extends WDIOReporter {
|
|
|
108
127
|
}
|
|
109
128
|
}
|
|
110
129
|
|
|
130
|
+
/**
|
|
131
|
+
*
|
|
132
|
+
* @param {*} fullTestTitle
|
|
133
|
+
* @returns string
|
|
134
|
+
*/
|
|
135
|
+
function getTestLogs(fullTestTitle) {
|
|
136
|
+
const logsArr = services.logger.getLogs(fullTestTitle);
|
|
137
|
+
// remove duplicates (for some reason, logs are duplicated several times)
|
|
138
|
+
const logs = logsArr ? Array.from(new Set(logsArr)).join('\n').trim() : '';
|
|
139
|
+
return logs;
|
|
140
|
+
}
|
|
141
|
+
|
|
111
142
|
export default WebdriverReporter;
|
package/src/bin/cli.js
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { spawn } from 'cross-spawn';
|
|
5
|
+
import glob from 'glob';
|
|
6
|
+
import createDebugMessages from 'debug';
|
|
7
|
+
import TestomatClient from '../client.js';
|
|
8
|
+
import XmlReader from '../xmlReader.js';
|
|
9
|
+
import { APP_PREFIX, STATUS } from '../constants.js';
|
|
10
|
+
import { version } from '../../package.json';
|
|
11
|
+
import { config } from '../config.js';
|
|
12
|
+
import { readLatestRunId } from '../utils/utils.js';
|
|
13
|
+
import pc from 'picocolors';
|
|
14
|
+
import { filesize as prettyBytes } from 'filesize';
|
|
15
|
+
import dotenv from 'dotenv';
|
|
16
|
+
|
|
17
|
+
const debug = createDebugMessages('@testomatio/reporter:xml-cli');
|
|
18
|
+
console.log(pc.cyan(pc.bold(` 🤩 Testomat.io Reporter v${version}`)));
|
|
19
|
+
const program = new Command();
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.version(version)
|
|
23
|
+
.option('--env-file <envfile>', 'Load environment variables from env file')
|
|
24
|
+
.hook('preAction', thisCommand => {
|
|
25
|
+
const opts = thisCommand.opts();
|
|
26
|
+
if (opts.envFile) {
|
|
27
|
+
dotenv.config({ path: opts.envFile });
|
|
28
|
+
} else {
|
|
29
|
+
dotenv.config();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
program
|
|
34
|
+
.command('start')
|
|
35
|
+
.description('Start a new run and return its ID')
|
|
36
|
+
.action(async () => {
|
|
37
|
+
console.log('Starting a new Run on Testomat.io...');
|
|
38
|
+
const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config.TESTOMATIO;
|
|
39
|
+
const client = new TestomatClient({ apiKey });
|
|
40
|
+
|
|
41
|
+
client.createRun().then(() => {
|
|
42
|
+
console.log(process.env.runId);
|
|
43
|
+
process.exit(0);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
program
|
|
48
|
+
.command('finish')
|
|
49
|
+
.description('Finish Run by its ID')
|
|
50
|
+
.action(async () => {
|
|
51
|
+
process.env.TESTOMATIO_RUN ||= readLatestRunId();
|
|
52
|
+
|
|
53
|
+
if (!process.env.TESTOMATIO_RUN) {
|
|
54
|
+
console.log('TESTOMATIO_RUN environment variable must be set or restored from a previous run.');
|
|
55
|
+
return process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log('Finishing Run on Testomat.io...');
|
|
59
|
+
const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config.TESTOMATIO;
|
|
60
|
+
const client = new TestomatClient({ apiKey });
|
|
61
|
+
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
client.updateRunStatus(STATUS.FINISHED).then(() => {
|
|
64
|
+
console.log(pc.yellow(`Run ${process.env.TESTOMATIO_RUN} was finished`));
|
|
65
|
+
process.exit(0);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
program
|
|
70
|
+
.command('run')
|
|
71
|
+
.description('Run tests with the specified command')
|
|
72
|
+
.argument('<command>', 'Test runner command')
|
|
73
|
+
.option('--filter <filter>', 'Additional execution filter')
|
|
74
|
+
.action(async (command, opts) => {
|
|
75
|
+
const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config.TESTOMATIO;
|
|
76
|
+
const title = process.env.TESTOMATIO_TITLE;
|
|
77
|
+
|
|
78
|
+
if (!command || !command.split) {
|
|
79
|
+
console.log(APP_PREFIX, `No command provided. Use -c option to launch a test runner.`);
|
|
80
|
+
return process.exit(255);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const client = new TestomatClient({ apiKey, title, parallel: true });
|
|
84
|
+
|
|
85
|
+
if (opts.filter) {
|
|
86
|
+
const [pipe, ...optsArray] = opts.filter.split(':');
|
|
87
|
+
const pipeOptions = optsArray.join(':');
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const tests = await client.prepareRun({ pipe, pipeOptions });
|
|
91
|
+
if (tests && tests.length > 0) {
|
|
92
|
+
command += ` --grep (${tests.join('|')})`;
|
|
93
|
+
}
|
|
94
|
+
} catch (err) {
|
|
95
|
+
console.log(APP_PREFIX, err);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log(APP_PREFIX, `🚀 Running`, pc.green(command));
|
|
100
|
+
|
|
101
|
+
const runTests = () => {
|
|
102
|
+
const testCmds = command.split(' ');
|
|
103
|
+
const cmd = spawn(testCmds[0], testCmds.slice(1), { stdio: 'inherit' });
|
|
104
|
+
|
|
105
|
+
cmd.on('close', code => {
|
|
106
|
+
const emoji = code === 0 ? '🟢' : '🔴';
|
|
107
|
+
console.log(APP_PREFIX, emoji, `Runner exited with ${pc.bold(code)}`);
|
|
108
|
+
if (apiKey) {
|
|
109
|
+
const status = code === 0 ? 'passed' : 'failed';
|
|
110
|
+
client.updateRunStatus(status, true);
|
|
111
|
+
}
|
|
112
|
+
process.exit(code);
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
if (apiKey) {
|
|
117
|
+
client.createRun().then(runTests);
|
|
118
|
+
} else {
|
|
119
|
+
runTests();
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
program
|
|
124
|
+
.command('xml')
|
|
125
|
+
.description('Parse XML reports and upload to Testomat.io')
|
|
126
|
+
.argument('<pattern>', 'XML file pattern')
|
|
127
|
+
.option('-d, --dir <dir>', 'Project directory')
|
|
128
|
+
.option('--java-tests [java-path]', 'Load Java tests from path, by default: src/test/java')
|
|
129
|
+
.option('--lang <lang>', 'Language used (python, ruby, java)')
|
|
130
|
+
.option('--timelimit <time>', 'default time limit in seconds to kill a stuck process')
|
|
131
|
+
.action(async (pattern, opts) => {
|
|
132
|
+
if (!pattern.endsWith('.xml')) {
|
|
133
|
+
pattern += '.xml';
|
|
134
|
+
}
|
|
135
|
+
let { javaTests, lang } = opts;
|
|
136
|
+
if (javaTests === true) javaTests = 'src/test/java';
|
|
137
|
+
lang = lang?.toLowerCase();
|
|
138
|
+
const runReader = new XmlReader({ javaTests, lang });
|
|
139
|
+
const files = glob.sync(pattern, { cwd: opts.dir || process.cwd() });
|
|
140
|
+
if (!files.length) {
|
|
141
|
+
console.log(APP_PREFIX, `Report can't be created. No XML files found 😥`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
for (const file of files) {
|
|
146
|
+
console.log(APP_PREFIX, `Parsed ${file}`);
|
|
147
|
+
runReader.parse(file);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let timeoutTimer;
|
|
151
|
+
if (opts.timelimit) {
|
|
152
|
+
timeoutTimer = setTimeout(
|
|
153
|
+
() => {
|
|
154
|
+
console.log(
|
|
155
|
+
`⚠️ Reached timeout of ${opts.timelimit}s. Exiting... (Exit code is 0 to not fail the pipeline)`,
|
|
156
|
+
);
|
|
157
|
+
process.exit(0);
|
|
158
|
+
},
|
|
159
|
+
parseInt(opts.timelimit, 10) * 1000,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
await runReader.createRun();
|
|
165
|
+
await runReader.uploadData();
|
|
166
|
+
} catch (err) {
|
|
167
|
+
console.log(APP_PREFIX, 'Error updating status, skipping...', err);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
program
|
|
174
|
+
.command('upload-artifacts')
|
|
175
|
+
.description('Upload artifacts to Testomat.io')
|
|
176
|
+
.option('--force', 'Re-upload artifacts even if they were uploaded before')
|
|
177
|
+
.action(async opts => {
|
|
178
|
+
const apiKey = config.TESTOMATIO;
|
|
179
|
+
|
|
180
|
+
process.env.TESTOMATIO_DISABLE_ARTIFACTS = '';
|
|
181
|
+
const runId = process.env.TESTOMATIO_RUN || process.env.runId || readLatestRunId();
|
|
182
|
+
|
|
183
|
+
if (!runId) {
|
|
184
|
+
console.log('TESTOMATIO_RUN environment variable must be set or restored from a previous run.');
|
|
185
|
+
return process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const client = new TestomatClient({
|
|
189
|
+
apiKey,
|
|
190
|
+
runId,
|
|
191
|
+
isBatchEnabled: false,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
let testruns = client.uploader.readUploadedFiles(runId);
|
|
195
|
+
const numTotalArtifacts = testruns.length;
|
|
196
|
+
|
|
197
|
+
debug('Found testruns:', testruns);
|
|
198
|
+
|
|
199
|
+
if (!opts.force) testruns = testruns.filter(tr => !tr.uploaded);
|
|
200
|
+
|
|
201
|
+
if (!testruns.length) {
|
|
202
|
+
console.log(APP_PREFIX, '🗄️ Total artifacts:', numTotalArtifacts);
|
|
203
|
+
if (numTotalArtifacts) {
|
|
204
|
+
console.log(APP_PREFIX, 'No new artifacts to upload');
|
|
205
|
+
console.log(APP_PREFIX, 'To re-upload artifacts run this command with --force flag');
|
|
206
|
+
}
|
|
207
|
+
process.exit(0);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const testrunsByRid = testruns.reduce((acc, { rid, file }) => {
|
|
211
|
+
if (!acc[rid]) {
|
|
212
|
+
acc[rid] = [];
|
|
213
|
+
}
|
|
214
|
+
if (!acc[rid].includes(file)) acc[rid].push(file);
|
|
215
|
+
return acc;
|
|
216
|
+
}, {});
|
|
217
|
+
|
|
218
|
+
await client.createRun();
|
|
219
|
+
client.uploader.checkEnabled();
|
|
220
|
+
client.uploader.disableLogStorage();
|
|
221
|
+
|
|
222
|
+
for (const rid in testrunsByRid) {
|
|
223
|
+
const files = testrunsByRid[rid];
|
|
224
|
+
await client.addTestRun(undefined, { rid, files });
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
console.log(APP_PREFIX, '🗄️', client.uploader.successfulUploads.length, 'artifacts 🟢uploaded');
|
|
228
|
+
|
|
229
|
+
if (client.uploader.successfulUploads.length) {
|
|
230
|
+
debug('\n', APP_PREFIX, `🗄️ ${client.uploader.successfulUploads.length} artifacts uploaded to S3 bucket`);
|
|
231
|
+
const uploadedArtifacts = client.uploader.successfulUploads.map(file => ({
|
|
232
|
+
relativePath: file.path.replace(process.cwd(), ''),
|
|
233
|
+
link: file.link,
|
|
234
|
+
sizePretty: prettyBytes(file.size, { round: 0 }).toString(),
|
|
235
|
+
}));
|
|
236
|
+
|
|
237
|
+
uploadedArtifacts.forEach(upload => {
|
|
238
|
+
debug(
|
|
239
|
+
`🟢Uploaded artifact`,
|
|
240
|
+
`${upload.relativePath},`,
|
|
241
|
+
'size:',
|
|
242
|
+
`${upload.sizePretty},`,
|
|
243
|
+
'link:',
|
|
244
|
+
`${upload.link}`,
|
|
245
|
+
);
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const filesizeStrMaxLength = 7;
|
|
250
|
+
|
|
251
|
+
if (client.uploader.failedUploads.length) {
|
|
252
|
+
console.log(
|
|
253
|
+
'\n',
|
|
254
|
+
APP_PREFIX,
|
|
255
|
+
'🗄️',
|
|
256
|
+
client.uploader.failedUploads.length,
|
|
257
|
+
`artifacts 🔴${pc.bold('failed')} to upload`,
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const failedUploads = client.uploader.failedUploads.map(({ path, size }) => ({
|
|
261
|
+
relativePath: path.replace(process.cwd(), ''),
|
|
262
|
+
sizePretty: prettyBytes(size, { round: 0 }).toString(),
|
|
263
|
+
}));
|
|
264
|
+
|
|
265
|
+
const pathPadding = Math.max(...failedUploads.map(upload => upload.relativePath.length)) + 1;
|
|
266
|
+
failedUploads.forEach(upload => {
|
|
267
|
+
console.log(
|
|
268
|
+
` ${pc.gray('|')} 🔴 ${upload.relativePath.padEnd(pathPadding)} ${pc.gray(
|
|
269
|
+
`| ${upload.sizePretty.padStart(filesizeStrMaxLength)} |`,
|
|
270
|
+
)}`,
|
|
271
|
+
);
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
program.parse(process.argv);
|
|
277
|
+
|
|
278
|
+
if (!process.argv.slice(2).length) {
|
|
279
|
+
program.outputHelp();
|
|
280
|
+
}
|
package/src/bin/reportXml.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import { Command } from 'commander';
|
|
3
3
|
import pc from 'picocolors';
|
|
4
|
-
import glob from 'glob';
|
|
4
|
+
import { glob } from 'glob';
|
|
5
5
|
import createDebugMessages from 'debug';
|
|
6
6
|
import { APP_PREFIX } from '../constants.js';
|
|
7
7
|
import XmlReader from '../xmlReader.js';
|
|
8
8
|
import { version } from '../../package.json';
|
|
9
|
+
import dotenv from 'dotenv';
|
|
9
10
|
|
|
10
11
|
const debug = createDebugMessages('@testomatio/reporter:xml-cli');
|
|
11
12
|
console.log(pc.cyan(pc.bold(` 🤩 Testomat.io XML Reporter v${version}`)));
|
|
13
|
+
const program = new Command();
|
|
12
14
|
|
|
13
15
|
program
|
|
14
16
|
.arguments('<pattern>')
|
|
@@ -25,10 +27,10 @@ program
|
|
|
25
27
|
if (opts.envFile) {
|
|
26
28
|
console.log(APP_PREFIX, 'Loading env file:', opts.envFile);
|
|
27
29
|
debug('Loading env file: %s', opts.envFile);
|
|
28
|
-
|
|
30
|
+
dotenv.config({ path: opts.envFile });
|
|
29
31
|
}
|
|
30
|
-
if (javaTests === true) javaTests = 'src/test/java';
|
|
31
32
|
lang = lang?.toLowerCase();
|
|
33
|
+
if (javaTests === true || (lang === 'java' && !javaTests)) javaTests = 'src/test/java';
|
|
32
34
|
const runReader = new XmlReader({ javaTests, lang });
|
|
33
35
|
const files = glob.sync(pattern, { cwd: opts.dir || process.cwd() });
|
|
34
36
|
if (!files.length) {
|
|
@@ -44,10 +46,15 @@ program
|
|
|
44
46
|
|
|
45
47
|
let timeoutTimer;
|
|
46
48
|
if (opts.timelimit) {
|
|
47
|
-
timeoutTimer = setTimeout(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
timeoutTimer = setTimeout(
|
|
50
|
+
() => {
|
|
51
|
+
console.log(
|
|
52
|
+
`⚠️ Reached timeout of ${opts.timelimit}s. Exiting... (Exit code is 0 to not fail the pipeline)`,
|
|
53
|
+
);
|
|
54
|
+
process.exit(0);
|
|
55
|
+
},
|
|
56
|
+
parseInt(opts.timelimit, 10) * 1000,
|
|
57
|
+
);
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
try {
|
package/src/bin/startTest.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from 'cross-spawn';
|
|
3
|
-
import
|
|
3
|
+
import { Command } from 'commander';
|
|
4
4
|
import pc from 'picocolors';
|
|
5
5
|
import TestomatClient from '../client.js';
|
|
6
6
|
import { APP_PREFIX, STATUS } from '../constants.js';
|
|
7
7
|
import { version } from '../../package.json';
|
|
8
|
-
import {config} from '../config.js';
|
|
8
|
+
import { config } from '../config.js';
|
|
9
|
+
import dotenv from 'dotenv';
|
|
9
10
|
|
|
10
11
|
console.log(pc.cyan(pc.bold(` 🤩 Testomat.io Reporter v${version}`)));
|
|
12
|
+
const program = new Command();
|
|
11
13
|
|
|
12
14
|
program
|
|
13
15
|
.option('-c, --command <cmd>', 'Test runner command')
|
|
@@ -19,7 +21,7 @@ program
|
|
|
19
21
|
const { launch, finish, filter } = opts;
|
|
20
22
|
let { command } = opts;
|
|
21
23
|
|
|
22
|
-
if (opts.envFile)
|
|
24
|
+
if (opts.envFile) dotenv.config({ path: opts.envFile });
|
|
23
25
|
|
|
24
26
|
const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config.TESTOMATIO;
|
|
25
27
|
const title = process.env.TESTOMATIO_TITLE;
|
|
@@ -36,6 +38,8 @@ program
|
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
if (finish) {
|
|
41
|
+
// TODO: add error in case of TESTOMATIO environment variable is not set
|
|
42
|
+
// because command is fine in console, but actually (on testomat.io) run is not finished
|
|
39
43
|
if (!process.env.TESTOMATIO_RUN) {
|
|
40
44
|
console.log('TESTOMATIO_RUN environment variable must be set.');
|
|
41
45
|
return process.exit(1);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import pc from 'picocolors';
|
|
5
|
+
import createDebugMessages from 'debug';
|
|
6
|
+
import TestomatClient from '../client.js';
|
|
7
|
+
import { APP_PREFIX } from '../constants.js';
|
|
8
|
+
import { version } from '../../package.json';
|
|
9
|
+
import { config } from '../config.js';
|
|
10
|
+
import { readLatestRunId } from '../utils/utils.js';
|
|
11
|
+
import dotenv from 'dotenv';
|
|
12
|
+
|
|
13
|
+
const debug = createDebugMessages('@testomatio/reporter:upload-cli');
|
|
14
|
+
console.log(pc.cyan(pc.bold(` 🤩 Testomat.io Reporter v${version}`)));
|
|
15
|
+
const program = new Command();
|
|
16
|
+
|
|
17
|
+
program
|
|
18
|
+
.option('--env-file <envfile>', 'Load environment variables from env file')
|
|
19
|
+
.option('--force', 'Re-upload artifacts even if they were uploaded before')
|
|
20
|
+
.action(async opts => {
|
|
21
|
+
if (opts.envFile) {
|
|
22
|
+
dotenv.config({ path: opts.envFile });
|
|
23
|
+
} else {
|
|
24
|
+
dotenv.config();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const apiKey = config.TESTOMATIO;
|
|
28
|
+
process.env.TESTOMATIO_DISABLE_ARTIFACTS = '';
|
|
29
|
+
const runId = process.env.TESTOMATIO_RUN || process.env.runId || readLatestRunId();
|
|
30
|
+
|
|
31
|
+
if (!runId) {
|
|
32
|
+
console.log('TESTOMATIO_RUN environment variable must be set or restored from a previous run.');
|
|
33
|
+
return process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const client = new TestomatClient({
|
|
37
|
+
apiKey,
|
|
38
|
+
runId,
|
|
39
|
+
isBatchEnabled: false,
|
|
40
|
+
});
|
|
41
|
+
let testruns = client.uploader.readUploadedFiles(process.env.TESTOMATIO_RUN);
|
|
42
|
+
|
|
43
|
+
const numTotalArtifacts = testruns.length;
|
|
44
|
+
|
|
45
|
+
debug('Found testruns:', testruns);
|
|
46
|
+
|
|
47
|
+
if (!opts.force) testruns = testruns.filter(tr => !tr.uploaded);
|
|
48
|
+
|
|
49
|
+
if (!testruns.length) {
|
|
50
|
+
console.log(APP_PREFIX, 'Total artifacts:', numTotalArtifacts);
|
|
51
|
+
if (numTotalArtifacts) {
|
|
52
|
+
console.log(APP_PREFIX, 'No new artifacts to upload');
|
|
53
|
+
console.log(APP_PREFIX, 'To re-upload artifacts run this command with --force flag');
|
|
54
|
+
}
|
|
55
|
+
process.exit(0);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const testrunsByRid = testruns.reduce((acc, { rid, file }) => {
|
|
59
|
+
if (!acc[rid]) {
|
|
60
|
+
acc[rid] = [];
|
|
61
|
+
}
|
|
62
|
+
if (!acc[rid].includes(file)) acc[rid].push(file);
|
|
63
|
+
return acc;
|
|
64
|
+
}, {});
|
|
65
|
+
|
|
66
|
+
// we need to obtain S3 credentials
|
|
67
|
+
await client.createRun();
|
|
68
|
+
|
|
69
|
+
client.uploader.checkEnabled();
|
|
70
|
+
client.uploader.disableLogStorage();
|
|
71
|
+
|
|
72
|
+
for (const rid in testrunsByRid) {
|
|
73
|
+
const files = testrunsByRid[rid];
|
|
74
|
+
await client.addTestRun(undefined, {
|
|
75
|
+
rid,
|
|
76
|
+
files,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log(APP_PREFIX, client.uploader.successfulUploads.length, 'artifacts uploaded');
|
|
81
|
+
if (client.uploader.failedUploads.length) {
|
|
82
|
+
console.log(APP_PREFIX, client.uploader.failedUploads.length, 'artifacts failed to upload');
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
if (process.argv.length <= 1) {
|
|
87
|
+
program.outputHelp();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
program.parse(process.argv);
|