@testomatio/reporter 1.2.4-beta → 1.3.0-ignore-stack-for-passed.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.
Files changed (48) hide show
  1. package/README.md +61 -54
  2. package/lib/adapter/codecept.js +96 -35
  3. package/lib/adapter/cucumber/current.js +19 -12
  4. package/lib/adapter/cucumber/legacy.js +8 -7
  5. package/lib/adapter/cucumber.js +2 -2
  6. package/lib/adapter/cypress-plugin/index.js +52 -25
  7. package/lib/adapter/jasmine.js +1 -1
  8. package/lib/adapter/jest.js +49 -16
  9. package/lib/adapter/mocha.js +103 -51
  10. package/lib/adapter/playwright.js +80 -27
  11. package/lib/adapter/webdriver.js +1 -1
  12. package/lib/bin/reportXml.js +14 -13
  13. package/lib/bin/startTest.js +27 -6
  14. package/lib/client.js +192 -69
  15. package/lib/config.js +34 -0
  16. package/lib/constants.js +19 -7
  17. package/lib/data-storage.js +203 -0
  18. package/lib/fileUploader.js +128 -53
  19. package/lib/junit-adapter/adapter.js +0 -2
  20. package/lib/junit-adapter/csharp.js +3 -4
  21. package/lib/junit-adapter/index.js +3 -3
  22. package/lib/junit-adapter/java.js +35 -17
  23. package/lib/junit-adapter/javascript.js +1 -2
  24. package/lib/junit-adapter/python.js +12 -14
  25. package/lib/junit-adapter/ruby.js +1 -2
  26. package/lib/pipe/csv.js +5 -3
  27. package/lib/pipe/github.js +27 -39
  28. package/lib/pipe/gitlab.js +20 -24
  29. package/lib/pipe/html.js +317 -0
  30. package/lib/pipe/index.js +3 -1
  31. package/lib/pipe/testomatio.js +189 -56
  32. package/lib/reporter-functions.js +46 -0
  33. package/lib/reporter.js +11 -9
  34. package/lib/services/artifacts.js +57 -0
  35. package/lib/services/index.js +13 -0
  36. package/lib/services/key-values.js +58 -0
  37. package/lib/services/logger.js +311 -0
  38. package/lib/template/template-draft.hbs +249 -0
  39. package/lib/template/testomatio.hbs +388 -0
  40. package/lib/utils/pipe_utils.js +128 -0
  41. package/lib/{util.js → utils/utils.js} +144 -12
  42. package/lib/xmlReader.js +211 -122
  43. package/package.json +18 -7
  44. package/lib/_ArtifactStorageOld.js +0 -142
  45. package/lib/artifactStorage.js +0 -25
  46. package/lib/dataStorage.js +0 -241
  47. package/lib/helpers.js +0 -34
  48. package/lib/logger.js +0 -293
