@testomatio/reporter 1.1.0-beta.mocha-create.9 → 1.1.1-beta-codecept-logger
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 +67 -4
- package/lib/adapter/mocha.js +54 -35
- package/lib/client.js +46 -43
- package/lib/pipe/testomatio.js +1 -2
- package/lib/reporter-functions.js +16 -5
- package/lib/reporter.js +2 -1
- package/lib/storages/artifact-storage.js +21 -12
- package/lib/storages/data-storage.js +48 -185
- package/lib/storages/key-value-storage.js +25 -10
- package/lib/storages/logger.js +46 -16
- package/lib/utils/utils.js +0 -14
- package/package.json +1 -1
- package/Changelog.md +0 -367
|
@@ -4,225 +4,108 @@ const path = require('path');
|
|
|
4
4
|
const os = require('os');
|
|
5
5
|
const { join } = require('path');
|
|
6
6
|
const { TESTOMAT_TMP_STORAGE_DIR } = require('../constants');
|
|
7
|
-
const { fileSystem
|
|
8
|
-
|
|
9
|
-
const getTestIdFromTestTitle = parseTest;
|
|
7
|
+
const { fileSystem } = require('../utils/utils');
|
|
10
8
|
|
|
11
9
|
class DataStorage {
|
|
12
10
|
/**
|
|
13
11
|
* Creates data storage instance for specific data type.
|
|
14
12
|
* Stores data to global variable or to file depending on what is applicable for current test runner
|
|
15
|
-
* (running environment).
|
|
16
13
|
* Recommend to use composition while using this class (instead of inheritance).
|
|
17
14
|
* ! Also the class which will use data storage should be singleton (to avoid data loss).
|
|
18
|
-
*
|
|
15
|
+
* But the data storage itself is not singleton. It will have an instance per data type.
|
|
16
|
+
* @param {'log' | 'artifact' | 'keyvalue'} dataType – type of data to store
|
|
19
17
|
*/
|
|
20
18
|
constructor(dataType) {
|
|
21
19
|
this.dataType = dataType || 'data';
|
|
20
|
+
|
|
21
|
+
// some frameworks use global variable to store data, some use file storage
|
|
22
22
|
this.isFileStorage = true;
|
|
23
|
-
this.#refreshStorageType();
|
|
24
23
|
|
|
25
24
|
this.dataDirPath = path.join(TESTOMAT_TMP_STORAGE_DIR, this.dataType);
|
|
26
|
-
|
|
27
|
-
// set test title for mocha (could not be moved to adapter)
|
|
28
|
-
// it does not override existing hook, just add new one
|
|
29
|
-
try {
|
|
30
|
-
// @ts-ignore
|
|
31
|
-
if (!beforeEach) return;
|
|
32
|
-
// @ts-ignore-next-line
|
|
33
|
-
beforeEach(function () {
|
|
34
|
-
if (this.currentTest?.__mocha_id__) {
|
|
35
|
-
global.testTitle = this.currentTest.fullTitle();
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
} catch (e) {
|
|
39
|
-
// ignore
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// set test title for playwright
|
|
43
|
-
try {
|
|
44
|
-
// eslint-disable-next-line import/no-extraneous-dependencies, import/no-unresolved
|
|
45
|
-
const { test } = require('@playwright/test');
|
|
46
|
-
// eslint-disable-next-line no-empty-pattern
|
|
47
|
-
test.beforeEach(async ({}, testInfo) => {
|
|
48
|
-
global.testTitle = testInfo.title;
|
|
49
|
-
global.testomatioRunningEnvironment = 'playwright';
|
|
50
|
-
});
|
|
51
|
-
} catch (e) {
|
|
52
|
-
// ignore
|
|
53
|
-
}
|
|
54
25
|
}
|
|
55
26
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (global.codeceptjs) return 'codeceptjs';
|
|
65
|
-
|
|
66
|
-
// 'cucumber:current', 'cucumber:legacy'
|
|
67
|
-
if (global.testomatioRunningEnvironment) return global.testomatioRunningEnvironment;
|
|
68
|
-
|
|
69
|
-
if (process.env.PLAYWRIGHT_TEST_BASE_URL || process.env.TEST_WORKER_INDEX) return 'playwright';
|
|
70
|
-
|
|
71
|
-
// mocha - can't detect
|
|
72
|
-
return null;
|
|
27
|
+
#stringToFilename(str) {
|
|
28
|
+
// TODO: use md5 hash later
|
|
29
|
+
const validFilenameRegex = /[^a-zA-Z0-9_.-]/g;
|
|
30
|
+
// replace all characters not in the regex above with underscore, then duplicate underscores removed
|
|
31
|
+
let filename = str.replace(validFilenameRegex, '_').replace(/_{2,}/g, '_').substring(0, 255); // max filename length
|
|
32
|
+
// remove leading and trailing underscores
|
|
33
|
+
filename = filename.replace(/^_+|_+$/g, '');
|
|
34
|
+
return filename;
|
|
73
35
|
}
|
|
74
36
|
|
|
75
37
|
/**
|
|
76
38
|
* Puts any data to storage (file or global variable).
|
|
77
39
|
* If file: stores data as text, if global variable – stores as array of data.
|
|
78
40
|
* @param {*} data anything you want to store (string, object, array, etc)
|
|
79
|
-
* @param {*} context could be testId or any context (test, suite,
|
|
41
|
+
* @param {*} context could be testId or any context (test name, suite name, including their IDs etc)
|
|
42
|
+
* suite name + test name is used by default
|
|
80
43
|
* @returns
|
|
81
44
|
*/
|
|
82
45
|
putData(data, context = null) {
|
|
83
46
|
fileSystem.createDir(this.dataDirPath);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
context = context ?? global.testTitle ?? null;
|
|
87
|
-
let testId = this.#tryToRetrieveTestId(context) || context || null;
|
|
88
|
-
|
|
89
|
-
if (this.runningEnvironment === 'codeceptjs') {
|
|
90
|
-
this.isFileStorage = false;
|
|
91
|
-
testId = testId ?? global.testomatioDataStore?.currentlyRunningTestId;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (this.runningEnvironment === 'jest') {
|
|
95
|
-
testId = testId ?? jestHelpers.getIdOfCurrentlyRunningTest();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// logs in playwright are gathered by pw framework itself
|
|
99
|
-
if (this.runningEnvironment === 'playwright' && this.dataType === 'log') return;
|
|
100
|
-
|
|
101
|
-
// get id from global store
|
|
102
|
-
if (global.testomatioDataStore && global.testomatioDataStore.currentlyRunningTestId)
|
|
103
|
-
testId = testId ?? global.testomatioDataStore?.currentlyRunningTestId;
|
|
104
|
-
|
|
105
|
-
if (!testId && global?.currentlyRunningTestTitle)
|
|
106
|
-
testId = this.#tryToRetrieveTestId(global.currentlyRunningTestTitle);
|
|
107
|
-
|
|
108
|
-
if (!testId) {
|
|
109
|
-
debug(`No test id provided for "${this.dataType}" data:`, data);
|
|
47
|
+
if (!context) {
|
|
48
|
+
debug(`No context provided for "${this.dataType}" data:`, data);
|
|
110
49
|
return;
|
|
111
50
|
}
|
|
51
|
+
context = this.#stringToFilename(context);
|
|
112
52
|
|
|
113
53
|
if (this.isFileStorage) {
|
|
114
|
-
this.#putDataToFile(data,
|
|
54
|
+
this.#putDataToFile(data, context);
|
|
115
55
|
} else {
|
|
116
|
-
this.#putDataToGlobalVar(data,
|
|
56
|
+
this.#putDataToGlobalVar(data, context);
|
|
117
57
|
}
|
|
118
58
|
}
|
|
119
59
|
|
|
120
60
|
/**
|
|
121
|
-
* Returns data, stored for specific
|
|
61
|
+
* Returns data, stored for specific test/context (or data which was stored without test id specified).
|
|
122
62
|
* This method will get data from global variable and/or from from file (previosly saved with put method).
|
|
123
63
|
*
|
|
124
|
-
* @param {
|
|
125
|
-
* @returns
|
|
64
|
+
* @param {string} context
|
|
65
|
+
* @returns {any []} of data (any type), null (if no data found for test) or string (if data type is log)
|
|
126
66
|
*/
|
|
127
67
|
getData(context) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
let testId = null;
|
|
131
|
-
if (typeof context === 'string') {
|
|
132
|
-
testId = this.#tryToRetrieveTestId(context) || context;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (!testId) {
|
|
136
|
-
debug(`Cannot get test id from passed context:`, context);
|
|
68
|
+
if (!context) {
|
|
69
|
+
debug(`No context passed`, context);
|
|
137
70
|
return null;
|
|
138
71
|
}
|
|
139
72
|
|
|
73
|
+
context = this.#stringToFilename(context);
|
|
74
|
+
|
|
140
75
|
let testDataFromFile = [];
|
|
141
76
|
let testDataFromGlobalVar = [];
|
|
142
77
|
|
|
143
78
|
if (global?.testomatioDataStore) {
|
|
144
|
-
testDataFromGlobalVar = this.#getDataFromGlobalVar(
|
|
145
|
-
// these frameworks use global variable storage
|
|
146
|
-
// if (testDataFromGlobalVar && ['cucumber', 'codeceptjs'].includes(this.runningEnvironment)) {
|
|
79
|
+
testDataFromGlobalVar = this.#getDataFromGlobalVar(context);
|
|
147
80
|
if (testDataFromGlobalVar) {
|
|
148
|
-
// return as string if its log data
|
|
149
|
-
if (this.dataType === 'log' && testDataFromGlobalVar.length) return testDataFromGlobalVar.join('\n');
|
|
150
|
-
// return as array for other data types
|
|
151
81
|
if (testDataFromGlobalVar.length) return testDataFromGlobalVar;
|
|
152
82
|
}
|
|
153
83
|
// don't return nothing if no data in global variable
|
|
154
84
|
}
|
|
155
85
|
|
|
156
|
-
|
|
157
|
-
mocha has created a global storage, but just in some cases, generally it is not available
|
|
158
|
-
*/
|
|
159
|
-
// if (this.isFileStorage || !testData) {
|
|
160
|
-
// testData = this.#getDataFromFile(testId);
|
|
161
|
-
// if (testData) return testData;
|
|
162
|
-
// }
|
|
163
|
-
|
|
164
|
-
testDataFromFile = this.#getDataFromFile(testId);
|
|
86
|
+
testDataFromFile = this.#getDataFromFile(context);
|
|
165
87
|
|
|
166
88
|
if (testDataFromFile.length) {
|
|
167
|
-
if (this.dataType === 'log') return testDataFromFile.join('\n');
|
|
168
89
|
return testDataFromFile;
|
|
169
90
|
}
|
|
170
|
-
debug(`No "${this.dataType}" data for test id ${
|
|
91
|
+
debug(`No "${this.dataType}" data for test id ${context} in both file and global variable`);
|
|
171
92
|
|
|
172
93
|
// in case no data found for test
|
|
173
94
|
return null;
|
|
174
95
|
}
|
|
175
96
|
|
|
176
97
|
/**
|
|
177
|
-
*
|
|
178
|
-
* Context could be anything (test, suite, string, etc) which is used to define testId.
|
|
179
|
-
* Or it could represent any other entity (which does not contain test id).
|
|
180
|
-
* @param {*} context
|
|
181
|
-
*/
|
|
182
|
-
#tryToRetrieveTestId(context) {
|
|
183
|
-
if (!context) return null;
|
|
184
|
-
this.#refreshStorageType();
|
|
185
|
-
|
|
186
|
-
if (this.runningEnvironment === 'playwright' || context?.title) {
|
|
187
|
-
// context is testInfo
|
|
188
|
-
const testId = getTestIdFromTestTitle(context.title);
|
|
189
|
-
if (testId) return testId;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (typeof context === 'string') {
|
|
193
|
-
const testId = getTestIdFromTestTitle(context);
|
|
194
|
-
if (testId) return testId;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return null;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Refreshes storage type (file or global variable) depending on current environment
|
|
202
|
-
* This method should be run on each attempt to put or get data from/to storage
|
|
203
|
-
* Because storage instance is created before the test runner is started. And storage type could be changed
|
|
204
|
-
*/
|
|
205
|
-
#refreshStorageType() {
|
|
206
|
-
this.runningEnvironment = this.getRunningEnviroment();
|
|
207
|
-
|
|
208
|
-
// some test frameworks do not persist global variables, thus file storage is used for them (by default)
|
|
209
|
-
if (this.runningEnvironment === 'codeceptjs') this.isFileStorage = false;
|
|
210
|
-
// playwrigth stores logs by itself; but file storage is used for other data types for playwright
|
|
211
|
-
if (this.runningEnvironment === 'playwright' && this.dataType === 'log') this.isFileStorage = false;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* @param {*} testId
|
|
98
|
+
* @param {string} context
|
|
216
99
|
* @returns aray of data (any type)
|
|
217
100
|
*/
|
|
218
|
-
#getDataFromGlobalVar(
|
|
101
|
+
#getDataFromGlobalVar(context) {
|
|
219
102
|
try {
|
|
220
103
|
if (global?.testomatioDataStore[this.dataType]) {
|
|
221
|
-
const testData = global.testomatioDataStore[this.dataType][
|
|
222
|
-
if (testData) debug(`"${this.dataType}" data for test id ${
|
|
104
|
+
const testData = global.testomatioDataStore[this.dataType][context];
|
|
105
|
+
if (testData) debug(`"${this.dataType}" data for test id ${context}:`, testData.join(', '));
|
|
223
106
|
return testData || [];
|
|
224
107
|
}
|
|
225
|
-
// debug(`No ${this.dataType} data for test
|
|
108
|
+
// debug(`No ${this.dataType} data for test context ${context} in <global> storage`);
|
|
226
109
|
return [];
|
|
227
110
|
} catch (e) {
|
|
228
111
|
// there could be no data, ignore
|
|
@@ -231,19 +114,19 @@ class DataStorage {
|
|
|
231
114
|
|
|
232
115
|
/**
|
|
233
116
|
*
|
|
234
|
-
* @param {*}
|
|
117
|
+
* @param {*} context
|
|
235
118
|
* @returns array of data (any type)
|
|
236
119
|
*/
|
|
237
|
-
#getDataFromFile(
|
|
120
|
+
#getDataFromFile(context) {
|
|
238
121
|
try {
|
|
239
|
-
const filepath = join(this.dataDirPath, `${this.dataType}_${
|
|
122
|
+
const filepath = join(this.dataDirPath, `${this.dataType}_${context}`);
|
|
240
123
|
if (fs.existsSync(filepath)) {
|
|
241
124
|
const testDataAsText = fs.readFileSync(filepath, 'utf-8');
|
|
242
|
-
if (testDataAsText) debug(`"${this.dataType}" data for test id ${
|
|
125
|
+
if (testDataAsText) debug(`"${this.dataType}" data for test id ${context}:`, testDataAsText);
|
|
243
126
|
const testDataArr = testDataAsText?.split(os.EOL) || [];
|
|
244
127
|
return testDataArr;
|
|
245
128
|
}
|
|
246
|
-
// debug(`No ${this.dataType} data for test
|
|
129
|
+
// debug(`No ${this.dataType} data for test ${context} in <file> storage`);
|
|
247
130
|
return [];
|
|
248
131
|
} catch (e) {
|
|
249
132
|
// there could be no data, ignore
|
|
@@ -254,23 +137,23 @@ class DataStorage {
|
|
|
254
137
|
/**
|
|
255
138
|
* Puts data to global variable. Unlike the file storage, stores data in array (file storage just append as string).
|
|
256
139
|
* @param {*} data
|
|
257
|
-
* @param {*}
|
|
140
|
+
* @param {*} context
|
|
258
141
|
*/
|
|
259
|
-
#putDataToGlobalVar(data,
|
|
260
|
-
debug(
|
|
142
|
+
#putDataToGlobalVar(data, context) {
|
|
143
|
+
debug('Saving data to global variable for ', context, ':', data);
|
|
261
144
|
if (!global.testomatioDataStore) global.testomatioDataStore = {};
|
|
262
145
|
if (!global.testomatioDataStore?.[this.dataType]) global.testomatioDataStore[this.dataType] = {};
|
|
263
146
|
|
|
264
|
-
if (!global.testomatioDataStore?.[this.dataType][
|
|
265
|
-
global.testomatioDataStore[this.dataType][
|
|
147
|
+
if (!global.testomatioDataStore?.[this.dataType][context]) global.testomatioDataStore[this.dataType][context] = [];
|
|
148
|
+
global.testomatioDataStore[this.dataType][context].push(data);
|
|
266
149
|
}
|
|
267
150
|
|
|
268
|
-
#putDataToFile(data,
|
|
151
|
+
#putDataToFile(data, context) {
|
|
269
152
|
if (typeof data !== 'string') data = JSON.stringify(data);
|
|
270
|
-
const filename = `${this.dataType}_${
|
|
153
|
+
const filename = `${this.dataType}_${context}`;
|
|
271
154
|
const filepath = join(this.dataDirPath, filename);
|
|
272
155
|
if (!fs.existsSync(this.dataDirPath)) fileSystem.createDir(this.dataDirPath);
|
|
273
|
-
debug('Saving data to file for
|
|
156
|
+
debug('Saving data to file for', context, 'to', filepath, ':\n', data, '\n');
|
|
274
157
|
|
|
275
158
|
// append new line if file already exists (in this case its definitely includes some data)
|
|
276
159
|
if (fs.existsSync(filepath)) {
|
|
@@ -285,23 +168,3 @@ module.exports = DataStorage;
|
|
|
285
168
|
|
|
286
169
|
// TODO: consider using fs promises instead of writeSync/appendFileSync to
|
|
287
170
|
// prevent blocking and improve performance (probably queue usage will be required)
|
|
288
|
-
|
|
289
|
-
// TODO: rewrite client - everything regarding storing artifacts
|
|
290
|
-
// TODO: try to define adapter inside client
|
|
291
|
-
// TODO: ability to intercept multiple loggers (upd: no need)
|
|
292
|
-
|
|
293
|
-
/* does not work for Playwright
|
|
294
|
-
try {
|
|
295
|
-
const { test } = require('@playwright/test');
|
|
296
|
-
test.beforeEach(async ({}, testInfo) => {
|
|
297
|
-
global.testTitle = testInfo.title;
|
|
298
|
-
global.testomatioRunningEnvironment = 'playwright';
|
|
299
|
-
});
|
|
300
|
-
} catch (e) {
|
|
301
|
-
// ignore
|
|
302
|
-
}
|
|
303
|
-
// Playwright storage works fine only when running tests from a single file;
|
|
304
|
-
// otherwise it is not possible to define test id/title, it is overwritten
|
|
305
|
-
TODO: the only way implementation for Pw for now is to pass testInfo inside test
|
|
306
|
-
// (and process this testInfo inside "put" function)
|
|
307
|
-
*/
|
|
@@ -2,23 +2,39 @@ const debug = require('debug')('@testomatio/reporter:key-value-storage');
|
|
|
2
2
|
const DataStorage = require('./data-storage');
|
|
3
3
|
|
|
4
4
|
class KeyValueStorage {
|
|
5
|
+
static #instance;
|
|
6
|
+
|
|
7
|
+
#context;
|
|
8
|
+
|
|
5
9
|
constructor() {
|
|
6
10
|
this.dataStorage = new DataStorage('keyvalue');
|
|
11
|
+
}
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* @returns {KeyValueStorage}
|
|
16
|
+
*/
|
|
17
|
+
static getInstance() {
|
|
18
|
+
if (!this.#instance) {
|
|
19
|
+
this.#instance = new KeyValueStorage();
|
|
11
20
|
}
|
|
21
|
+
return this.#instance;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {string} context - suite title + test title
|
|
26
|
+
*/
|
|
27
|
+
setContext(context) {
|
|
28
|
+
this.#context = context;
|
|
12
29
|
}
|
|
13
30
|
|
|
14
31
|
/**
|
|
15
32
|
* Stores key-value pair and passes it to reporter
|
|
16
33
|
* @param {{key: string}} keyValue - key-value pair(s) as object
|
|
17
|
-
* @param {*} context testId or test title
|
|
18
34
|
*/
|
|
19
|
-
put(keyValue
|
|
35
|
+
put(keyValue) {
|
|
20
36
|
if (!keyValue) return;
|
|
21
|
-
this.dataStorage.putData(keyValue, context);
|
|
37
|
+
this.dataStorage.putData(keyValue, this.#context);
|
|
22
38
|
}
|
|
23
39
|
|
|
24
40
|
#isKeyValueObject(smth) {
|
|
@@ -30,7 +46,8 @@ class KeyValueStorage {
|
|
|
30
46
|
* @param {*} context testId or test context from test runner
|
|
31
47
|
* @returns {Object} key-values pairs as object, e.g. {priority: 'high', browser: 'chrome'}
|
|
32
48
|
*/
|
|
33
|
-
get(context) {
|
|
49
|
+
get(context = null) {
|
|
50
|
+
context = context || this.#context;
|
|
34
51
|
if (!context) return null;
|
|
35
52
|
|
|
36
53
|
const keyValuesList = this.dataStorage.getData(context);
|
|
@@ -53,6 +70,4 @@ class KeyValueStorage {
|
|
|
53
70
|
}
|
|
54
71
|
}
|
|
55
72
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
module.exports = new KeyValueStorage();
|
|
73
|
+
module.exports.keyValueStorage = KeyValueStorage.getInstance();
|
package/lib/storages/logger.js
CHANGED
|
@@ -26,18 +26,45 @@ class Logger {
|
|
|
26
26
|
// set default logger to be used in log, warn, error, etc methods
|
|
27
27
|
#originalUserLogger = { ...console };
|
|
28
28
|
|
|
29
|
-
#dataStorage
|
|
29
|
+
#dataStorage;
|
|
30
|
+
|
|
31
|
+
#context = null;
|
|
32
|
+
|
|
33
|
+
static #instance;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
* @returns {Logger}
|
|
38
|
+
*/
|
|
39
|
+
static getInstance() {
|
|
40
|
+
if (!this.#instance) {
|
|
41
|
+
this.#instance = new Logger();
|
|
42
|
+
}
|
|
43
|
+
return this.#instance;
|
|
44
|
+
}
|
|
30
45
|
|
|
31
46
|
logLevel = process?.env?.LOG_LEVEL?.toUpperCase() || 'ALL';
|
|
32
47
|
|
|
33
48
|
constructor() {
|
|
49
|
+
this.#dataStorage = new DataStorage('log');
|
|
50
|
+
|
|
34
51
|
// intercept console by default
|
|
35
52
|
this.intercept(console);
|
|
53
|
+
}
|
|
36
54
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
55
|
+
/**
|
|
56
|
+
* @param { 'file' | 'global' } storageType
|
|
57
|
+
*/
|
|
58
|
+
setStorageType(storageType) {
|
|
59
|
+
this.isFileStorage = storageType === 'file';
|
|
60
|
+
this.#dataStorage.isFileStorage = this.isFileStorage;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {string} context - suite title + test title
|
|
65
|
+
*/
|
|
66
|
+
setContext(context) {
|
|
67
|
+
this.#context = context;
|
|
41
68
|
}
|
|
42
69
|
|
|
43
70
|
/**
|
|
@@ -55,17 +82,17 @@ class Logger {
|
|
|
55
82
|
}
|
|
56
83
|
}
|
|
57
84
|
logs = chalk.blue(`> ${logs}`);
|
|
58
|
-
this.#dataStorage.putData(logs);
|
|
85
|
+
this.#dataStorage.putData(logs, this.#context);
|
|
59
86
|
}
|
|
60
87
|
|
|
61
88
|
/**
|
|
62
89
|
*
|
|
63
|
-
* @param {
|
|
64
|
-
* @returns
|
|
90
|
+
* @param {string} context testId or test context from test runner
|
|
91
|
+
* @returns {string[]}
|
|
65
92
|
*/
|
|
66
93
|
getLogs(context) {
|
|
67
94
|
const logs = this.#dataStorage.getData(context);
|
|
68
|
-
return logs
|
|
95
|
+
return logs;
|
|
69
96
|
}
|
|
70
97
|
|
|
71
98
|
#stringifyLogs(...args) {
|
|
@@ -124,7 +151,7 @@ class Logger {
|
|
|
124
151
|
logs = this.#stringifyLogs(strings, ...args);
|
|
125
152
|
}
|
|
126
153
|
this.#originalUserLogger.log(logs);
|
|
127
|
-
this.#dataStorage.putData(logs);
|
|
154
|
+
this.#dataStorage.putData(logs, this.#context);
|
|
128
155
|
}
|
|
129
156
|
|
|
130
157
|
/**
|
|
@@ -140,8 +167,12 @@ class Logger {
|
|
|
140
167
|
if (severity < LEVELS[this.logLevel]?.severity) return;
|
|
141
168
|
|
|
142
169
|
const logs = this.#stringifyLogs(...argsArray);
|
|
170
|
+
|
|
171
|
+
// skip logs from testomatio reporter itself
|
|
172
|
+
if (logs.includes('[TESTOMATIO]')) return;
|
|
173
|
+
|
|
143
174
|
const colorizedLogs = chalk[LEVELS[level].color](logs);
|
|
144
|
-
this.#dataStorage.putData(colorizedLogs);
|
|
175
|
+
this.#dataStorage.putData(colorizedLogs, this.#context);
|
|
145
176
|
try {
|
|
146
177
|
// level.toLowerCase() represents method name (log, warn, error, etc)
|
|
147
178
|
this.#originalUserLogger[level.toLowerCase()](colorizedLogs);
|
|
@@ -239,11 +270,7 @@ class Logger {
|
|
|
239
270
|
}
|
|
240
271
|
}
|
|
241
272
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const logger = new Logger();
|
|
245
|
-
|
|
246
|
-
module.exports = logger;
|
|
273
|
+
module.exports.logger = Logger.getInstance();
|
|
247
274
|
|
|
248
275
|
// TODO: parse passed arguments as {level: 'str', message: 'str'} because some loggers use such syntax;
|
|
249
276
|
// upd: did not face such loggers, but still could be useful
|
|
@@ -288,3 +315,6 @@ Finally, in the test it will look like:
|
|
|
288
315
|
|
|
289
316
|
Parallelization in Cypress is only available if using Cypress Dashboard??
|
|
290
317
|
*/
|
|
318
|
+
|
|
319
|
+
// TODO: add time to logs
|
|
320
|
+
// TODO: add logger name to logs?
|
package/lib/utils/utils.js
CHANGED
|
@@ -290,19 +290,6 @@ 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
|
-
|
|
306
293
|
module.exports = {
|
|
307
294
|
isSameTest,
|
|
308
295
|
fetchSourceCode,
|
|
@@ -312,7 +299,6 @@ module.exports = {
|
|
|
312
299
|
fetchFilesFromStackTrace,
|
|
313
300
|
fileSystem,
|
|
314
301
|
getCurrentDateTime,
|
|
315
|
-
jestHelpers,
|
|
316
302
|
specificTestInfo,
|
|
317
303
|
isValidUrl,
|
|
318
304
|
ansiRegExp,
|