@testomatio/reporter 2.1.3-beta.3-multi-links → 2.3.0-beta.1-links
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 +5 -3
- package/lib/adapter/cucumber/current.js +2 -0
- package/lib/adapter/jest.js +2 -0
- package/lib/adapter/mocha.js +14 -0
- package/lib/adapter/playwright.js +2 -0
- package/lib/adapter/webdriver.js +8 -9
- package/lib/bin/startTest.js +38 -91
- package/lib/client.js +4 -32
- package/lib/data-storage.d.ts +4 -4
- package/lib/data-storage.js +11 -12
- package/lib/pipe/testomatio.js +3 -3
- package/lib/reporter-functions.d.ts +26 -6
- package/lib/reporter-functions.js +36 -35
- package/lib/reporter.d.ts +10 -8
- package/lib/reporter.js +9 -7
- package/lib/services/index.d.ts +2 -2
- package/lib/services/index.js +2 -2
- package/lib/services/labels.d.ts +0 -22
- package/lib/services/labels.js +0 -62
- package/lib/services/links.d.ts +1 -1
- package/lib/utils/utils.js +3 -1
- package/package.json +1 -1
- package/src/adapter/codecept.js +6 -4
- package/src/adapter/cucumber/current.js +2 -0
- package/src/adapter/jest.js +2 -0
- package/src/adapter/mocha.js +15 -0
- package/src/adapter/playwright.js +2 -0
- package/src/adapter/webdriver.js +8 -9
- package/src/bin/startTest.js +43 -114
- package/src/client.js +4 -32
- package/src/data-storage.js +11 -14
- package/src/pipe/testomatio.js +3 -3
- package/src/reporter-functions.js +36 -38
- package/src/reporter.js +8 -6
- package/src/services/index.js +2 -2
- package/src/services/labels.js +0 -58
- package/src/services/links.js +69 -0
- package/src/utils/utils.js +5 -3
- package/lib/utils/cli_utils.d.ts +0 -1
- package/lib/utils/cli_utils.js +0 -524304
package/lib/adapter/codecept.js
CHANGED
|
@@ -26,6 +26,8 @@ const HOOK_EXECUTION_ORDER = {
|
|
|
26
26
|
PRE_TEST: ['BeforeSuiteHook', 'BeforeHook'],
|
|
27
27
|
POST_TEST: ['AfterHook', 'AfterSuiteHook']
|
|
28
28
|
};
|
|
29
|
+
// codeceptjs workers are self-contained
|
|
30
|
+
data_storage_js_1.dataStorage.isFileStorage = false;
|
|
29
31
|
const DATA_REGEXP = /[|\s]+?(\{".*\}|\[.*\])/;
|
|
30
32
|
if (MAJOR_VERSION < 3) {
|
|
31
33
|
console.log('🔴 This reporter works with CodeceptJS 3+, please update your tests');
|
|
@@ -48,7 +50,6 @@ function CodeceptReporter(config) {
|
|
|
48
50
|
step: output.step,
|
|
49
51
|
say: output.say,
|
|
50
52
|
};
|
|
51
|
-
output.stepShift = 0;
|
|
52
53
|
output.debug = function (msg) {
|
|
53
54
|
originalOutput.debug(msg);
|
|
54
55
|
data_storage_js_1.dataStorage.putData('log', repeat(this?.stepShift || 0) + picocolors_1.default.cyan(msg.toString()));
|
|
@@ -62,6 +63,7 @@ function CodeceptReporter(config) {
|
|
|
62
63
|
originalOutput.log(msg);
|
|
63
64
|
data_storage_js_1.dataStorage.putData('log', repeat(this?.stepShift || 0) + picocolors_1.default.gray(msg));
|
|
64
65
|
};
|
|
66
|
+
output.stepShift = 0;
|
|
65
67
|
recorder.startUnlessRunning();
|
|
66
68
|
const hookSteps = new Map();
|
|
67
69
|
let currentHook = null;
|
|
@@ -140,7 +142,7 @@ function CodeceptReporter(config) {
|
|
|
140
142
|
const manuallyAttachedArtifacts = index_js_1.services.artifacts.get(test.fullTitle());
|
|
141
143
|
const keyValues = index_js_1.services.keyValues.get(test.fullTitle());
|
|
142
144
|
const stepHierarchy = buildUnifiedStepHierarchy(test.steps, hookSteps);
|
|
143
|
-
const
|
|
145
|
+
const links = index_js_1.services.links.get(test.fullTitle());
|
|
144
146
|
index_js_1.services.setContext(null);
|
|
145
147
|
client.addTestRun(test.state, {
|
|
146
148
|
...stripExampleFromTitle(title),
|
|
@@ -153,7 +155,7 @@ function CodeceptReporter(config) {
|
|
|
153
155
|
files,
|
|
154
156
|
steps: stepHierarchy, // Array of step objects per API schema
|
|
155
157
|
logs,
|
|
156
|
-
|
|
158
|
+
links,
|
|
157
159
|
manuallyAttachedArtifacts,
|
|
158
160
|
meta: { ...keyValues, ...test.meta },
|
|
159
161
|
});
|
|
@@ -105,6 +105,7 @@ class CucumberReporter extends cucumber_1.Formatter {
|
|
|
105
105
|
const logs = index_js_1.services.logger.getLogs(testTitle).join('\n');
|
|
106
106
|
const artifacts = index_js_1.services.artifacts.get(testTitle);
|
|
107
107
|
const keyValues = index_js_1.services.keyValues.get(testTitle);
|
|
108
|
+
const links = index_js_1.services.links.get(testTitle);
|
|
108
109
|
this.client.addTestRun(status, {
|
|
109
110
|
// error: testCaseAttempt.worstTestStepResult.message,
|
|
110
111
|
message,
|
|
@@ -114,6 +115,7 @@ class CucumberReporter extends cucumber_1.Formatter {
|
|
|
114
115
|
.trim(),
|
|
115
116
|
example: { ...example },
|
|
116
117
|
logs,
|
|
118
|
+
links,
|
|
117
119
|
manuallyAttachedArtifacts: artifacts,
|
|
118
120
|
meta: keyValues,
|
|
119
121
|
title: scenario,
|
package/lib/adapter/jest.js
CHANGED
|
@@ -57,6 +57,7 @@ class JestReporter {
|
|
|
57
57
|
const logs = getTestLogs(result);
|
|
58
58
|
const artifacts = index_js_1.services.artifacts.get(result.fullName);
|
|
59
59
|
const keyValues = index_js_1.services.keyValues.get(result.fullName);
|
|
60
|
+
const links = index_js_1.services.links.get(result.fullName);
|
|
60
61
|
const deducedStatus = status === 'pending' ? 'skipped' : status;
|
|
61
62
|
// In jest if test is not matched with test name pattern it is considered as skipped.
|
|
62
63
|
// So adding a check if it is skipped for real or because of test pattern
|
|
@@ -69,6 +70,7 @@ class JestReporter {
|
|
|
69
70
|
title,
|
|
70
71
|
time: duration,
|
|
71
72
|
logs,
|
|
73
|
+
links,
|
|
72
74
|
manuallyAttachedArtifacts: artifacts,
|
|
73
75
|
meta: keyValues,
|
|
74
76
|
});
|
package/lib/adapter/mocha.js
CHANGED
|
@@ -43,6 +43,7 @@ function MochaReporter(runner, opts) {
|
|
|
43
43
|
const logs = getTestLogs(test);
|
|
44
44
|
const artifacts = index_js_1.services.artifacts.get(test.fullTitle());
|
|
45
45
|
const keyValues = index_js_1.services.keyValues.get(test.fullTitle());
|
|
46
|
+
const links = index_js_1.services.links.get(test.fullTitle());
|
|
46
47
|
client.addTestRun(constants_js_1.STATUS.PASSED, {
|
|
47
48
|
test_id: testId,
|
|
48
49
|
suite_title: getSuiteTitle(test),
|
|
@@ -53,12 +54,16 @@ function MochaReporter(runner, opts) {
|
|
|
53
54
|
logs,
|
|
54
55
|
manuallyAttachedArtifacts: artifacts,
|
|
55
56
|
meta: keyValues,
|
|
57
|
+
links,
|
|
56
58
|
});
|
|
57
59
|
});
|
|
58
60
|
runner.on(EVENT_TEST_PENDING, test => {
|
|
59
61
|
skipped += 1;
|
|
60
62
|
console.log('skip: %s', test.fullTitle());
|
|
61
63
|
const testId = (0, utils_js_1.getTestomatIdFromTestTitle)(test.title);
|
|
64
|
+
const artifacts = index_js_1.services.artifacts.get(test.fullTitle());
|
|
65
|
+
const keyValues = index_js_1.services.keyValues.get(test.fullTitle());
|
|
66
|
+
const links = index_js_1.services.links.get(test.fullTitle());
|
|
62
67
|
client.addTestRun(constants_js_1.STATUS.SKIPPED, {
|
|
63
68
|
title: getTestName(test),
|
|
64
69
|
suite_title: getSuiteTitle(test),
|
|
@@ -66,6 +71,9 @@ function MochaReporter(runner, opts) {
|
|
|
66
71
|
file: getFile(test),
|
|
67
72
|
test_id: testId,
|
|
68
73
|
time: test.duration,
|
|
74
|
+
manuallyAttachedArtifacts: artifacts,
|
|
75
|
+
meta: keyValues,
|
|
76
|
+
links,
|
|
69
77
|
});
|
|
70
78
|
});
|
|
71
79
|
runner.on(EVENT_TEST_FAIL, async (test, err) => {
|
|
@@ -73,6 +81,9 @@ function MochaReporter(runner, opts) {
|
|
|
73
81
|
console.log(picocolors_1.default.bold(picocolors_1.default.red('✖')), test.fullTitle(), picocolors_1.default.gray(err.message));
|
|
74
82
|
const testId = (0, utils_js_1.getTestomatIdFromTestTitle)(test.title);
|
|
75
83
|
const logs = getTestLogs(test);
|
|
84
|
+
const artifacts = index_js_1.services.artifacts.get(test.fullTitle());
|
|
85
|
+
const keyValues = index_js_1.services.keyValues.get(test.fullTitle());
|
|
86
|
+
const links = index_js_1.services.links.get(test.fullTitle());
|
|
76
87
|
client.addTestRun(constants_js_1.STATUS.FAILED, {
|
|
77
88
|
error: err,
|
|
78
89
|
suite_title: getSuiteTitle(test),
|
|
@@ -82,6 +93,9 @@ function MochaReporter(runner, opts) {
|
|
|
82
93
|
code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
|
|
83
94
|
time: test.duration,
|
|
84
95
|
logs,
|
|
96
|
+
manuallyAttachedArtifacts: artifacts,
|
|
97
|
+
meta: keyValues,
|
|
98
|
+
links,
|
|
85
99
|
});
|
|
86
100
|
});
|
|
87
101
|
runner.on(EVENT_RUN_END, () => {
|
|
@@ -55,6 +55,7 @@ class PlaywrightReporter {
|
|
|
55
55
|
}
|
|
56
56
|
const manuallyAttachedArtifacts = index_js_1.services.artifacts.get(fullTestTitle);
|
|
57
57
|
const testMeta = index_js_1.services.keyValues.get(fullTestTitle);
|
|
58
|
+
const links = index_js_1.services.links.get(fullTestTitle);
|
|
58
59
|
const rid = test.id || test.testId || (0, uuid_1.v4)();
|
|
59
60
|
/**
|
|
60
61
|
* @type {{
|
|
@@ -91,6 +92,7 @@ class PlaywrightReporter {
|
|
|
91
92
|
steps: steps.length ? steps : undefined,
|
|
92
93
|
time: duration,
|
|
93
94
|
logs,
|
|
95
|
+
links,
|
|
94
96
|
manuallyAttachedArtifacts,
|
|
95
97
|
meta: {
|
|
96
98
|
browser: project.browser,
|
package/lib/adapter/webdriver.js
CHANGED
|
@@ -77,12 +77,10 @@ class WebdriverReporter extends reporter_1.default {
|
|
|
77
77
|
onTestEnd(test) {
|
|
78
78
|
test.suite = test.parent;
|
|
79
79
|
const logs = getTestLogs(test.fullTitle);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
test.artifacts = index_js_1.services.artifacts.get(test.fullTitle);
|
|
81
|
+
test.meta = index_js_1.services.keyValues.get(test.fullTitle);
|
|
82
|
+
test.links = index_js_1.services.links.get(test.fullTitle);
|
|
83
83
|
test.logs = logs;
|
|
84
|
-
// test.artifacts = artifacts;
|
|
85
|
-
// test.meta = keyValues;
|
|
86
84
|
this._addTestPromises.push(this.addTest(test));
|
|
87
85
|
}
|
|
88
86
|
// wdio-cucumber does not trigger onTestEnd hook, thus, using this one
|
|
@@ -94,7 +92,7 @@ class WebdriverReporter extends reporter_1.default {
|
|
|
94
92
|
async addTest(test) {
|
|
95
93
|
if (!this.client)
|
|
96
94
|
return;
|
|
97
|
-
const { title, _duration: duration, state, error, output } = test;
|
|
95
|
+
const { title, _duration: duration, state, error, output, links, artifacts, meta, logs } = test;
|
|
98
96
|
const testId = (0, utils_js_1.getTestomatIdFromTestTitle)(title);
|
|
99
97
|
const screenshotEndpoint = '/session/:sessionId/screenshot';
|
|
100
98
|
const screenshotsBuffers = output
|
|
@@ -102,10 +100,11 @@ class WebdriverReporter extends reporter_1.default {
|
|
|
102
100
|
.map(el => Buffer.from(el.result.value, 'base64'));
|
|
103
101
|
await this.client.addTestRun(state, {
|
|
104
102
|
rid: test.uid || '',
|
|
105
|
-
manuallyAttachedArtifacts:
|
|
103
|
+
manuallyAttachedArtifacts: artifacts,
|
|
106
104
|
error,
|
|
107
|
-
logs
|
|
108
|
-
meta
|
|
105
|
+
logs,
|
|
106
|
+
meta,
|
|
107
|
+
links,
|
|
109
108
|
title,
|
|
110
109
|
test_id: testId,
|
|
111
110
|
time: duration,
|
package/lib/bin/startTest.js
CHANGED
|
@@ -4,103 +4,50 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const picocolors_1 = __importDefault(require("picocolors"));
|
|
10
|
-
const client_js_1 = __importDefault(require("../client.js"));
|
|
11
|
-
const constants_js_1 = require("../constants.js");
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
12
9
|
const utils_js_1 = require("../utils/utils.js");
|
|
13
|
-
const
|
|
14
|
-
|
|
10
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
11
|
+
// Define __dirname - this will be replaced by build script with actual __dirname for CommonJS
|
|
12
|
+
const cliPath = (0, node_path_1.join)(__dirname, 'cli.js');
|
|
15
13
|
const version = (0, utils_js_1.getPackageVersion)();
|
|
16
14
|
console.log(picocolors_1.default.cyan(picocolors_1.default.bold(` 🤩 Testomat.io Reporter v${version}`)));
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
dotenv_1.default.config({ path: opts.envFile });
|
|
29
|
-
const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config_js_1.config.TESTOMATIO;
|
|
30
|
-
const title = process.env.TESTOMATIO_TITLE;
|
|
31
|
-
if (launch) {
|
|
32
|
-
console.log('Starting a new Run on Testomat.io...');
|
|
33
|
-
const client = new client_js_1.default({ apiKey });
|
|
34
|
-
client.createRun().then(() => {
|
|
35
|
-
console.log(process.env.runId);
|
|
36
|
-
process.exit(0);
|
|
37
|
-
});
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
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
|
|
43
|
-
if (!process.env.TESTOMATIO_RUN) {
|
|
44
|
-
console.log('TESTOMATIO_RUN environment variable must be set.');
|
|
45
|
-
return process.exit(1);
|
|
15
|
+
// Parse command line arguments to map start-test-run options to @testomatio/reporter run format
|
|
16
|
+
const args = process.argv.slice(2);
|
|
17
|
+
const newArgs = ['run'];
|
|
18
|
+
let i = 0;
|
|
19
|
+
while (i < args.length) {
|
|
20
|
+
const arg = args[i];
|
|
21
|
+
if (arg === '-c' || arg === '--command') {
|
|
22
|
+
// Map -c/--command to positional argument for run command
|
|
23
|
+
i++;
|
|
24
|
+
if (i < args.length) {
|
|
25
|
+
newArgs.push(args[i]);
|
|
46
26
|
}
|
|
47
|
-
console.log('Finishing Run on Testomat.io...');
|
|
48
|
-
const client = new client_js_1.default({ apiKey });
|
|
49
|
-
// @ts-ignore
|
|
50
|
-
client.updateRunStatus(constants_js_1.STATUS.FINISHED).then(() => {
|
|
51
|
-
console.log(picocolors_1.default.yellow(`Run ${process.env.TESTOMATIO_RUN} was finished`));
|
|
52
|
-
process.exit(0);
|
|
53
|
-
});
|
|
54
|
-
return;
|
|
55
27
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return;
|
|
28
|
+
else if (arg.startsWith('--command=')) {
|
|
29
|
+
// Handle --command=value format
|
|
30
|
+
const command = arg.split('=', 2)[1];
|
|
31
|
+
newArgs.push(command);
|
|
61
32
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const pipeOptions = optsArray.join(':');
|
|
66
|
-
try {
|
|
67
|
-
const tests = await client.prepareRun({ pipe, pipeOptions });
|
|
68
|
-
if (!tests || tests.length === 0) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
const grep = ` --grep (${tests.join('|')})`;
|
|
72
|
-
command += grep;
|
|
73
|
-
}
|
|
74
|
-
catch (err) {
|
|
75
|
-
console.log(constants_js_1.APP_PREFIX, err);
|
|
76
|
-
}
|
|
33
|
+
else if (arg === '--launch') {
|
|
34
|
+
// Map --launch to start command
|
|
35
|
+
newArgs[0] = 'start';
|
|
77
36
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const cmd = (0, cross_spawn_1.spawn)(testCmds[0], testCmds.slice(1), { stdio: 'inherit' });
|
|
82
|
-
cmd.on('close', code => {
|
|
83
|
-
console.log(constants_js_1.APP_PREFIX, '⚠️ ', `Runner exited with ${picocolors_1.default.bold(code)}, report is ignored`);
|
|
84
|
-
if (code > exitCode)
|
|
85
|
-
exitCode = code;
|
|
86
|
-
process.exitCode = exitCode;
|
|
87
|
-
});
|
|
88
|
-
return;
|
|
37
|
+
else if (arg === '--finish') {
|
|
38
|
+
// Map --finish to finish command
|
|
39
|
+
newArgs[0] = 'finish';
|
|
89
40
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const status = code === 0 ? 'passed' : 'failed';
|
|
96
|
-
client.updateRunStatus(status, true);
|
|
97
|
-
if (code > exitCode)
|
|
98
|
-
exitCode = code;
|
|
99
|
-
process.exitCode = exitCode;
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
if (process.argv.length <= 2) {
|
|
104
|
-
program.outputHelp();
|
|
41
|
+
else {
|
|
42
|
+
// Pass through other arguments
|
|
43
|
+
newArgs.push(arg);
|
|
44
|
+
}
|
|
45
|
+
i++;
|
|
105
46
|
}
|
|
106
|
-
|
|
47
|
+
// Execute the main CLI with mapped arguments
|
|
48
|
+
const child = (0, node_child_process_1.spawn)(process.execPath, [cliPath, ...newArgs], {
|
|
49
|
+
stdio: 'inherit'
|
|
50
|
+
});
|
|
51
|
+
child.on('exit', (code) => {
|
|
52
|
+
process.exit(code);
|
|
53
|
+
});
|
package/lib/client.js
CHANGED
|
@@ -181,46 +181,18 @@ class Client {
|
|
|
181
181
|
/**
|
|
182
182
|
* @type {TestData}
|
|
183
183
|
*/
|
|
184
|
-
const { rid, error = null, time = 0, example = null, files = [], filesBuffers = [], steps, code = null, title, file, suite_title, suite_id, test_id, timestamp,
|
|
184
|
+
const { rid, error = null, time = 0, example = null, files = [], filesBuffers = [], steps, code = null, title, file, suite_title, suite_id, test_id, timestamp, links, manuallyAttachedArtifacts, overwrite, } = testData;
|
|
185
185
|
let { message = '', meta = {} } = testData;
|
|
186
186
|
// stringify meta values and limit keys and values length to 255
|
|
187
187
|
meta = Object.entries(meta)
|
|
188
188
|
.filter(([, value]) => value !== null && value !== undefined)
|
|
189
|
-
.map(([key, value]) => {
|
|
190
|
-
try {
|
|
191
|
-
if (typeof value === 'object') {
|
|
192
|
-
value = JSON.stringify(value);
|
|
193
|
-
}
|
|
194
|
-
else if (typeof value !== 'string') {
|
|
195
|
-
try {
|
|
196
|
-
value = value.toString();
|
|
197
|
-
}
|
|
198
|
-
catch (err) {
|
|
199
|
-
console.warn(constants_js_1.APP_PREFIX, `Can't convert meta value to string`, err);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
if (value?.length > 255) {
|
|
203
|
-
value = value.substring(0, 255);
|
|
204
|
-
debug(constants_js_1.APP_PREFIX, `Meta info value "${value}" is too long, trimmed to 255 characters`);
|
|
205
|
-
}
|
|
206
|
-
if (key?.length > 255) {
|
|
207
|
-
const newKey = key.substring(0, 255);
|
|
208
|
-
debug(constants_js_1.APP_PREFIX, `Meta info key "${key}" is too long, trimmed to 255 characters`);
|
|
209
|
-
return [newKey, value];
|
|
210
|
-
}
|
|
211
|
-
return [key, value];
|
|
212
|
-
}
|
|
213
|
-
catch (err) {
|
|
214
|
-
debug(constants_js_1.APP_PREFIX, `Error while processing meta info key ${key}`, err);
|
|
215
|
-
return [null, null];
|
|
216
|
-
}
|
|
217
|
-
})
|
|
218
189
|
.reduce((acc, [key, value]) => {
|
|
219
190
|
if (key)
|
|
220
191
|
acc[key] = value;
|
|
221
192
|
return acc;
|
|
222
193
|
}, {});
|
|
223
|
-
//
|
|
194
|
+
// Get links from storage using the test context
|
|
195
|
+
const testContext = suite_title ? `${suite_title} ${title}` : title;
|
|
224
196
|
let errorFormatted = '';
|
|
225
197
|
if (error) {
|
|
226
198
|
errorFormatted += this.formatError(error) || '';
|
|
@@ -268,7 +240,7 @@ class Client {
|
|
|
268
240
|
timestamp,
|
|
269
241
|
artifacts,
|
|
270
242
|
meta,
|
|
271
|
-
|
|
243
|
+
links,
|
|
272
244
|
overwrite,
|
|
273
245
|
...(rootSuiteId && { root_suite_id: rootSuiteId }),
|
|
274
246
|
};
|
package/lib/data-storage.d.ts
CHANGED
|
@@ -12,22 +12,22 @@ declare class DataStorage {
|
|
|
12
12
|
/**
|
|
13
13
|
* Puts any data to storage (file or global variable).
|
|
14
14
|
* If file: stores data as text, if global variable – stores as array of data.
|
|
15
|
-
* @param {'log' | 'artifact' | 'keyvalue' | '
|
|
15
|
+
* @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
|
|
16
16
|
* @param {*} data anything you want to store (string, object, array, etc)
|
|
17
17
|
* @param {*} context could be testId or any context (test name, suite name, including their IDs etc)
|
|
18
18
|
* suite name + test name is used by default
|
|
19
19
|
* @returns
|
|
20
20
|
*/
|
|
21
|
-
putData(dataType: "log" | "artifact" | "keyvalue" | "
|
|
21
|
+
putData(dataType: "log" | "artifact" | "keyvalue" | "links", data: any, context?: any): void;
|
|
22
22
|
/**
|
|
23
23
|
* Returns data, stored for specific test/context (or data which was stored without test id specified).
|
|
24
24
|
* This method will get data from global variable and/or from from file (previosly saved with put method).
|
|
25
25
|
*
|
|
26
|
-
* @param {'log' | 'artifact' | 'keyvalue' | '
|
|
26
|
+
* @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
|
|
27
27
|
* @param {string} context
|
|
28
28
|
* @returns {any []} array of data (any type), null (if no data found for context) or string (if data type is log)
|
|
29
29
|
*/
|
|
30
|
-
getData(dataType: "log" | "artifact" | "keyvalue" | "
|
|
30
|
+
getData(dataType: "log" | "artifact" | "keyvalue" | "links", context: string): any[];
|
|
31
31
|
#private;
|
|
32
32
|
}
|
|
33
33
|
export function stringToMD5Hash(str: any): string;
|
package/lib/data-storage.js
CHANGED
|
@@ -45,7 +45,6 @@ const os_1 = __importDefault(require("os"));
|
|
|
45
45
|
const constants_js_1 = require("./constants.js");
|
|
46
46
|
const utils_js_1 = require("./utils/utils.js");
|
|
47
47
|
const crypto_1 = __importDefault(require("crypto"));
|
|
48
|
-
const startTime = Date.now();
|
|
49
48
|
const debug = (0, debug_1.default)('@testomatio/reporter:storage');
|
|
50
49
|
class DataStorage {
|
|
51
50
|
static #instance;
|
|
@@ -76,7 +75,7 @@ class DataStorage {
|
|
|
76
75
|
/**
|
|
77
76
|
* Puts any data to storage (file or global variable).
|
|
78
77
|
* If file: stores data as text, if global variable – stores as array of data.
|
|
79
|
-
* @param {'log' | 'artifact' | 'keyvalue' | '
|
|
78
|
+
* @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
|
|
80
79
|
* @param {*} data anything you want to store (string, object, array, etc)
|
|
81
80
|
* @param {*} context could be testId or any context (test name, suite name, including their IDs etc)
|
|
82
81
|
* suite name + test name is used by default
|
|
@@ -104,7 +103,7 @@ class DataStorage {
|
|
|
104
103
|
* Returns data, stored for specific test/context (or data which was stored without test id specified).
|
|
105
104
|
* This method will get data from global variable and/or from from file (previosly saved with put method).
|
|
106
105
|
*
|
|
107
|
-
* @param {'log' | 'artifact' | 'keyvalue' | '
|
|
106
|
+
* @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
|
|
108
107
|
* @param {string} context
|
|
109
108
|
* @returns {any []} array of data (any type), null (if no data found for context) or string (if data type is log)
|
|
110
109
|
*/
|
|
@@ -135,7 +134,7 @@ class DataStorage {
|
|
|
135
134
|
return null;
|
|
136
135
|
}
|
|
137
136
|
/**
|
|
138
|
-
* @param {'log' | 'artifact' | 'keyvalue' | '
|
|
137
|
+
* @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
|
|
139
138
|
* @param {string} context
|
|
140
139
|
* @returns aray of data (any type)
|
|
141
140
|
*/
|
|
@@ -144,7 +143,7 @@ class DataStorage {
|
|
|
144
143
|
if (global?.testomatioDataStore[dataType]) {
|
|
145
144
|
const testData = global.testomatioDataStore[dataType][context];
|
|
146
145
|
if (testData)
|
|
147
|
-
debug(
|
|
146
|
+
debug('<=', dataType, 'global', context, testData);
|
|
148
147
|
return testData || [];
|
|
149
148
|
}
|
|
150
149
|
// debug(`No ${this.dataType} data for context ${context} in <global> storage`);
|
|
@@ -155,7 +154,7 @@ class DataStorage {
|
|
|
155
154
|
}
|
|
156
155
|
}
|
|
157
156
|
/**
|
|
158
|
-
* @param {'log' | 'artifact' | 'keyvalue' | '
|
|
157
|
+
* @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
|
|
159
158
|
* @param {*} context
|
|
160
159
|
* @returns array of data (any type)
|
|
161
160
|
*/
|
|
@@ -166,7 +165,7 @@ class DataStorage {
|
|
|
166
165
|
if (fs_1.default.existsSync(filepath)) {
|
|
167
166
|
const testDataAsText = fs_1.default.readFileSync(filepath, 'utf-8');
|
|
168
167
|
if (testDataAsText)
|
|
169
|
-
debug(
|
|
168
|
+
debug('<=', dataType, 'file', context, testDataAsText);
|
|
170
169
|
const testDataArr = testDataAsText?.split(os_1.default.EOL) || [];
|
|
171
170
|
return testDataArr;
|
|
172
171
|
}
|
|
@@ -180,12 +179,12 @@ class DataStorage {
|
|
|
180
179
|
}
|
|
181
180
|
/**
|
|
182
181
|
* Puts data to global variable. Unlike the file storage, stores data in array (file storage just append as string).
|
|
183
|
-
* @param {'log' | 'artifact' | 'keyvalue' | '
|
|
182
|
+
* @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
|
|
184
183
|
* @param {*} data
|
|
185
184
|
* @param {*} context
|
|
186
185
|
*/
|
|
187
186
|
#putDataToGlobalVar(dataType, data, context) {
|
|
188
|
-
debug('
|
|
187
|
+
debug('=>', dataType, 'global', context, data);
|
|
189
188
|
if (!global.testomatioDataStore)
|
|
190
189
|
global.testomatioDataStore = {};
|
|
191
190
|
if (!global.testomatioDataStore?.[dataType])
|
|
@@ -196,7 +195,7 @@ class DataStorage {
|
|
|
196
195
|
}
|
|
197
196
|
/**
|
|
198
197
|
* Puts data to file. Unlike the global variable storage, stores data as string
|
|
199
|
-
* @param {'log' | 'artifact' | 'keyvalue' | '
|
|
198
|
+
* @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
|
|
200
199
|
* @param {*} data
|
|
201
200
|
* @param {string} context
|
|
202
201
|
* @returns
|
|
@@ -209,7 +208,7 @@ class DataStorage {
|
|
|
209
208
|
const filepath = (0, path_1.join)(dataDirPath, filename);
|
|
210
209
|
if (!fs_1.default.existsSync(dataDirPath))
|
|
211
210
|
utils_js_1.fileSystem.createDir(dataDirPath);
|
|
212
|
-
debug(
|
|
211
|
+
debug('=>', dataType, 'file', context, data);
|
|
213
212
|
// append new line if file already exists (in this case its definitely includes some data)
|
|
214
213
|
if (fs_1.default.existsSync(filepath)) {
|
|
215
214
|
fs_1.default.appendFileSync(filepath, os_1.default.EOL + data, 'utf-8');
|
|
@@ -223,7 +222,7 @@ function stringToMD5Hash(str) {
|
|
|
223
222
|
const md5 = crypto_1.default.createHash('md5');
|
|
224
223
|
md5.update(str);
|
|
225
224
|
const hash = md5.digest('hex');
|
|
226
|
-
return `${
|
|
225
|
+
return `${process.env.runId || 'run'}_${hash}`;
|
|
227
226
|
}
|
|
228
227
|
exports.dataStorage = DataStorage.getInstance();
|
|
229
228
|
// TODO: consider using fs promises instead of writeSync/appendFileSync to
|
package/lib/pipe/testomatio.js
CHANGED
|
@@ -113,8 +113,7 @@ class TestomatioPipe {
|
|
|
113
113
|
const resp = await this.client.request({
|
|
114
114
|
method: 'GET',
|
|
115
115
|
url: '/api/test_grep',
|
|
116
|
-
|
|
117
|
-
responseType: q.responseType
|
|
116
|
+
...q,
|
|
118
117
|
});
|
|
119
118
|
if (Array.isArray(resp.data?.tests) && resp.data?.tests?.length > 0) {
|
|
120
119
|
(0, utils_js_1.foundedTestLog)(constants_js_1.APP_PREFIX, resp.data.tests);
|
|
@@ -173,7 +172,8 @@ class TestomatioPipe {
|
|
|
173
172
|
const resp = await this.client.request({
|
|
174
173
|
method: 'PUT',
|
|
175
174
|
url: `/api/reporter/${this.runId}`,
|
|
176
|
-
data: runParams
|
|
175
|
+
data: runParams,
|
|
176
|
+
responseType: 'json'
|
|
177
177
|
});
|
|
178
178
|
if (resp.data.artifacts)
|
|
179
179
|
(0, pipe_utils_js_1.setS3Credentials)(resp.data.artifacts);
|
|
@@ -4,11 +4,15 @@ declare namespace _default {
|
|
|
4
4
|
export { addStep as step };
|
|
5
5
|
export { setKeyValue as keyValue };
|
|
6
6
|
export { setLabel as label };
|
|
7
|
+
export { linkTest };
|
|
8
|
+
export { linkJira };
|
|
7
9
|
}
|
|
8
10
|
export default _default;
|
|
9
11
|
/**
|
|
10
12
|
* Stores path to file as artifact and uploads it to the S3 storage
|
|
11
13
|
* @param {string | {path: string, type: string, name: string}} data - path to file or object with path, type and name
|
|
14
|
+
* @param {any} [context=null] - optional context parameter
|
|
15
|
+
* @returns {void}
|
|
12
16
|
*/
|
|
13
17
|
declare function saveArtifact(data: string | {
|
|
14
18
|
path: string;
|
|
@@ -17,18 +21,21 @@ declare function saveArtifact(data: string | {
|
|
|
17
21
|
}, context?: any): void;
|
|
18
22
|
/**
|
|
19
23
|
* Attach log message(s) to the test report
|
|
20
|
-
* @param
|
|
24
|
+
* @param {...any} args - log messages to attach
|
|
25
|
+
* @returns {void}
|
|
21
26
|
*/
|
|
22
27
|
declare function logMessage(...args: any[]): void;
|
|
23
28
|
/**
|
|
24
29
|
* Similar to "log" function but marks message in report as a step
|
|
25
|
-
* @param {string} message
|
|
30
|
+
* @param {string} message - step message
|
|
31
|
+
* @returns {void}
|
|
26
32
|
*/
|
|
27
33
|
declare function addStep(message: string): void;
|
|
28
34
|
/**
|
|
29
35
|
* Add key-value pair(s) to the test report
|
|
30
|
-
* @param {{[key: string]: string} | string} keyValue object { key: value } (multiple props allowed) or key (string)
|
|
31
|
-
* @param {string
|
|
36
|
+
* @param {{[key: string]: string} | string} keyValue - object { key: value } (multiple props allowed) or key (string)
|
|
37
|
+
* @param {string|null} [value=null] - optional value when keyValue is a string
|
|
38
|
+
* @returns {void}
|
|
32
39
|
*/
|
|
33
40
|
declare function setKeyValue(keyValue: {
|
|
34
41
|
[key: string]: string;
|
|
@@ -36,6 +43,19 @@ declare function setKeyValue(keyValue: {
|
|
|
36
43
|
/**
|
|
37
44
|
* Add a single label to the test report
|
|
38
45
|
* @param {string} key - label key (e.g. 'severity', 'feature', or just 'smoke' for labels without values)
|
|
39
|
-
* @param {string} [value] - optional label value (e.g. 'high', 'login')
|
|
46
|
+
* @param {string|null} [value=null] - optional label value (e.g. 'high', 'login')
|
|
47
|
+
* @returns {void}
|
|
40
48
|
*/
|
|
41
|
-
declare function setLabel(key: string, value?: string): void;
|
|
49
|
+
declare function setLabel(key: string, value?: string | null): void;
|
|
50
|
+
/**
|
|
51
|
+
* Add link(s) to the test report
|
|
52
|
+
* @param {...string} testIds - test IDs to link
|
|
53
|
+
* @returns {void}
|
|
54
|
+
*/
|
|
55
|
+
declare function linkTest(...testIds: string[]): void;
|
|
56
|
+
/**
|
|
57
|
+
* Add JIRA issue link(s) to the test report
|
|
58
|
+
* @param {...string} jiraIds - JIRA issue IDs to link
|
|
59
|
+
* @returns {void}
|
|
60
|
+
*/
|
|
61
|
+
declare function linkJira(...jiraIds: string[]): void;
|