@testomatio/reporter 1.0.16 → 1.0.18-beta.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/Changelog.md +359 -0
- package/lib/adapter/codecept.js +2 -5
- package/lib/adapter/cucumber/current.js +3 -3
- package/lib/adapter/cucumber/legacy.js +2 -2
- package/lib/adapter/jest.js +2 -16
- package/lib/adapter/mocha.js +15 -43
- package/lib/adapter/playwright.js +33 -21
- package/lib/bin/startTest.js +6 -6
- package/lib/client.js +19 -22
- package/lib/constants.js +4 -6
- package/lib/reporter-functions.js +43 -0
- package/lib/reporter.js +9 -4
- package/lib/storages/artifact-storage.js +70 -0
- package/lib/{dataStorage.js → storages/data-storage.js} +122 -47
- package/lib/storages/key-value-storage.js +58 -0
- package/lib/{logger.js → storages/logger.js} +4 -33
- package/lib/utils/utils.js +14 -0
- package/package.json +1 -1
- package/lib/_ArtifactStorageOld.js +0 -142
- package/lib/artifactStorage.js +0 -25
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const debug = require('debug')('@testomatio/reporter:logger');
|
|
3
|
-
const
|
|
3
|
+
const DataStorage = require('./data-storage');
|
|
4
4
|
|
|
5
5
|
const LOG_METHODS = ['assert', 'debug', 'error', 'info', 'log', 'trace', 'warn'];
|
|
6
6
|
const LEVELS = {
|
|
@@ -38,20 +38,6 @@ class Logger {
|
|
|
38
38
|
if (!Logger.instance) {
|
|
39
39
|
Logger.instance = this;
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
// add beforeEach hook for mocha. it does not override existing hook, just add new one
|
|
43
|
-
try {
|
|
44
|
-
// @ts-ignore
|
|
45
|
-
if (!beforeEach) return;
|
|
46
|
-
// @ts-ignore-next-line
|
|
47
|
-
beforeEach(function () {
|
|
48
|
-
if (this.currentTest?.__mocha_id__) {
|
|
49
|
-
global.testTitle = this.currentTest.fullTitle();
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
} catch (e) {
|
|
53
|
-
// ignore
|
|
54
|
-
}
|
|
55
41
|
}
|
|
56
42
|
|
|
57
43
|
/**
|
|
@@ -61,9 +47,6 @@ class Logger {
|
|
|
61
47
|
* @param {...any} values
|
|
62
48
|
*/
|
|
63
49
|
step(strings, ...values) {
|
|
64
|
-
// get testId for mocha
|
|
65
|
-
const context = global.testTitle ?? null;
|
|
66
|
-
|
|
67
50
|
let logs = '';
|
|
68
51
|
for (let i = 0; i < strings.length; i++) {
|
|
69
52
|
logs += strings[i];
|
|
@@ -72,7 +55,7 @@ class Logger {
|
|
|
72
55
|
}
|
|
73
56
|
}
|
|
74
57
|
logs = chalk.blue(`> ${logs}`);
|
|
75
|
-
this.#dataStorage.putData(logs
|
|
58
|
+
this.#dataStorage.putData(logs);
|
|
76
59
|
}
|
|
77
60
|
|
|
78
61
|
/**
|
|
@@ -117,11 +100,6 @@ class Logger {
|
|
|
117
100
|
templateLiteralLog(strings, ...args) {
|
|
118
101
|
if (Array.isArray(strings)) strings = strings.filter(item => item !== '').map(item => item.trim());
|
|
119
102
|
if (Array.isArray(args)) args = args.filter(item => item !== '');
|
|
120
|
-
// entity which is used to define testId
|
|
121
|
-
let context = null;
|
|
122
|
-
|
|
123
|
-
// get testId for mocha
|
|
124
|
-
context = global.testTitle ?? null;
|
|
125
103
|
|
|
126
104
|
let logs;
|
|
127
105
|
// this block means tagged template is used (syntax like $`text ${someVar}`)
|
|
@@ -146,7 +124,7 @@ class Logger {
|
|
|
146
124
|
logs = this.#stringifyLogs(strings, ...args);
|
|
147
125
|
}
|
|
148
126
|
this.#originalUserLogger.log(logs);
|
|
149
|
-
this.#dataStorage.putData(logs
|
|
127
|
+
this.#dataStorage.putData(logs);
|
|
150
128
|
}
|
|
151
129
|
|
|
152
130
|
/**
|
|
@@ -158,18 +136,12 @@ class Logger {
|
|
|
158
136
|
#logWrapper(argsArray, level) {
|
|
159
137
|
if (!argsArray.length) return;
|
|
160
138
|
|
|
161
|
-
// entity which is used to define testId
|
|
162
|
-
let context = null;
|
|
163
|
-
|
|
164
|
-
// get context for mocha
|
|
165
|
-
context = global.testTitle ?? null;
|
|
166
|
-
|
|
167
139
|
const severity = LEVELS[level].severity;
|
|
168
140
|
if (severity < LEVELS[this.logLevel]?.severity) return;
|
|
169
141
|
|
|
170
142
|
const logs = this.#stringifyLogs(...argsArray);
|
|
171
143
|
const colorizedLogs = chalk[LEVELS[level].color](logs);
|
|
172
|
-
this.#dataStorage.putData(colorizedLogs
|
|
144
|
+
this.#dataStorage.putData(colorizedLogs);
|
|
173
145
|
try {
|
|
174
146
|
// level.toLowerCase() represents method name (log, warn, error, etc)
|
|
175
147
|
this.#originalUserLogger[level.toLowerCase()](colorizedLogs);
|
|
@@ -269,7 +241,6 @@ class Logger {
|
|
|
269
241
|
|
|
270
242
|
Logger.instance = null;
|
|
271
243
|
|
|
272
|
-
// module.exports.Logger = Logger;
|
|
273
244
|
const logger = new Logger();
|
|
274
245
|
|
|
275
246
|
module.exports = logger;
|
package/lib/utils/utils.js
CHANGED
|
@@ -290,6 +290,19 @@ function removeColorCodes(input) {
|
|
|
290
290
|
return input.replace(/\x1b\[[0-9;]*m/g, '');
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
+
const jestHelpers = {
|
|
294
|
+
getIdOfCurrentlyRunningTest: () => {
|
|
295
|
+
if (!process.env.JEST_WORKER_ID) return null;
|
|
296
|
+
try {
|
|
297
|
+
// @ts-expect-error "expect" could only be defined inside Jest environement (forbidden to import it outside)
|
|
298
|
+
// eslint-disable-next-line no-undef
|
|
299
|
+
if (expect && expect?.getState()?.currentTestName) return parseTest(expect?.getState()?.currentTestName);
|
|
300
|
+
} catch (e) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
|
|
293
306
|
module.exports = {
|
|
294
307
|
isSameTest,
|
|
295
308
|
fetchSourceCode,
|
|
@@ -299,6 +312,7 @@ module.exports = {
|
|
|
299
312
|
fetchFilesFromStackTrace,
|
|
300
313
|
fileSystem,
|
|
301
314
|
getCurrentDateTime,
|
|
315
|
+
jestHelpers,
|
|
302
316
|
specificTestInfo,
|
|
303
317
|
isValidUrl,
|
|
304
318
|
ansiRegExp,
|
package/package.json
CHANGED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
const debug = require('debug')('@testomatio/reporter:storage');
|
|
2
|
-
const { join, resolve } = require('path');
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const os = require('os');
|
|
5
|
-
const uuid = require('uuid');
|
|
6
|
-
const { TESTOMAT_ARTIFACT_SUFFIX } = require('./constants');
|
|
7
|
-
const { specificTestInfo } = require('./utils/utils');
|
|
8
|
-
|
|
9
|
-
class ArtifactStorage {
|
|
10
|
-
|
|
11
|
-
constructor(params) {
|
|
12
|
-
this.isFile = false;
|
|
13
|
-
this.isMemory = true;
|
|
14
|
-
this.storage = params?.toFile;
|
|
15
|
-
|
|
16
|
-
if (this.storage) {
|
|
17
|
-
// this is fine to use when you start saving artifacts;
|
|
18
|
-
// but when you need to retrieve them, you will not know if there is "isFile" param,
|
|
19
|
-
// because you need to create a new instance of ArtifactStorage inside client
|
|
20
|
-
// so the solution is make it opposite to isMemory (which will be retrieved from global)
|
|
21
|
-
this.isFile = true;
|
|
22
|
-
this.isMemory = false;
|
|
23
|
-
this.tmpDirFullpath = this.createTestomatTmpDir(ArtifactStorage._tmpPrefix);
|
|
24
|
-
debug('SAVE to tmp folder mode enabled!');
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static async storeToFile(tmpDirName, artifact, testSuffix = "test") {
|
|
29
|
-
// this assumes to use multiple files for each test. do we really want this?
|
|
30
|
-
const suffix = TESTOMAT_ARTIFACT_SUFFIX + uuid.v4() + testSuffix;
|
|
31
|
-
const dirpath = join(os.tmpdir(), tmpDirName);
|
|
32
|
-
// why json?
|
|
33
|
-
const filepath = resolve(dirpath, `${suffix}.json`);
|
|
34
|
-
|
|
35
|
-
return fs.promises.appendFile(filepath, JSON.stringify(artifact));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
static async artifact(artifact, context) {
|
|
39
|
-
// TODO: mode for different pre-hooks. As variant - "all-tests" || "only_fail"
|
|
40
|
-
// const mode = process.env.TESTOMAT_ARTIFACTS || "only_fail";
|
|
41
|
-
|
|
42
|
-
// you save the artifact without specifying its source - test id
|
|
43
|
-
if (Array.isArray(global.testomatioArtifacts)) {
|
|
44
|
-
debug("Saving artifacts to global storage");
|
|
45
|
-
|
|
46
|
-
global.testomatioArtifacts.push(artifact);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (global?.testomatioArtifacts === undefined) {
|
|
50
|
-
const tmpDirNames = ArtifactStorage.tmpTestomatDirNames();
|
|
51
|
-
|
|
52
|
-
const testSuffix = specificTestInfo(context.test);
|
|
53
|
-
|
|
54
|
-
if (Array.isArray(tmpDirNames) && tmpDirNames.length) {
|
|
55
|
-
debug("Saving artifacts to memory tmp folder");
|
|
56
|
-
|
|
57
|
-
return ArtifactStorage.storeToFile(tmpDirNames[tmpDirNames.length - 1], artifact, testSuffix);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async artifactByTestName(test) {
|
|
63
|
-
const list = [];
|
|
64
|
-
|
|
65
|
-
if (this.isFile && this.tmpDirFullpath) {
|
|
66
|
-
const files = fs.readdirSync(this.tmpDirFullpath);
|
|
67
|
-
|
|
68
|
-
for (const file of files) {
|
|
69
|
-
if (file.includes(test)) {
|
|
70
|
-
const buff = await fs.promises.readFile(`${this.tmpDirFullpath }/${ file}`);
|
|
71
|
-
|
|
72
|
-
list.push(JSON.parse(buff.toString()));
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return list;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// returns all the content from all files; do we really need it?
|
|
81
|
-
async tmpContents() {
|
|
82
|
-
const contents = [];
|
|
83
|
-
|
|
84
|
-
if (this.isFile && this.tmpDirFullpath) {
|
|
85
|
-
const files = fs.readdirSync(this.tmpDirFullpath);
|
|
86
|
-
|
|
87
|
-
for (const file of files) {
|
|
88
|
-
const buff = await fs.promises.readFile(`${this.tmpDirFullpath }/${ file}`);
|
|
89
|
-
const content = buff.toString();
|
|
90
|
-
|
|
91
|
-
contents.push(content);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return contents;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
createTestomatTmpDir(clientPrefix) {
|
|
99
|
-
return fs.mkdtempSync(join(os.tmpdir(), clientPrefix));
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
clearTmpDirByName(name) {
|
|
103
|
-
const tmpDirPath = join(os.tmpdir(), name);
|
|
104
|
-
|
|
105
|
-
if (fs.existsSync(tmpDirPath)) {
|
|
106
|
-
fs.rmSync(tmpDirPath, { recursive: true });
|
|
107
|
-
debug(` Testomat tmpDir = ${tmpDirPath} was deleted successfully!`);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// no need to use multiple dirs; we can implement it later if required
|
|
114
|
-
static tmpTestomatDirNames() {
|
|
115
|
-
const subname = ArtifactStorage._tmpPrefix || "tsmt_reporter";
|
|
116
|
-
|
|
117
|
-
return fs.readdirSync(os.tmpdir(), { withFileTypes: true })
|
|
118
|
-
.filter((item) => item.isDirectory())
|
|
119
|
-
.map((item) => item.name)
|
|
120
|
-
.filter((name) => name.includes(subname));
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
cleanup() {
|
|
124
|
-
// when you do a cleanup, I know nothing about isFile param
|
|
125
|
-
if (this.isFile && this.tmpDirFullpath) {
|
|
126
|
-
const tmpDirNames = ArtifactStorage.tmpTestomatDirNames();
|
|
127
|
-
|
|
128
|
-
if (Array.isArray(tmpDirNames) && tmpDirNames.length) {
|
|
129
|
-
for (const name of tmpDirNames) {
|
|
130
|
-
this.clearTmpDirByName(name);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
debug("The tmp folder has not been created! Nothing to delete");
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
ArtifactStorage._tmpPrefix = "tsmt_reporter";
|
|
141
|
-
|
|
142
|
-
module.exports = ArtifactStorage;
|
package/lib/artifactStorage.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// const debug = require('debug')('@testomatio/reporter:logger');
|
|
2
|
-
const { DataStorage } = require('./dataStorage');
|
|
3
|
-
|
|
4
|
-
class ArtifactStorage {
|
|
5
|
-
constructor() {
|
|
6
|
-
this.dataStorage = new DataStorage('artifact');
|
|
7
|
-
|
|
8
|
-
// singleton
|
|
9
|
-
if (!ArtifactStorage.instance) {
|
|
10
|
-
ArtifactStorage.instance = this;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
save(data, context = null) {
|
|
15
|
-
this.dataStorage.putData(data, context);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
get(context) {
|
|
19
|
-
this.dataStorage.getData(context);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
ArtifactStorage.instance = null;
|
|
24
|
-
|
|
25
|
-
module.exports = new ArtifactStorage();
|