@testomatio/reporter 1.6.0-beta-2-artifacts → 2.0.0-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.js +288 -330
- package/lib/adapter/cucumber/current.js +195 -203
- package/lib/adapter/cucumber/legacy.js +130 -155
- package/lib/adapter/cucumber.js +5 -16
- package/lib/adapter/cypress-plugin/index.js +91 -105
- package/lib/adapter/jasmine/jasmine.js +63 -0
- package/lib/adapter/jasmine.js +54 -53
- package/lib/adapter/jest.js +97 -99
- package/lib/adapter/mocha/mocha.js +125 -0
- package/lib/adapter/mocha.js +111 -140
- package/lib/adapter/playwright.js +168 -200
- package/lib/adapter/vitest.js +144 -143
- package/lib/adapter/webdriver.js +113 -97
- package/lib/bin/reportXml.js +49 -49
- package/lib/bin/startTest.js +80 -97
- package/lib/client.js +344 -385
- package/lib/config.js +16 -21
- package/lib/constants.js +49 -43
- package/lib/data-storage.js +206 -188
- package/lib/fileUploader.js +245 -0
- package/lib/junit-adapter/adapter.js +17 -20
- package/lib/junit-adapter/csharp.js +18 -14
- package/lib/junit-adapter/index.js +27 -25
- package/lib/junit-adapter/java.js +41 -53
- package/lib/junit-adapter/javascript.js +30 -27
- package/lib/junit-adapter/python.js +38 -37
- package/lib/junit-adapter/ruby.js +11 -8
- package/lib/output.js +44 -52
- package/lib/package.json +1 -0
- package/lib/pipe/bitbucket.js +208 -227
- package/lib/pipe/csv.js +111 -124
- package/lib/pipe/github.js +184 -211
- package/lib/pipe/gitlab.js +164 -205
- package/lib/pipe/html.js +253 -312
- package/lib/pipe/index.js +83 -63
- package/lib/pipe/testomatio.js +391 -454
- package/lib/reporter-functions.js +16 -20
- package/lib/reporter.js +47 -17
- package/lib/services/artifacts.js +55 -51
- package/lib/services/index.js +14 -12
- package/lib/services/key-values.js +56 -53
- package/lib/services/logger.js +227 -245
- package/lib/utils/chalk.js +10 -0
- package/lib/utils/pipe_utils.js +91 -84
- package/lib/utils/utils.js +289 -273
- package/lib/xmlReader.js +480 -519
- package/package.json +57 -19
- package/src/adapter/codecept.js +369 -0
- package/src/adapter/cucumber/current.js +228 -0
- package/src/adapter/cucumber/legacy.js +158 -0
- package/src/adapter/cucumber.js +4 -0
- package/src/adapter/cypress-plugin/index.js +110 -0
- package/src/adapter/jasmine.js +60 -0
- package/src/adapter/jest.js +107 -0
- package/src/adapter/mocha.cjs +2 -0
- package/src/adapter/mocha.js +156 -0
- package/src/adapter/playwright.js +222 -0
- package/src/adapter/vitest.js +183 -0
- package/src/adapter/webdriver.js +111 -0
- package/src/bin/reportXml.js +67 -0
- package/src/bin/startTest.js +119 -0
- package/src/client.js +423 -0
- package/src/config.js +30 -0
- package/src/constants.js +49 -0
- package/src/data-storage.js +204 -0
- package/src/fileUploader.js +307 -0
- package/src/junit-adapter/adapter.js +23 -0
- package/src/junit-adapter/csharp.js +16 -0
- package/src/junit-adapter/index.js +28 -0
- package/src/junit-adapter/java.js +58 -0
- package/src/junit-adapter/javascript.js +31 -0
- package/src/junit-adapter/python.js +42 -0
- package/src/junit-adapter/ruby.js +10 -0
- package/src/output.js +57 -0
- package/src/pipe/bitbucket.js +254 -0
- package/src/pipe/csv.js +140 -0
- package/src/pipe/github.js +234 -0
- package/src/pipe/gitlab.js +229 -0
- package/src/pipe/html.js +366 -0
- package/src/pipe/index.js +73 -0
- package/src/pipe/testomatio.js +498 -0
- package/src/reporter-functions.js +44 -0
- package/src/reporter.cjs +22 -0
- package/src/reporter.js +24 -0
- package/src/services/artifacts.js +59 -0
- package/src/services/index.js +13 -0
- package/src/services/key-values.js +59 -0
- package/src/services/logger.js +314 -0
- package/src/template/emptyData.svg +23 -0
- package/src/template/testomatio.hbs +1421 -0
- package/src/utils/chalk.js +13 -0
- package/src/utils/pipe_utils.js +127 -0
- package/src/utils/utils.js +341 -0
- package/src/xmlReader.js +551 -0
- package/lib/bin/cli.js +0 -216
- package/lib/bin/uploadArtifacts.js +0 -86
- package/lib/uploader.js +0 -312
package/lib/adapter/mocha.js
CHANGED
|
@@ -1,154 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
6
|
// eslint-disable-next-line global-require, import/no-extraneous-dependencies
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const {
|
|
11
|
-
EVENT_RUN_BEGIN,
|
|
12
|
-
EVENT_RUN_END,
|
|
13
|
-
EVENT_TEST_FAIL,
|
|
14
|
-
EVENT_TEST_PASS,
|
|
15
|
-
EVENT_TEST_PENDING,
|
|
16
|
-
EVENT_SUITE_BEGIN,
|
|
17
|
-
EVENT_SUITE_END,
|
|
18
|
-
EVENT_TEST_BEGIN,
|
|
19
|
-
EVENT_TEST_END,
|
|
20
|
-
} = Mocha.Runner.constants;
|
|
21
|
-
|
|
7
|
+
const mocha_1 = __importDefault(require("mocha"));
|
|
8
|
+
const client_js_1 = __importDefault(require("../client.js"));
|
|
9
|
+
const constants_js_1 = require("../constants.js");
|
|
10
|
+
const utils_js_1 = require("../utils/utils.js");
|
|
11
|
+
const config_js_1 = require("../config.js");
|
|
12
|
+
const index_js_1 = require("../services/index.js");
|
|
13
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
14
|
+
const { EVENT_RUN_BEGIN, EVENT_RUN_END, EVENT_TEST_FAIL, EVENT_TEST_PASS, EVENT_TEST_PENDING, EVENT_SUITE_BEGIN, EVENT_SUITE_END, EVENT_TEST_BEGIN, EVENT_TEST_END, } = mocha_1.default.Runner.constants;
|
|
22
15
|
function MochaReporter(runner, opts) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
runner.on(EVENT_RUN_BEGIN, () => {
|
|
34
|
-
client.createRun();
|
|
35
|
-
|
|
36
|
-
fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
runner.on(EVENT_SUITE_BEGIN, async suite => {
|
|
40
|
-
services.setContext(suite.fullTitle());
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
runner.on(EVENT_SUITE_END, async () => {
|
|
44
|
-
services.setContext(null);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
runner.on(EVENT_TEST_BEGIN, async test => {
|
|
48
|
-
services.setContext(test.fullTitle());
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
runner.on(EVENT_TEST_END, async () => {
|
|
52
|
-
services.setContext(null);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
runner.on(EVENT_TEST_PASS, async test => {
|
|
56
|
-
passes += 1;
|
|
57
|
-
|
|
58
|
-
console.log(chalk.bold.green('✔'), test.fullTitle());
|
|
59
|
-
const testId = getTestomatIdFromTestTitle(test.title);
|
|
60
|
-
|
|
61
|
-
const logs = getTestLogs(test);
|
|
62
|
-
const artifacts = services.artifacts.get(test.fullTitle());
|
|
63
|
-
const keyValues = services.keyValues.get(test.fullTitle());
|
|
64
|
-
|
|
65
|
-
client.addTestRun(STATUS.PASSED, {
|
|
66
|
-
test_id: testId,
|
|
67
|
-
suite_title: getSuiteTitle(test),
|
|
68
|
-
title: getTestName(test),
|
|
69
|
-
code: test.body.toString(),
|
|
70
|
-
file: getFile(test),
|
|
71
|
-
time: test.duration,
|
|
72
|
-
logs,
|
|
73
|
-
manuallyAttachedArtifacts: artifacts,
|
|
74
|
-
meta: keyValues,
|
|
16
|
+
mocha_1.default.reporters.Base.call(this, runner);
|
|
17
|
+
let passes = 0;
|
|
18
|
+
let failures = 0;
|
|
19
|
+
let skipped = 0;
|
|
20
|
+
// let artifactStore;
|
|
21
|
+
const apiKey = opts?.reporterOptions?.apiKey || config_js_1.config.TESTOMATIO;
|
|
22
|
+
const client = new client_js_1.default({ apiKey });
|
|
23
|
+
runner.on(EVENT_RUN_BEGIN, () => {
|
|
24
|
+
client.createRun();
|
|
25
|
+
utils_js_1.fileSystem.clearDir(constants_js_1.TESTOMAT_TMP_STORAGE_DIR);
|
|
75
26
|
});
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
runner.on(EVENT_TEST_PENDING, test => {
|
|
79
|
-
skipped += 1;
|
|
80
|
-
console.log('skip: %s', test.fullTitle());
|
|
81
|
-
const testId = getTestomatIdFromTestTitle(test.title);
|
|
82
|
-
client.addTestRun(STATUS.SKIPPED, {
|
|
83
|
-
title: getTestName(test),
|
|
84
|
-
suite_title: getSuiteTitle(test),
|
|
85
|
-
code: test.body.toString(),
|
|
86
|
-
file: getFile(test),
|
|
87
|
-
test_id: testId,
|
|
88
|
-
time: test.duration,
|
|
27
|
+
runner.on(EVENT_SUITE_BEGIN, async (suite) => {
|
|
28
|
+
index_js_1.services.setContext(suite.fullTitle());
|
|
89
29
|
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
30
|
+
runner.on(EVENT_SUITE_END, async () => {
|
|
31
|
+
index_js_1.services.setContext(null);
|
|
32
|
+
});
|
|
33
|
+
runner.on(EVENT_TEST_BEGIN, async (test) => {
|
|
34
|
+
index_js_1.services.setContext(test.fullTitle());
|
|
35
|
+
});
|
|
36
|
+
runner.on(EVENT_TEST_END, async () => {
|
|
37
|
+
index_js_1.services.setContext(null);
|
|
38
|
+
});
|
|
39
|
+
runner.on(EVENT_TEST_PASS, async (test) => {
|
|
40
|
+
passes += 1;
|
|
41
|
+
console.log(picocolors_1.default.bold(picocolors_1.default.green('✔')), test.fullTitle());
|
|
42
|
+
const testId = (0, utils_js_1.getTestomatIdFromTestTitle)(test.title);
|
|
43
|
+
const logs = getTestLogs(test);
|
|
44
|
+
const artifacts = index_js_1.services.artifacts.get(test.fullTitle());
|
|
45
|
+
const keyValues = index_js_1.services.keyValues.get(test.fullTitle());
|
|
46
|
+
client.addTestRun(constants_js_1.STATUS.PASSED, {
|
|
47
|
+
test_id: testId,
|
|
48
|
+
suite_title: getSuiteTitle(test),
|
|
49
|
+
title: getTestName(test),
|
|
50
|
+
code: test.body.toString(),
|
|
51
|
+
file: getFile(test),
|
|
52
|
+
time: test.duration,
|
|
53
|
+
logs,
|
|
54
|
+
manuallyAttachedArtifacts: artifacts,
|
|
55
|
+
meta: keyValues,
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
runner.on(EVENT_TEST_PENDING, test => {
|
|
59
|
+
skipped += 1;
|
|
60
|
+
console.log('skip: %s', test.fullTitle());
|
|
61
|
+
const testId = (0, utils_js_1.getTestomatIdFromTestTitle)(test.title);
|
|
62
|
+
client.addTestRun(constants_js_1.STATUS.SKIPPED, {
|
|
63
|
+
title: getTestName(test),
|
|
64
|
+
suite_title: getSuiteTitle(test),
|
|
65
|
+
code: test.body.toString(),
|
|
66
|
+
file: getFile(test),
|
|
67
|
+
test_id: testId,
|
|
68
|
+
time: test.duration,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
runner.on(EVENT_TEST_FAIL, async (test, err) => {
|
|
72
|
+
failures += 1;
|
|
73
|
+
console.log(picocolors_1.default.bold(picocolors_1.default.red('✖')), test.fullTitle(), picocolors_1.default.gray(err.message));
|
|
74
|
+
const testId = (0, utils_js_1.getTestomatIdFromTestTitle)(test.title);
|
|
75
|
+
const logs = getTestLogs(test);
|
|
76
|
+
client.addTestRun(constants_js_1.STATUS.FAILED, {
|
|
77
|
+
error: err,
|
|
78
|
+
suite_title: getSuiteTitle(test),
|
|
79
|
+
file: getFile(test),
|
|
80
|
+
test_id: testId,
|
|
81
|
+
title: getTestName(test),
|
|
82
|
+
code: test.body.toString(),
|
|
83
|
+
time: test.duration,
|
|
84
|
+
logs,
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
runner.on(EVENT_RUN_END, () => {
|
|
88
|
+
const status = failures === 0 ? constants_js_1.STATUS.PASSED : constants_js_1.STATUS.FAILED;
|
|
89
|
+
console.log(picocolors_1.default.bold(status), `${passes} passed, ${failures} failed, ${skipped} skipped`);
|
|
90
|
+
// @ts-ignore
|
|
91
|
+
client.updateRunStatus(status);
|
|
108
92
|
});
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
runner.on(EVENT_RUN_END, () => {
|
|
112
|
-
const status = failures === 0 ? STATUS.PASSED : STATUS.FAILED;
|
|
113
|
-
console.log(chalk.bold(status), `${passes} passed, ${failures} failed, ${skipped} skipped`);
|
|
114
|
-
client.updateRunStatus(status);
|
|
115
|
-
});
|
|
116
93
|
}
|
|
117
|
-
|
|
118
94
|
function getTestLogs(test) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return logs;
|
|
95
|
+
const suiteLogsArr = index_js_1.services.logger.getLogs(test.parent.fullTitle());
|
|
96
|
+
const suiteLogs = suiteLogsArr ? suiteLogsArr.join('\n').trim() : '';
|
|
97
|
+
const testLogsArr = index_js_1.services.logger.getLogs(test.fullTitle());
|
|
98
|
+
const testLogs = testLogsArr ? testLogsArr.join('\n').trim() : '';
|
|
99
|
+
let logs = '';
|
|
100
|
+
if (suiteLogs) {
|
|
101
|
+
logs += `${picocolors_1.default.bold('\t--- BeforeSuite ---')}\n${suiteLogs}`;
|
|
102
|
+
}
|
|
103
|
+
if (testLogs) {
|
|
104
|
+
logs += `\n${picocolors_1.default.bold('\t--- Test ---')}\n${testLogs}`;
|
|
105
|
+
}
|
|
106
|
+
return logs;
|
|
132
107
|
}
|
|
133
|
-
|
|
134
|
-
// To have this reporter "extend" a built-in reporter uncomment the following line:
|
|
135
|
-
Mocha.utils.inherits(MochaReporter, Mocha.reporters.Spec);
|
|
136
|
-
|
|
137
|
-
module.exports = MochaReporter;
|
|
138
|
-
|
|
139
108
|
function getSuiteTitle(test, pathArr = []) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return pathArr.filter(t => !!t)[0];
|
|
109
|
+
if (test.parent.parent)
|
|
110
|
+
getSuiteTitle(test.parent, pathArr);
|
|
111
|
+
pathArr.push(test.parent.title);
|
|
112
|
+
return pathArr.filter(t => !!t)[0];
|
|
145
113
|
}
|
|
146
|
-
|
|
147
114
|
function getFile(test) {
|
|
148
|
-
|
|
115
|
+
return test.parent.file?.replace(process.cwd(), '');
|
|
149
116
|
}
|
|
150
|
-
|
|
151
117
|
function getTestName(test) {
|
|
152
|
-
|
|
153
|
-
|
|
118
|
+
if (process.env.TESTOMATIO_CREATE === 'fulltitle')
|
|
119
|
+
return test.fullTitle();
|
|
120
|
+
return test.title;
|
|
154
121
|
}
|
|
122
|
+
// To have this reporter "extend" a built-in reporter uncomment the following line:
|
|
123
|
+
// @ts-ignore
|
|
124
|
+
mocha_1.default.utils.inherits(MochaReporter, mocha_1.default.reporters.Spec);
|
|
125
|
+
module.exports = MochaReporter;
|
|
@@ -1,226 +1,194 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.initPlaywrightForStorage = initPlaywrightForStorage;
|
|
7
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const uuid_1 = require("uuid");
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const constants_js_1 = require("../constants.js");
|
|
14
|
+
const client_js_1 = __importDefault(require("../client.js"));
|
|
15
|
+
const fileUploader_js_1 = require("../fileUploader.js");
|
|
16
|
+
const utils_js_1 = require("../utils/utils.js");
|
|
17
|
+
const index_js_1 = require("../services/index.js");
|
|
18
|
+
const data_storage_js_1 = require("../data-storage.js");
|
|
14
19
|
const reportTestPromises = [];
|
|
15
|
-
|
|
16
20
|
class PlaywrightReporter {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this.uploads = [];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
onBegin(config, suite) {
|
|
24
|
-
// clean data storage
|
|
25
|
-
fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
|
|
26
|
-
if (!this.client) return;
|
|
27
|
-
this.suite = suite;
|
|
28
|
-
this.config = config;
|
|
29
|
-
this.client.createRun();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
onTestBegin(testInfo) {
|
|
33
|
-
const fullTestTitle = getTestContextName(testInfo);
|
|
34
|
-
dataStorage.setContext(fullTestTitle);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
onTestEnd(test, result) {
|
|
38
|
-
if (!this.client) return;
|
|
39
|
-
|
|
40
|
-
const { title } = test;
|
|
41
|
-
const { error, duration } = result;
|
|
42
|
-
const suite_title = test.parent ? test.parent?.title : path.basename(test?.location?.file);
|
|
43
|
-
|
|
44
|
-
const steps = [];
|
|
45
|
-
for (const step of result.steps) {
|
|
46
|
-
const appendedStep = appendStep(step);
|
|
47
|
-
if (appendedStep) {
|
|
48
|
-
steps.push(appendedStep);
|
|
49
|
-
}
|
|
21
|
+
constructor(config = {}) {
|
|
22
|
+
this.client = new client_js_1.default({ apiKey: config?.apiKey });
|
|
23
|
+
this.uploads = [];
|
|
50
24
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
25
|
+
onBegin(config, suite) {
|
|
26
|
+
// clean data storage
|
|
27
|
+
utils_js_1.fileSystem.clearDir(constants_js_1.TESTOMAT_TMP_STORAGE_DIR);
|
|
28
|
+
if (!this.client)
|
|
29
|
+
return;
|
|
30
|
+
this.suite = suite;
|
|
31
|
+
this.config = config;
|
|
32
|
+
this.client.createRun();
|
|
56
33
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const reportTestPromise = this.client.addTestRun(checkStatus(result.status), {
|
|
62
|
-
rid,
|
|
63
|
-
error,
|
|
64
|
-
test_id: getTestomatIdFromTestTitle(`${title} ${test.tags?.join(' ')}`),
|
|
65
|
-
suite_title,
|
|
66
|
-
title,
|
|
67
|
-
steps: steps.length ? steps : undefined,
|
|
68
|
-
time: duration,
|
|
69
|
-
logs,
|
|
70
|
-
manuallyAttachedArtifacts,
|
|
71
|
-
meta: keyValues,
|
|
72
|
-
file: test.location?.file,
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
this.uploads.push({
|
|
76
|
-
rid,
|
|
77
|
-
title: test.title,
|
|
78
|
-
files: result.attachments.filter(a => a.body || a.path),
|
|
79
|
-
file: test.location?.file,
|
|
80
|
-
});
|
|
81
|
-
// remove empty uploads
|
|
82
|
-
this.uploads = this.uploads.filter(upload => upload.files.length);
|
|
83
|
-
|
|
84
|
-
reportTestPromises.push(reportTestPromise);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
#getArtifactPath(artifact) {
|
|
88
|
-
if (artifact.path) {
|
|
89
|
-
if (path.isAbsolute(artifact.path)) return artifact.path;
|
|
90
|
-
|
|
91
|
-
return path.join(this.config.outputDir || this.config.projects[0].outputDir, artifact.path);
|
|
34
|
+
onTestBegin(testInfo) {
|
|
35
|
+
const fullTestTitle = getTestContextName(testInfo);
|
|
36
|
+
data_storage_js_1.dataStorage.setContext(fullTestTitle);
|
|
92
37
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
38
|
+
onTestEnd(test, result) {
|
|
39
|
+
// test.parent.project().__projectId
|
|
40
|
+
if (!this.client)
|
|
41
|
+
return;
|
|
42
|
+
const { title } = test;
|
|
43
|
+
const { error, duration } = result;
|
|
44
|
+
const suite_title = test.parent ? test.parent?.title : path_1.default.basename(test?.location?.file);
|
|
45
|
+
const steps = [];
|
|
46
|
+
for (const step of result.steps) {
|
|
47
|
+
const appendedStep = appendStep(step);
|
|
48
|
+
if (appendedStep) {
|
|
49
|
+
steps.push(appendedStep);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const fullTestTitle = getTestContextName(test);
|
|
53
|
+
let logs = '';
|
|
54
|
+
if (result.stderr.length || result.stdout.length) {
|
|
55
|
+
logs = `\n\n${picocolors_1.default.bold('Logs:')}\n${picocolors_1.default.red(result.stderr.join(''))}\n${result.stdout.join('')}`;
|
|
56
|
+
}
|
|
57
|
+
const manuallyAttachedArtifacts = index_js_1.services.artifacts.get(fullTestTitle);
|
|
58
|
+
const keyValues = index_js_1.services.keyValues.get(fullTestTitle);
|
|
59
|
+
const rid = test.id || test.testId || (0, uuid_1.v4)();
|
|
60
|
+
const reportTestPromise = this.client.addTestRun(checkStatus(result.status), {
|
|
61
|
+
rid,
|
|
62
|
+
error,
|
|
63
|
+
test_id: (0, utils_js_1.getTestomatIdFromTestTitle)(`${title} ${test.tags?.join(' ')}`),
|
|
64
|
+
suite_title,
|
|
65
|
+
title,
|
|
66
|
+
steps: steps.length ? steps : undefined,
|
|
67
|
+
time: duration,
|
|
68
|
+
logs,
|
|
69
|
+
manuallyAttachedArtifacts,
|
|
70
|
+
meta: keyValues,
|
|
71
|
+
file: test.location?.file,
|
|
72
|
+
});
|
|
73
|
+
this.uploads.push({
|
|
74
|
+
rid,
|
|
75
|
+
title: test.title,
|
|
76
|
+
files: result.attachments.filter(a => a.body || a.path),
|
|
77
|
+
file: test.location?.file,
|
|
78
|
+
});
|
|
79
|
+
// remove empty uploads
|
|
80
|
+
this.uploads = this.uploads.filter(anUpload => anUpload.files.length);
|
|
81
|
+
reportTestPromises.push(reportTestPromise);
|
|
98
82
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
83
|
+
#getArtifactPath(artifact) {
|
|
84
|
+
if (artifact.path) {
|
|
85
|
+
if (path_1.default.isAbsolute(artifact.path))
|
|
86
|
+
return artifact.path;
|
|
87
|
+
return path_1.default.join(this.config.outputDir || this.config.projects[0].outputDir, artifact.path);
|
|
88
|
+
}
|
|
89
|
+
if (artifact.body) {
|
|
90
|
+
const fileName = tmpFile();
|
|
91
|
+
fs_1.default.writeFileSync(fileName, artifact.body);
|
|
92
|
+
return fileName;
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
async onEnd(result) {
|
|
97
|
+
if (!this.client)
|
|
98
|
+
return;
|
|
99
|
+
await Promise.all(reportTestPromises);
|
|
100
|
+
if (this.uploads.length && fileUploader_js_1.upload.isArtifactsEnabled()) {
|
|
101
|
+
console.log(constants_js_1.APP_PREFIX, `🎞️ Uploading ${this.uploads.length} files...`);
|
|
102
|
+
const promises = [];
|
|
103
|
+
for (const anUpload of this.uploads) {
|
|
104
|
+
const { rid, file, title } = anUpload;
|
|
105
|
+
const files = anUpload.files.map(attachment => ({
|
|
106
|
+
path: this.#getArtifactPath(attachment),
|
|
107
|
+
title,
|
|
108
|
+
type: attachment.contentType,
|
|
109
|
+
}));
|
|
110
|
+
promises.push(this.client.addTestRun(undefined, {
|
|
111
|
+
rid,
|
|
112
|
+
title,
|
|
113
|
+
files,
|
|
114
|
+
file,
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
await Promise.all(promises);
|
|
118
|
+
}
|
|
119
|
+
await this.client.updateRunStatus(checkStatus(result.status));
|
|
136
120
|
}
|
|
137
|
-
await Promise.all(promises);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
await this.client.updateRunStatus(checkStatus(result.status));
|
|
141
|
-
}
|
|
142
121
|
}
|
|
143
|
-
|
|
144
122
|
function checkStatus(status) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}[status] || Status.FAILED
|
|
151
|
-
);
|
|
123
|
+
return ({
|
|
124
|
+
skipped: constants_js_1.STATUS.SKIPPED,
|
|
125
|
+
timedOut: constants_js_1.STATUS.FAILED,
|
|
126
|
+
passed: constants_js_1.STATUS.PASSED,
|
|
127
|
+
}[status] || constants_js_1.STATUS.FAILED);
|
|
152
128
|
}
|
|
153
|
-
|
|
154
129
|
function appendStep(step, shift = 0) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const formattedSteps = [];
|
|
173
|
-
for (const child of step.steps || []) {
|
|
174
|
-
const appendedChild = appendStep(child, shift + 2);
|
|
175
|
-
if (appendedChild) {
|
|
176
|
-
formattedSteps.push(appendedChild);
|
|
130
|
+
// nesting too deep, ignore those steps
|
|
131
|
+
if (shift >= 10)
|
|
132
|
+
return;
|
|
133
|
+
let newCategory = step.category;
|
|
134
|
+
switch (newCategory) {
|
|
135
|
+
case 'test.step':
|
|
136
|
+
newCategory = 'user';
|
|
137
|
+
break;
|
|
138
|
+
case 'hook':
|
|
139
|
+
newCategory = 'hook';
|
|
140
|
+
break;
|
|
141
|
+
case 'attach':
|
|
142
|
+
return null; // Skip steps with category 'attach'
|
|
143
|
+
default:
|
|
144
|
+
newCategory = 'framework';
|
|
177
145
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
146
|
+
const formattedSteps = [];
|
|
147
|
+
for (const child of step.steps || []) {
|
|
148
|
+
const appendedChild = appendStep(child, shift + 2);
|
|
149
|
+
if (appendedChild) {
|
|
150
|
+
formattedSteps.push(appendedChild);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const resultStep = {
|
|
154
|
+
category: newCategory,
|
|
155
|
+
title: step.title,
|
|
156
|
+
duration: step.duration,
|
|
157
|
+
};
|
|
158
|
+
if (formattedSteps.length) {
|
|
159
|
+
resultStep.steps = formattedSteps.filter(s => !!s);
|
|
160
|
+
}
|
|
161
|
+
if (step.error !== undefined) {
|
|
162
|
+
resultStep.error = step.error;
|
|
163
|
+
}
|
|
164
|
+
return resultStep;
|
|
195
165
|
}
|
|
196
|
-
|
|
197
166
|
function tmpFile(prefix = 'tmp.') {
|
|
198
|
-
|
|
199
|
-
|
|
167
|
+
const tmpdir = os_1.default.tmpdir();
|
|
168
|
+
return path_1.default.join(tmpdir, prefix + crypto_1.default.randomBytes(16).toString('hex'));
|
|
200
169
|
}
|
|
201
|
-
|
|
202
170
|
/**
|
|
203
171
|
* Returns filename + test title
|
|
204
172
|
* @param {*} test - testInfo object from Playwright
|
|
205
173
|
* @returns
|
|
206
174
|
*/
|
|
207
175
|
function getTestContextName(test) {
|
|
208
|
-
|
|
176
|
+
return `${test._requireFile || ''}_${test.title}`;
|
|
209
177
|
}
|
|
210
|
-
|
|
211
178
|
function initPlaywrightForStorage() {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
179
|
+
try {
|
|
180
|
+
// @ts-ignore-next-line
|
|
181
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
182
|
+
const { test } = require('@playwright/test');
|
|
183
|
+
// eslint-disable-next-line no-empty-pattern
|
|
184
|
+
test.beforeEach(async ({}, testInfo) => {
|
|
185
|
+
global.testomatioTestTitle = `${testInfo.file || ''}_${testInfo.title}`;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
catch (e) {
|
|
189
|
+
// ignore
|
|
190
|
+
}
|
|
223
191
|
}
|
|
224
|
-
|
|
225
192
|
module.exports = PlaywrightReporter;
|
|
193
|
+
|
|
226
194
|
module.exports.initPlaywrightForStorage = initPlaywrightForStorage;
|