@@ -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('./util');
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;
@@ -1,25 +0,0 @@
1
- // const debug = require('debug')('@testomatio/reporter:logger');
2
- const { DataStorage } = require('./dataStorage');
3
-
4
- class ArtifactStorage {
5
- constructor(params = {}) {
6
- this.dataStorage = new DataStorage('artifact', params);
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();
@@ -1,241 +0,0 @@
1
- const debug = require('debug')('@testomatio/reporter:storage');
2
- const fs = require('fs');
3
- const path = require('path');
4
- const os = require('os');
5
- const { join } = require('path');
6
- const JestReporter = require('./adapter/jest');
7
- const { TESTOMAT_TMP_STORAGE } = require('./constants');
8
- const { fileSystem } = require('./util');
9
- // const { getCurrentlyRunningTestId } = require('./helpers');
10
- class DataStorage {
11
- /**
12
- * Creates data storage instance for specific data type.
13
- * Stores data to global variable or to file depending on what is applicable for current test runner.
14
- * dataType: 'log' | 'artifact' | ...
15
- * @param {*} dataType storage type (like 'log', 'artifact'); could be any string, used only to define file path
16
- */
17
- constructor(dataType) {
18
- // if (!dataType) throw new Error('Data type is required when creating data storage');
19
- this.dataType = dataType || 'data';
20
- this.dataDirName = this.dataType;
21
-
22
- this._refreshStorageType();
23
-
24
- // dir is created in any case (not to recheck its existence every time)
25
- this.dataDirPath = path.join(TESTOMAT_TMP_STORAGE.mainDir, this.dataDirName);
26
- fileSystem.createDir(this.dataDirPath);
27
-
28
- debug(`Data storage mode: ${this.isFileStorage ? 'file' : 'memory'}`);
29
- }
30
-
31
- // TODO: implement
32
- // eslint-disable-next-line no-unused-vars
33
- getTestIdFromContext(context) {
34
- // return testId;
35
- }
36
-
37
- /**
38
- * Refreshes storage type (file or global variable) depending on current environment
39
- * This method should be run on each attempt to put or get data from/to storage
40
- * Because storage instance is created before the test runner is started
41
- */
42
- _refreshStorageType() {
43
- this.isFileStorage = !global.testomatioDataStore;
44
- /*
45
- FYI:
46
- If this storage instance is used within test runner, it works fine.
47
- But if, for example, we create storage instance inside the testomatio client (to get stored data),
48
- the environment could be different (not already a test runner env).
49
- Thus, checking environment is only reasonable when you put data to starage
50
- and potentially useless when get data from storage
51
- */
52
- this.runningEnvironment = this.getRunningEnviroment();
53
-
54
- // jest does not persist global variables, thus file storage is used
55
- if (this.runningEnvironment === 'jest') this.isFileStorage = true;
56
- if (this.runningEnvironment === 'playwright') this.isFileStorage = true;
57
- }
58
-
59
- /**
60
- * Try to define the running environment. Not 100% reliable and used as additional check
61
- * @returns jest | mocha | ...
62
- */
63
- getRunningEnviroment() {
64
- // jest
65
- if (process.env.JEST_WORKER_ID) return 'jest';
66
-
67
- // mocha
68
- try {
69
- // @ts-expect-error mocha is defined only in mocha environment
70
- if (typeof mocha !== 'undefined') return 'mocha';
71
- } catch (e) {
72
- // ignore
73
- }
74
-
75
- // codeceptjs
76
- // @ts-expect-error codeceptjs is defined only in codeceptjs environment
77
- if (global.codeceptjs) return 'codeceptjs';
78
-
79
- // others
80
- // 'cucumber:current', 'cucumber:legacy'
81
- if (global.testomatioRunningEnvironment) return global.testomatioRunningEnvironment;
82
-
83
- if (process.env.PLAYWRIGHT_TEST_BASE_URL) return 'playwright';
84
-
85
- return null;
86
- }
87
-
88
- /**
89
- * Puts any data to storage (file or global variable)
90
- * @param {*} data anything you want to store
91
- * @param {*} context could be testId or any context (test, suite, etc) which is used to define testId
92
- * @returns
93
- */
94
- putData(data, context = null) {
95
- this._refreshStorageType();
96
-
97
- let testId = null;
98
- if (typeof context === 'string') {
99
- testId = context;
100
- } else {
101
- // TODO: derive testId from context
102
- // testId = context...
103
- }
104
-
105
- // try to get testId for Jest
106
- if (this.runningEnvironment === 'jest') testId = testId ?? JestReporter.getIdOfCurrentlyRunningTest();
107
- if (this.runningEnvironment === 'codeceptjs') testId = testId ?? global.testomatioDataStore?.currentlyRunningTestId;
108
- // if (this.runningEnvironment === 'playwright') testId = testId ?? getCurrentlyRunningTestId();
109
- // get id from global store
110
- if (global.testomatioDataStore && global.testomatioDataStore.currentlyRunningTestId)
111
- testId = testId ?? global.testomatioDataStore?.currentlyRunningTestId;
112
-
113
- // if testId is not provided, data is be saved to `{dataType}_other` file;
114
- if (!testId) {
115
- debug(`No test id provided for ${this.dataType} data: ${data}`);
116
- return;
117
- }
118
-
119
- if (this.isFileStorage) {
120
- this._putDataToFile(data, testId);
121
- } else {
122
- this._putDataToGlobalVar(data, testId);
123
- }
124
- }
125
-
126
- /**
127
- * Returns data, stored for specific testId (or data which was stored without test id specified).
128
- * This method will get data from global variable. But if it is not available, it will try to get data from file.
129
- * Thus, good approach is to remove file storage folder before each test run (and after, for sure).
130
- *
131
- * Defining the execution environment is not guaranteed! Is used only as additional check.
132
- * @param {*} context could be testId or any context (test, suite, etc) which is used to define testId
133
- * @returns
134
- */
135
- getData(context) {
136
- this._refreshStorageType();
137
-
138
- let testId = null;
139
- if (typeof context === 'string') {
140
- testId = context;
141
- } else {
142
- // TODO: derive testId from context
143
- // testId = context...
144
- }
145
-
146
- if (!testId) {
147
- debug(`Cannot get test id from passed context:\n}`, context);
148
- return null;
149
- }
150
-
151
- let testData = null;
152
-
153
- if (global?.testomatioDataStore) {
154
- testData = this._getDataFromGlobalVar(testId);
155
- if (testData) return testData;
156
- }
157
-
158
- if (this.isFileStorage || !testData) {
159
- testData = this._getDataFromFile(testId);
160
- if (testData) return testData;
161
- }
162
-
163
- debug(`No ${this.dataType} data for test id ${testId} in both file and global variable`);
164
- return testData;
165
- }
166
-
167
- _getDataFromGlobalVar(testId) {
168
- try {
169
- if (global?.testomatioDataStore[this.dataDirName]) {
170
- const testData = global.testomatioDataStore[this.dataDirName][testId];
171
- debug(`Data for test id ${testId}:\n${testData}`);
172
- return testData;
173
- }
174
- debug(`No ${this.dataType} data for test id ${testId} in <global> storage`);
175
- return null;
176
- } catch (e) {
177
- // there could be no data, ignore
178
- }
179
- }
180
-
181
- _getDataFromFile(testId) {
182
- try {
183
- const filepath = join(this.dataDirPath, `${this.dataType}_${testId}`);
184
- if (fs.existsSync(filepath)) {
185
- const testData = fs.readFileSync(filepath, 'utf-8');
186
- debug(`Data for test id ${testId}:\n${testData}`);
187
- return testData;
188
- }
189
- debug(`No ${this.dataType} data for test id ${testId} in <file> storage`);
190
- return null;
191
- } catch (e) {
192
- // there could be no data, ignore
193
- }
194
- return null;
195
- }
196
-
197
- _putDataToGlobalVar(data, testId) {
198
- debug('Saving data to global variable for test', testId, ':\n', data, '\n');
199
- if (!global.testomatioDataStore[this.dataDirName]) global.testomatioDataStore[this.dataDirName] = {};
200
- global.testomatioDataStore[this.dataDirName][testId] // eslint-disable-line no-unused-expressions
201
- ? (global.testomatioDataStore[this.dataDirName][testId] += `\n${data}`)
202
- : (global.testomatioDataStore[this.dataDirName][testId] = data);
203
- }
204
-
205
- _putDataToFile(data, testId) {
206
- if (typeof data !== 'string') data = JSON.stringify(data);
207
- const filename = `${this.dataType}_${testId}`;
208
- const filepath = join(this.dataDirPath, filename);
209
- debug('Saving data to file for test', testId, 'to', filepath, ':\n', data, '\n');
210
-
211
- // TODO: handle multiple invocations of JSON.stringify.
212
- // UPD: not actual because decided not to use it - it created extra wrapping quotes "" and // (escaped slashes)
213
- fs.appendFileSync(filepath, data + os.EOL, 'utf-8');
214
- }
215
- }
216
-
217
- module.exports.DataStorage = DataStorage;
218
-
219
- // TODO: consider using fs promises instead of writeSync/appendFileSync to
220
- // prevent blocking and improve performance (probably queue usage will be required)
221
-
222
- // TODO: rewrite client - everything regarding storing artifacts
223
- // TODO: try to define adapter inside client
224
- // TODO: use .env
225
- // TODO: ability to intercept multiple loggers (upd: no need)
226
-
227
- /* Playwright
228
- There is no global scope sharing between tests and reporter listeners.
229
- Thus need to use file storage. But when tests are run in parallel, the new problem occurs.
230
- Tried to solve it by using the TEST_WORKER_INDEX env variable, but it is available inside the listener
231
- (available only inside the test). Thus when cannot match currently running test id from the reporter listener
232
- with the currently running test.
233
- The only solution I see for now is to pass the test id to the logger from the test itself.
234
- By passing the testInfo param to the test function:
235
- async ({ page }, testInfo)
236
- and then retrieving the .title from it.
237
- */
238
-
239
- /* Cypress
240
- Parallelization is only available if using Cypress Dashboard??
241
- */
package/lib/helpers.js DELETED
@@ -1,34 +0,0 @@
1
- const path = require('path');
2
- const fs = require('fs');
3
- const { TESTOMAT_TMP_STORAGE } = require('./constants');
4
-
5
- // NEXT HELPERS ARE CREATED FOR PLAYWRIGHT. IGNORE FOR NOW. PROBABLY WILL BE REMOVED SHORTLY
6
-
7
- // TEST_WORKER_INDEX is not available inside the test listener :/
8
- /**
9
- * Sets id of currently running test to storage (global variable or file)
10
- * Used for Playwright
11
- * @param {*} testId
12
- */
13
- function setCurrentlyRunningTestIdForPlaywright(testId) {
14
- const workerId = +process.env.TEST_WORKER_INDEX || 0;
15
- const filePath = path.join(TESTOMAT_TMP_STORAGE.mainDir, 'current_test_id_' + workerId);
16
- fs.writeFileSync(filePath, testId);
17
- }
18
-
19
- /**
20
- * Gets id of currently running test from storage (global variable or file)
21
- * Used for Playwright
22
- * @returns string test id of currently running test
23
- */
24
- function getCurrentlyRunningTestIdForPlaywright() {
25
- const workerId = +process.env.TEST_WORKER_INDEX || 0;
26
- const filePath = path.join(TESTOMAT_TMP_STORAGE.mainDir, 'current_test_id_' + workerId);
27
- if (fs.existsSync(filePath)) {
28
- return fs.readFileSync(filePath, 'utf8') || null;
29
- }
30
- return null;
31
- };
32
-
33
- module.exports.setCurrentlyRunningTestId = setCurrentlyRunningTestIdForPlaywright;
34
- module.exports.getCurrentlyRunningTestId = getCurrentlyRunningTestIdForPlaywright;