@testomatio/reporter 1.1.1-beta.1.fix-logger → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/lib/adapter/playwright.js +47 -12
- package/lib/client.js +18 -3
- package/lib/data-storage.js +2 -2
- package/lib/fileUploader.js +9 -7
- package/lib/utils/utils.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,13 +65,16 @@ yarn add @testomatio/reporter --dev
|
|
|
65
65
|
|
|
66
66
|
### 1️⃣ Attach Reporter to the Test Runner
|
|
67
67
|
|
|
68
|
+
| | | |
|
|
69
|
+
|--|--|--|
|
|
68
70
|
| [Playwright](./docs/frameworks.md#playwright) | [CodeceptJS](./docs/frameworks.md#CodeceptJS) | [Cypress](./docs/frameworks.md#Cypress) |
|
|
69
71
|
| [Jest](./docs/frameworks.md#Jest) | [Mocha](./docs/frameworks.md#Mocha) | [WebDriverIO](./docs/frameworks.md#WebDriverIO) |
|
|
70
72
|
| [TestCafe](./docs/frameworks.md#TestCafe) | [Detox](./docs/frameworks.md#Detox) | [Codeception](https://github.com/testomatio/php-reporter) |
|
|
71
73
|
| [Newman (Postman)](./docs/frameworks.md#Newman) | [JUnit](./docs/junit.md#junit) | [NUnit](./docs/junit.md#nunit) |
|
|
72
74
|
| [PyTest](./docs/junit.md#pytest) | [PHPUnit](./docs/junit.md#phpunit) | [Protractor](./docs/frameworks.md#protractor) |
|
|
73
75
|
|
|
74
|
-
|
|
76
|
+
|
|
77
|
+
or **any [other via JUnit](./docs/junit.md)** report....
|
|
75
78
|
|
|
76
79
|
### 2️⃣ Configure Reports
|
|
77
80
|
|
|
@@ -7,6 +7,8 @@ const { APP_PREFIX, STATUS: Status, TESTOMAT_TMP_STORAGE_DIR } = require('../con
|
|
|
7
7
|
const TestomatioClient = require('../client');
|
|
8
8
|
const { isArtifactsEnabled } = require('../fileUploader');
|
|
9
9
|
const { parseTest, fileSystem } = require('../utils/utils');
|
|
10
|
+
const { services } = require('../services');
|
|
11
|
+
const { dataStorage } = require('../data-storage');
|
|
10
12
|
|
|
11
13
|
const reportTestPromises = [];
|
|
12
14
|
|
|
@@ -17,14 +19,20 @@ class PlaywrightReporter {
|
|
|
17
19
|
this.uploads = [];
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
onBegin(
|
|
22
|
+
onBegin(config, suite) {
|
|
21
23
|
// clean data storage
|
|
22
24
|
fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
|
|
23
25
|
if (!this.client) return;
|
|
24
26
|
this.suite = suite;
|
|
27
|
+
this.config = config;
|
|
25
28
|
this.client.createRun();
|
|
26
29
|
}
|
|
27
30
|
|
|
31
|
+
onTestBegin(testInfo) {
|
|
32
|
+
const fullTestTitle = getTestContextName(testInfo);
|
|
33
|
+
dataStorage.setContext(fullTestTitle);
|
|
34
|
+
}
|
|
35
|
+
|
|
28
36
|
onTestEnd(test, result) {
|
|
29
37
|
if (!this.client) return;
|
|
30
38
|
|
|
@@ -34,17 +42,22 @@ class PlaywrightReporter {
|
|
|
34
42
|
|
|
35
43
|
const { error, duration } = result;
|
|
36
44
|
|
|
37
|
-
const suite_title = test.parent
|
|
45
|
+
const suite_title = test.parent
|
|
46
|
+
? test.parent?.title
|
|
47
|
+
: path.basename(test?.location?.file);
|
|
38
48
|
|
|
39
49
|
const steps = [];
|
|
40
50
|
for (const step of result.steps) {
|
|
41
51
|
appendStep(step, steps);
|
|
42
52
|
}
|
|
43
53
|
|
|
54
|
+
const fullTestTitle = getTestContextName(test);
|
|
44
55
|
let logs = '';
|
|
45
56
|
if (result.stderr.length || result.stdout.length) {
|
|
46
57
|
logs = `\n\n${chalk.bold('Logs:')}\n${chalk.red(result.stderr.join(''))}\n${result.stdout.join('')}`;
|
|
47
58
|
}
|
|
59
|
+
const manuallyAttachedArtifacts = services.artifacts.get(fullTestTitle);
|
|
60
|
+
const keyValues = services.keyValues.get(fullTestTitle);
|
|
48
61
|
|
|
49
62
|
const reportTestPromise = this.client
|
|
50
63
|
.addTestRun(checkStatus(result.status), {
|
|
@@ -55,7 +68,8 @@ class PlaywrightReporter {
|
|
|
55
68
|
steps: steps.join('\n'),
|
|
56
69
|
time: duration,
|
|
57
70
|
logs,
|
|
58
|
-
|
|
71
|
+
manuallyAttachedArtifacts,
|
|
72
|
+
meta: keyValues,
|
|
59
73
|
})
|
|
60
74
|
.then(pipes => {
|
|
61
75
|
testId = pipes?.filter(p => p.pipe.includes('Testomatio'))[0]?.result?.data?.test_id;
|
|
@@ -73,7 +87,24 @@ class PlaywrightReporter {
|
|
|
73
87
|
reportTestPromises.push(reportTestPromise);
|
|
74
88
|
}
|
|
75
89
|
|
|
76
|
-
|
|
90
|
+
|
|
91
|
+
#getArtifactPath(artifact) {
|
|
92
|
+
if (artifact.path) {
|
|
93
|
+
if (path.isAbsolute(artifact.path)) return artifact.path;
|
|
94
|
+
|
|
95
|
+
return path.join(this.config.outputDir || this.config.projects[0].outputDir, artifact.path);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (artifact.body) {
|
|
99
|
+
const fileName = tmpFile();
|
|
100
|
+
fs.writeFileSync(fileName, artifact.body);
|
|
101
|
+
return fileName;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async onEnd(result, config) {
|
|
77
108
|
if (!this.client) return;
|
|
78
109
|
|
|
79
110
|
await Promise.all(reportTestPromises);
|
|
@@ -87,11 +118,7 @@ class PlaywrightReporter {
|
|
|
87
118
|
const { title, testId, suite_title } = upload;
|
|
88
119
|
|
|
89
120
|
const files = upload.files.map(attachment => {
|
|
90
|
-
|
|
91
|
-
const fileName = tmpFile();
|
|
92
|
-
fs.writeFileSync(fileName, attachment.body);
|
|
93
|
-
}
|
|
94
|
-
return { path: attachment.path, title, type: attachment.contentType };
|
|
121
|
+
return { path: this.#getArtifactPath(attachment), title, type: attachment.contentType };
|
|
95
122
|
});
|
|
96
123
|
|
|
97
124
|
promises.push(
|
|
@@ -139,6 +166,15 @@ function tmpFile(prefix = 'tmp.') {
|
|
|
139
166
|
return path.join(tmpdir, prefix + crypto.randomBytes(16).toString('hex'));
|
|
140
167
|
}
|
|
141
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Returns filename + test title
|
|
171
|
+
* @param {*} test - testInfo object from Playwright
|
|
172
|
+
* @returns
|
|
173
|
+
*/
|
|
174
|
+
function getTestContextName(test) {
|
|
175
|
+
return `${test._requireFile || ''}_${test.title}`;
|
|
176
|
+
}
|
|
177
|
+
|
|
142
178
|
function initPlaywrightForStorage() {
|
|
143
179
|
try {
|
|
144
180
|
// @ts-ignore-next-line
|
|
@@ -146,12 +182,11 @@ function initPlaywrightForStorage() {
|
|
|
146
182
|
const { test } = require('@playwright/test');
|
|
147
183
|
// eslint-disable-next-line no-empty-pattern
|
|
148
184
|
test.beforeEach(async ({}, testInfo) => {
|
|
149
|
-
|
|
150
|
-
global.testomatioTestTitle = fullTestTitle;
|
|
185
|
+
global.testomatioTestTitle = `${testInfo.file || ''}_${testInfo.title}`;
|
|
151
186
|
});
|
|
152
187
|
} catch (e) {
|
|
153
188
|
// ignore
|
|
154
|
-
}
|
|
189
|
+
}
|
|
155
190
|
}
|
|
156
191
|
|
|
157
192
|
module.exports = PlaywrightReporter;
|
package/lib/client.js
CHANGED
|
@@ -27,6 +27,7 @@ class Client {
|
|
|
27
27
|
this.pipes = pipesFactory(params, store);
|
|
28
28
|
this.queue = Promise.resolve();
|
|
29
29
|
this.totalUploaded = 0;
|
|
30
|
+
this.failedToUpload = 0;
|
|
30
31
|
this.version = JSON.parse(fs.readFileSync(join(__dirname, '..', 'package.json')).toString()).version;
|
|
31
32
|
this.executionList = Promise.resolve();
|
|
32
33
|
|
|
@@ -163,11 +164,14 @@ class Client {
|
|
|
163
164
|
uploadedFiles.push(upload.uploadFileAsBuffer(buffer, fileName, this.uuid));
|
|
164
165
|
}
|
|
165
166
|
|
|
166
|
-
const artifacts = await Promise.all(uploadedFiles);
|
|
167
|
+
const artifacts = (await Promise.all(uploadedFiles)).filter(n => !!n);
|
|
167
168
|
|
|
168
|
-
|
|
169
|
+
if (artifacts.length < uploadedFiles.length) {
|
|
170
|
+
const failedUploading = uploadedFiles.length - artifacts.length;
|
|
171
|
+
this.failedToUpload += failedUploading;
|
|
172
|
+
}
|
|
169
173
|
|
|
170
|
-
this.totalUploaded +=
|
|
174
|
+
this.totalUploaded += artifacts.length;
|
|
171
175
|
|
|
172
176
|
const data = {
|
|
173
177
|
files,
|
|
@@ -233,6 +237,16 @@ class Client {
|
|
|
233
237
|
process.env.TESTOMATIO_PRIVATE_ARTIFACTS ? 'privately' : chalk.bold('publicly')
|
|
234
238
|
} uploaded to S3 bucket`,
|
|
235
239
|
);
|
|
240
|
+
|
|
241
|
+
if (this.failedToUpload > 0) {
|
|
242
|
+
console.log(
|
|
243
|
+
APP_PREFIX,
|
|
244
|
+
chalk.yellow(
|
|
245
|
+
`Some artifacts were not uploaded. ${this.failedToUpload} artifacts could not be uploaded. Run tests with DEBUG="@testomatio/reporter:file-uploader" to see details"`,
|
|
246
|
+
),
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
236
250
|
}
|
|
237
251
|
})
|
|
238
252
|
.catch(err => console.log(APP_PREFIX, err));
|
|
@@ -295,6 +309,7 @@ class Client {
|
|
|
295
309
|
|
|
296
310
|
function isNotInternalFrame(frame) {
|
|
297
311
|
return (
|
|
312
|
+
frame.getFileName() &&
|
|
298
313
|
frame.getFileName().includes(sep) &&
|
|
299
314
|
!frame.getFileName().includes('node_modules') &&
|
|
300
315
|
!frame.getFileName().includes('internal')
|
package/lib/data-storage.js
CHANGED
|
@@ -59,7 +59,7 @@ class DataStorage {
|
|
|
59
59
|
putData(dataType, data, context = null) {
|
|
60
60
|
if (!dataType || !data) return;
|
|
61
61
|
|
|
62
|
-
context = context || this.context || global.testomatioTestTitle || jestHelpers.
|
|
62
|
+
context = context || this.context || global.testomatioTestTitle || jestHelpers.getNameOfCurrentlyRunningTest();
|
|
63
63
|
if (!context) {
|
|
64
64
|
debug(`No context provided for "${dataType}" data:`, data);
|
|
65
65
|
return;
|
|
@@ -85,7 +85,7 @@ class DataStorage {
|
|
|
85
85
|
*/
|
|
86
86
|
getData(dataType, context) {
|
|
87
87
|
// TODO: think if it could be useful
|
|
88
|
-
// context = context || this.context || global.testomatioTestTitle || jestHelpers.
|
|
88
|
+
// context = context || this.context || global.testomatioTestTitle || jestHelpers.getNameOfCurrentlyRunningTest();
|
|
89
89
|
|
|
90
90
|
if (!context) {
|
|
91
91
|
debug(`Trying to get "${dataType}" data without context`);
|
package/lib/fileUploader.js
CHANGED
|
@@ -11,7 +11,6 @@ const readFile = util.promisify(fs.readFile);
|
|
|
11
11
|
const stat = util.promisify(fs.stat);
|
|
12
12
|
const chalk = require('chalk');
|
|
13
13
|
const { randomUUID } = require('crypto');
|
|
14
|
-
const memoize = require('lodash.memoize');
|
|
15
14
|
|
|
16
15
|
const { APP_PREFIX } = require('./constants');
|
|
17
16
|
|
|
@@ -146,8 +145,13 @@ const uploadUsingS3 = async (filePath, runId) => {
|
|
|
146
145
|
params
|
|
147
146
|
});
|
|
148
147
|
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
|
|
149
|
+
const link = await getS3LocationLink(out);
|
|
150
|
+
|
|
151
|
+
debug(`Succesfully uploaded ${filePath} => ${S3_BUCKET}/${Key} | URL: ${link}`);
|
|
152
|
+
|
|
153
|
+
return link;
|
|
154
|
+
}
|
|
151
155
|
catch (e) {
|
|
152
156
|
debug('S3 file uploading error: ', e);
|
|
153
157
|
|
|
@@ -279,8 +283,6 @@ const getS3LocationLink = async (out) => {
|
|
|
279
283
|
|
|
280
284
|
let s3Location = response?.Location;
|
|
281
285
|
|
|
282
|
-
debug('Uploaded response.Location', s3Location);
|
|
283
|
-
|
|
284
286
|
if (!s3Location) {
|
|
285
287
|
// TODO: out: a fallback case - remove after deeper testing
|
|
286
288
|
s3Location = out?.singleUploadResult?.Location;
|
|
@@ -295,8 +297,8 @@ const getS3LocationLink = async (out) => {
|
|
|
295
297
|
};
|
|
296
298
|
|
|
297
299
|
module.exports = {
|
|
298
|
-
uploadFileByPath
|
|
299
|
-
uploadFileAsBuffer
|
|
300
|
+
uploadFileByPath,
|
|
301
|
+
uploadFileAsBuffer,
|
|
300
302
|
isArtifactsEnabled,
|
|
301
303
|
resetConfig,
|
|
302
304
|
};
|
package/lib/utils/utils.js
CHANGED
|
@@ -299,7 +299,7 @@ function removeColorCodes(input) {
|
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
const jestHelpers = {
|
|
302
|
-
|
|
302
|
+
getNameOfCurrentlyRunningTest: () => {
|
|
303
303
|
if (!process.env.JEST_WORKER_ID) return null;
|
|
304
304
|
try {
|
|
305
305
|
// TODO: expect?.getState()?.testPath + ' ' + expect?.getState()?.currentTestName
|