@testomatio/reporter 1.1.1 → 1.1.2-beta-fix-config-2

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.
@@ -5,7 +5,7 @@ const fs = require('fs');
5
5
  const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../../constants');
6
6
  const TestomatClient = require('../../client');
7
7
  const { parseTest, fileSystem } = require('../../utils/utils');
8
- const { TESTOMATIO } = require('../../config');
8
+ const config = require('../../config');
9
9
  const { services } = require('../../services');
10
10
 
11
11
  const { GherkinDocumentParser, PickleParser } = formatterHelpers;
@@ -30,7 +30,7 @@ class CucumberReporter extends Formatter {
30
30
  this.failures = [];
31
31
  this.cases = [];
32
32
 
33
- this.client = new TestomatClient({ apiKey: options.apiKey || TESTOMATIO });
33
+ this.client = new TestomatClient({ apiKey: options.apiKey || config.TESTOMATIO });
34
34
  this.status = STATUS.PASSED;
35
35
  }
36
36
 
@@ -4,7 +4,7 @@ const chalk = require('chalk');
4
4
  const { parseTest, fileSystem } = require('../../utils/utils');
5
5
  const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../../constants');
6
6
  const TestomatClient = require('../../client');
7
- const { TESTOMATIO } = require('../../config');
7
+ const config = require('../../config');
8
8
 
9
9
  const createTestomatFormatter = apiKey => {
10
10
  if (!apiKey || apiKey === '') {
@@ -152,4 +152,4 @@ const createTestomatFormatter = apiKey => {
152
152
  };
153
153
  };
154
154
 
155
- module.exports = createTestomatFormatter(TESTOMATIO);
155
+ module.exports = createTestomatFormatter(config.TESTOMATIO);
@@ -1,14 +1,14 @@
1
1
  const { STATUS } = require('../../constants');
2
2
  const { parseTest, parseSuite } = require('../../utils/utils');
3
3
  const TestomatClient = require('../../client');
4
- const { TESTOMATIO } = require('../../config');
4
+ const config = require('../../config');
5
5
 
6
6
  const testomatioReporter = on => {
7
- if (!TESTOMATIO) {
7
+ if (!config.TESTOMATIO) {
8
8
  console.log('TESTOMATIO key is empty, ignoring reports');
9
9
  return;
10
10
  }
11
- const client = new TestomatClient({ apiKey: TESTOMATIO });
11
+ const client = new TestomatClient({ apiKey: config.TESTOMATIO });
12
12
 
13
13
  on('before:run', async run => {
14
14
  // TODO: looks like client.env does not exist
@@ -55,8 +55,8 @@ class JestReporter {
55
55
  if (!fullSuiteTitle && testResult.testFilePath) fullSuiteTitle = path.basename(testResult.testFilePath);
56
56
 
57
57
  const logs = getTestLogs(result);
58
- const artifacts = services.artifacts.get(testResult.fullName);
59
- const keyValues = services.keyValues.get(testResult.fullName);
58
+ const artifacts = services.artifacts.get(result.fullName);
59
+ const keyValues = services.keyValues.get(result.fullName);
60
60
 
61
61
  const deducedStatus = status === 'pending' ? 'skipped' : status;
62
62
  // In jest if test is not matched with test name pattern it is considered as skipped.
@@ -4,7 +4,7 @@ const chalk = require('chalk');
4
4
  const TestomatClient = require('../client');
5
5
  const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../constants');
6
6
  const { parseTest, fileSystem } = require('../utils/utils');
7
- const { TESTOMATIO } = require('../config');
7
+ const config = require('../config');
8
8
  const { services } = require('../services');
9
9
 
10
10
  const {
@@ -26,7 +26,7 @@ function MochaReporter(runner, opts) {
26
26
  let skipped = 0;
27
27
  // let artifactStore;
28
28
 
29
- const apiKey = opts?.reporterOptions?.apiKey || TESTOMATIO;
29
+ const apiKey = opts?.reporterOptions?.apiKey || config.TESTOMATIO;
30
30
 
31
31
  const client = new TestomatClient({ apiKey });
32
32
 
@@ -42,9 +42,7 @@ class PlaywrightReporter {
42
42
 
43
43
  const { error, duration } = result;
44
44
 
45
- const suite_title = test.parent
46
- ? test.parent?.title
47
- : path.basename(test?.location?.file);
45
+ const suite_title = test.parent ? test.parent?.title : path.basename(test?.location?.file);
48
46
 
49
47
  const steps = [];
50
48
  for (const step of result.steps) {
@@ -87,12 +85,11 @@ class PlaywrightReporter {
87
85
  reportTestPromises.push(reportTestPromise);
88
86
  }
89
87
 
90
-
91
88
  #getArtifactPath(artifact) {
92
89
  if (artifact.path) {
93
90
  if (path.isAbsolute(artifact.path)) return artifact.path;
94
91
 
95
- return path.join(this.config.outputDir || this.config.projects[0].outputDir, artifact.path);
92
+ return path.join(this.config.outputDir || this.config.projects[0].outputDir, artifact.path);
96
93
  }
97
94
 
98
95
  if (artifact.body) {
@@ -104,7 +101,7 @@ class PlaywrightReporter {
104
101
  return null;
105
102
  }
106
103
 
107
- async onEnd(result, config) {
104
+ async onEnd(result) {
108
105
  if (!this.client) return;
109
106
 
110
107
  await Promise.all(reportTestPromises);
@@ -117,9 +114,11 @@ class PlaywrightReporter {
117
114
  for (const upload of this.uploads) {
118
115
  const { title, testId, suite_title } = upload;
119
116
 
120
- const files = upload.files.map(attachment => {
121
- return { path: this.#getArtifactPath(attachment), title, type: attachment.contentType };
122
- });
117
+ const files = upload.files.map(attachment => ({
118
+ path: this.#getArtifactPath(attachment),
119
+ title,
120
+ type: attachment.contentType
121
+ }));
123
122
 
124
123
  promises.push(
125
124
  this.client.addTestRun(undefined, {
@@ -169,7 +168,7 @@ function tmpFile(prefix = 'tmp.') {
169
168
  /**
170
169
  * Returns filename + test title
171
170
  * @param {*} test - testInfo object from Playwright
172
- * @returns
171
+ * @returns
173
172
  */
174
173
  function getTestContextName(test) {
175
174
  return `${test._requireFile || ''}_${test.title}`;
@@ -186,7 +185,7 @@ function initPlaywrightForStorage() {
186
185
  });
187
186
  } catch (e) {
188
187
  // ignore
189
- }
188
+ }
190
189
  }
191
190
 
192
191
  module.exports = PlaywrightReporter;
@@ -5,7 +5,7 @@ const chalk = require('chalk');
5
5
  const TestomatClient = require('../client');
6
6
  const { APP_PREFIX, STATUS } = require('../constants');
7
7
  const { version } = require('../../package.json');
8
- const { TESTOMATIO } = require('../config');
8
+ const config = require('../config');
9
9
 
10
10
  console.log(chalk.cyan.bold(` 🤩 Testomat.io Reporter v${version}`));
11
11
 
@@ -21,7 +21,7 @@ program
21
21
 
22
22
  if (opts.envFile) require('dotenv').config(opts.envFile); // eslint-disable-line
23
23
 
24
- const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || TESTOMATIO;
24
+ const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config.TESTOMATIO;
25
25
  const title = process.env.TESTOMATIO_TITLE;
26
26
 
27
27
  if (launch) {
package/lib/client.js CHANGED
@@ -140,7 +140,6 @@ class Client {
140
140
  } = testData;
141
141
  let { message = '' } = testData;
142
142
 
143
-
144
143
  let errorFormatted = '';
145
144
  if (error) {
146
145
  errorFormatted += this.formatError(error) || '';
@@ -242,11 +241,11 @@ class Client {
242
241
  console.log(
243
242
  APP_PREFIX,
244
243
  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"`,
244
+ `Some artifacts were not uploaded. ${this.failedToUpload} artifacts could not be uploaded.
245
+ Run tests with DEBUG="@testomatio/reporter:file-uploader" to see details"`,
246
246
  ),
247
247
  );
248
248
  }
249
-
250
249
  }
251
250
  })
252
251
  .catch(err => console.log(APP_PREFIX, err));
package/lib/config.js CHANGED
@@ -1,16 +1,24 @@
1
- // This file is used to read environment variables from .env file and process.env
1
+ // This file is used to read environment variables from .env file
2
+
3
+ if (process.env.TESTOMATIO_ENV_FILE_PATH) {
4
+ require('dotenv').config({ path: process.env.TESTOMATIO_ENV_FILE_PATH });
5
+ }
2
6
 
3
- // ! uncommenting next line leads ro reading vars from .env file
4
- // require('dotenv').config();
5
7
  const debug = require('debug')('@testomatio/reporter:config');
6
8
 
7
9
  /* for possibility to use multiple env files (reading different paths)
8
10
  const dotenv = require('dotenv');
9
11
  const envFileVars = dotenv.config({ path: '.env' }).parsed; */
10
12
 
11
- const TESTOMATIO = process.env.TESTOMATIO || process.env.TESTOMATIO_API_KEY || process.env.TESTOMATIO_TOKEN || '';
12
- if (TESTOMATIO === 'undefined') console.error('TESTOMATIO is "undefined". Something went wrong. Contact dev team.');
13
- process.env.TESTOMATIO = TESTOMATIO;
13
+ if (process.env.TESTOMATIO_API_KEY) {
14
+ process.env.TESTOMATIO = process.env.TESTOMATIO_API_KEY;
15
+ }
16
+ if (process.env.TESTOMATIO_TOKEN) {
17
+ process.env.TESTOMATIO = process.env.TESTOMATIO_TOKEN;
18
+ }
19
+
20
+ if (process.env.TESTOMATIO === 'undefined')
21
+ console.error('TESTOMATIO is "undefined". Something went wrong. Contact dev team.');
14
22
 
15
23
  // select only TESTOMATIO related variables (only to print them in debug)
16
24
  const testomatioEnvVars =
@@ -26,4 +34,3 @@ debug('TESTOMATIO variables:', testomatioEnvVars);
26
34
  const config = process.env;
27
35
 
28
36
  module.exports = config;
29
- module.exports.TESTOMATIO = TESTOMATIO;
package/lib/constants.js CHANGED
@@ -3,6 +3,8 @@ const os = require('os');
3
3
  const path = require('path');
4
4
 
5
5
  const APP_PREFIX = chalk.gray('[TESTOMATIO]');
6
+ const AXIOS_TIMEOUT = 20 * 1000; // sum = 20sec
7
+ const AXIOS_RETRY_TIMEOUT = 5 * 1000; // sum = 5sec
6
8
 
7
9
  const TESTOMAT_TMP_STORAGE_DIR = path.join(os.tmpdir(), 'testomatio_tmp');
8
10
 
@@ -32,5 +34,7 @@ module.exports = {
32
34
  TESTOMAT_TMP_STORAGE_DIR,
33
35
  CSV_HEADERS,
34
36
  STATUS,
35
- HTML_REPORT
37
+ HTML_REPORT,
38
+ AXIOS_TIMEOUT,
39
+ AXIOS_RETRY_TIMEOUT
36
40
  }
@@ -4,7 +4,8 @@ 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, jestHelpers } = require('./utils/utils');
7
+ const { fileSystem, testRunnerHelper } = require('./utils/utils');
8
+ const crypto = require('crypto');
8
9
 
9
10
  class DataStorage {
10
11
  static #instance;
@@ -37,16 +38,6 @@ class DataStorage {
37
38
  this.isFileStorage = true;
38
39
  }
39
40
 
40
- #stringToFilename(str) {
41
- // TODO: use md5 hash later
42
- const validFilenameRegex = /[^a-zA-Z0-9_.-]/g;
43
- // replace all characters not in the regex above with underscore, then duplicate underscores removed
44
- let filename = str.replace(validFilenameRegex, '_').replace(/_{2,}/g, '_').substring(0, 255); // max filename length
45
- // remove leading and trailing underscores
46
- filename = filename.replace(/^_+|_+$/g, '');
47
- return filename;
48
- }
49
-
50
41
  /**
51
42
  * Puts any data to storage (file or global variable).
52
43
  * If file: stores data as text, if global variable – stores as array of data.
@@ -59,19 +50,19 @@ class DataStorage {
59
50
  putData(dataType, data, context = null) {
60
51
  if (!dataType || !data) return;
61
52
 
62
- context = context || this.context || global.testomatioTestTitle || jestHelpers.getNameOfCurrentlyRunningTest();
53
+ context = context || this.context || testRunnerHelper.getNameOfCurrentlyRunningTest();
63
54
  if (!context) {
64
55
  debug(`No context provided for "${dataType}" data:`, data);
65
56
  return;
66
57
  }
67
- context = this.#stringToFilename(context);
58
+ const contextHash = stringToMD5Hash(context);
68
59
 
69
60
  if (this.isFileStorage) {
70
61
  const dataDirPath = path.join(TESTOMAT_TMP_STORAGE_DIR, dataType);
71
62
  fileSystem.createDir(dataDirPath);
72
- this.#putDataToFile(dataType, data, context);
63
+ this.#putDataToFile(dataType, data, contextHash);
73
64
  } else {
74
- this.#putDataToGlobalVar(dataType, data, context);
65
+ this.#putDataToGlobalVar(dataType, data, contextHash);
75
66
  }
76
67
  }
77
68
 
@@ -85,32 +76,32 @@ class DataStorage {
85
76
  */
86
77
  getData(dataType, context) {
87
78
  // TODO: think if it could be useful
88
- // context = context || this.context || global.testomatioTestTitle || jestHelpers.getNameOfCurrentlyRunningTest();
79
+ // context = context || this.context || testRunnerHelper.getNameOfCurrentlyRunningTest();
89
80
 
90
81
  if (!context) {
91
82
  debug(`Trying to get "${dataType}" data without context`);
92
83
  return null;
93
84
  }
94
85
 
95
- context = this.#stringToFilename(context);
86
+ const contextHash = stringToMD5Hash(context);
96
87
 
97
88
  let testDataFromFile = [];
98
89
  let testDataFromGlobalVar = [];
99
90
 
100
91
  if (global?.testomatioDataStore) {
101
- testDataFromGlobalVar = this.#getDataFromGlobalVar(dataType, context);
92
+ testDataFromGlobalVar = this.#getDataFromGlobalVar(dataType, contextHash);
102
93
  if (testDataFromGlobalVar) {
103
94
  if (testDataFromGlobalVar.length) return testDataFromGlobalVar;
104
95
  }
105
96
  // don't return nothing if no data in global variable
106
97
  }
107
98
 
108
- testDataFromFile = this.#getDataFromFile(dataType, context);
99
+ testDataFromFile = this.#getDataFromFile(dataType, contextHash);
109
100
 
110
101
  if (testDataFromFile.length) {
111
102
  return testDataFromFile;
112
103
  }
113
- debug(`No "${dataType}" data for context "${context}" in both file and global variable`);
104
+ debug(`No "${dataType}" data for context "${contextHash}" in both file and global variable`);
114
105
 
115
106
  // in case no data found for context
116
107
  return null;
@@ -197,7 +188,16 @@ class DataStorage {
197
188
  }
198
189
  }
199
190
 
191
+ function stringToMD5Hash(str) {
192
+ const md5 = crypto.createHash('md5');
193
+ md5.update(str);
194
+ const hash = md5.digest('hex');
195
+
196
+ return hash;
197
+ }
198
+
200
199
  module.exports.dataStorage = DataStorage.getInstance();
200
+ module.exports.stringToMD5Hash = stringToMD5Hash;
201
201
 
202
202
  // TODO: consider using fs promises instead of writeSync/appendFileSync to
203
203
  // prevent blocking and improve performance (probably queue usage will be required)
@@ -1,11 +1,15 @@
1
1
  const debug = require('debug')('@testomatio/reporter:pipe:testomatio');
2
2
  const chalk = require('chalk');
3
+ // Retry interceptor function
4
+ const axiosRetry = require('axios-retry');
5
+ // Default axios instance
3
6
  const axios = require('axios');
4
7
  const JsonCycle = require('json-cycle');
5
- const { APP_PREFIX, STATUS } = require('../constants');
8
+
9
+ const { APP_PREFIX, STATUS, AXIOS_TIMEOUT, AXIOS_RETRY_TIMEOUT } = require('../constants');
6
10
  const { isValidUrl, foundedTestLog } = require('../utils/utils');
7
- const { parseFilterParams, generateFilterRequestParams, setS3Credentials, } = require('../utils/pipe_utils');
8
- const { TESTOMATIO } = require('../config');
11
+ const { parseFilterParams, generateFilterRequestParams, setS3Credentials } = require('../utils/pipe_utils');
12
+ const config = require('../config');
9
13
 
10
14
  if (process.env.TESTOMATIO_RUN) {
11
15
  process.env.runId = process.env.TESTOMATIO_RUN;
@@ -21,7 +25,7 @@ class TestomatioPipe {
21
25
  constructor(params, store) {
22
26
  this.isEnabled = false;
23
27
  this.url = params.testomatioUrl || process.env.TESTOMATIO_URL || 'https://app.testomat.io';
24
- this.apiKey = params.apiKey || TESTOMATIO;
28
+ this.apiKey = params.apiKey || config.TESTOMATIO;
25
29
  debug('Testomatio Pipe: ', this.apiKey ? 'API KEY' : '*no api key*');
26
30
  if (!this.apiKey) {
27
31
  return;
@@ -34,10 +38,31 @@ class TestomatioPipe {
34
38
  this.groupTitle = params.groupTitle || process.env.TESTOMATIO_RUNGROUP_TITLE;
35
39
  this.env = process.env.TESTOMATIO_ENV;
36
40
  this.label = process.env.TESTOMATIO_LABEL;
37
-
41
+ // Create a new instance of axios with a custom config
38
42
  this.axios = axios.create({
39
43
  baseURL: `${this.url.trim()}`,
40
- timeout: 30000
44
+ timeout: AXIOS_TIMEOUT,
45
+ });
46
+ // Pass the axios instance to the retry function
47
+ axiosRetry(this.axios, {
48
+ retries: 3, // Number of retries (Defaults to 3)
49
+ shouldResetTimeout: true,
50
+ retryCondition: error => {
51
+ // Conditional check the error status code
52
+ switch (error.response.status) {
53
+ case 409:
54
+ case 429:
55
+ case 502:
56
+ case 503:
57
+ return true; // Retry request with response status code 409, 429, 502, 503
58
+ default:
59
+ return false; // Do not retry the others
60
+ }
61
+ },
62
+ retryDelay: retryCount => retryCount * AXIOS_RETRY_TIMEOUT, // sum = 15sec
63
+ onRetry: retryCount => {
64
+ debug(`Retry attempt #${retryCount} failed. Retrying again...`);
65
+ },
41
66
  });
42
67
 
43
68
  this.isEnabled = true;
@@ -57,7 +82,7 @@ class TestomatioPipe {
57
82
  /**
58
83
  * Asynchronously prepares and retrieves the Testomat.io test grepList based on the provided options.
59
84
  * @param {Object} opts - The options for preparing the test grepList.
60
- * @returns {Promise<string[]>} - An array containing the retrieved
85
+ * @returns {Promise<string[]>} - An array containing the retrieved
61
86
  * test grepList, or an empty array if no tests are found or the request is disabled.
62
87
  * @throws {Error} - Throws an error if there was a problem while making the request.
63
88
  */
@@ -70,7 +95,7 @@ class TestomatioPipe {
70
95
  const q = generateFilterRequestParams({
71
96
  type,
72
97
  id,
73
- apiKey: this.apiKey.trim()
98
+ apiKey: this.apiKey.trim(),
74
99
  });
75
100
 
76
101
  if (!q) {
@@ -84,14 +109,10 @@ class TestomatioPipe {
84
109
  foundedTestLog(APP_PREFIX, data.tests);
85
110
  return data.tests;
86
111
  }
87
-
112
+
88
113
  console.log(APP_PREFIX, `⛔ No tests found for your --filter --> ${type}=${id}`);
89
- }
90
- catch (err) {
91
- console.error(
92
- APP_PREFIX,
93
- `🚩 Error getting Testomat.io test grepList: ${err}`,
94
- );
114
+ } catch (err) {
115
+ console.error(APP_PREFIX, `🚩 Error getting Testomat.io test grepList: ${err}`);
95
116
  }
96
117
  }
97
118
 
@@ -150,10 +171,13 @@ class TestomatioPipe {
150
171
  maxContentLength: Infinity,
151
172
  maxBodyLength: Infinity,
152
173
  });
174
+
153
175
  this.runId = resp.data.uid;
154
176
  this.runUrl = `${this.url}/${resp.data.url.split('/').splice(3).join('/')}`;
155
177
  this.runPublicUrl = resp.data.public_url;
178
+
156
179
  if (resp.data.artifacts) setS3Credentials(resp.data.artifacts);
180
+
157
181
  this.store.runUrl = this.runUrl;
158
182
  this.store.runPublicUrl = this.runPublicUrl;
159
183
  this.store.runId = this.runId;
@@ -184,37 +208,38 @@ class TestomatioPipe {
184
208
 
185
209
  debug('Adding test', json);
186
210
 
187
- return this.axios.post(`/api/reporter/${this.runId}/testrun`, json, {
188
- maxContentLength: Infinity,
189
- maxBodyLength: Infinity,
190
- headers: {
191
- // Overwrite Axios's automatically set Content-Type
192
- 'Content-Type': 'application/json',
193
- },
194
- })
195
- .catch(err => {
196
- if (err.response) {
197
- if (err.response.status >= 400) {
198
- const responseData = err.response.data || { message: '' };
211
+ return this.axios
212
+ .post(`/api/reporter/${this.runId}/testrun`, json, {
213
+ maxContentLength: Infinity,
214
+ maxBodyLength: Infinity,
215
+ headers: {
216
+ // Overwrite Axios's automatically set Content-Type
217
+ 'Content-Type': 'application/json',
218
+ },
219
+ })
220
+ .catch(err => {
221
+ if (err.response) {
222
+ if (err.response.status >= 400) {
223
+ const responseData = err.response.data || { message: '' };
224
+ console.log(
225
+ APP_PREFIX,
226
+ chalk.yellow(`Warning: ${responseData.message} (${err.response.status})`),
227
+ chalk.grey(data?.title || ''),
228
+ );
229
+ if (err.response.data.message.includes('could not be matched')) {
230
+ this.hasUnmatchedTests = true;
231
+ }
232
+ return;
233
+ }
199
234
  console.log(
200
235
  APP_PREFIX,
201
- chalk.yellow(`Warning: ${responseData.message} (${err.response.status})`),
202
- chalk.grey(data?.title || ''),
236
+ chalk.yellow(`Warning: ${data?.title || ''} (${err.response?.status})`),
237
+ `Report couldn't be processed: ${err?.response?.data?.message}`,
203
238
  );
204
- if (err.response.data.message.includes('could not be matched')) {
205
- this.hasUnmatchedTests = true;
206
- }
207
- return;
239
+ } else {
240
+ console.log(APP_PREFIX, chalk.blue(data?.title || ''), "Report couldn't be processed", err);
208
241
  }
209
- console.log(
210
- APP_PREFIX,
211
- chalk.yellow(`Warning: ${data?.title || ''} (${err.response?.status})`),
212
- `Report couldn't be processed: ${err?.response?.data?.message}`,
213
- );
214
- } else {
215
- console.log(APP_PREFIX, chalk.blue(data?.title || ''), "Report couldn't be processed", err);
216
- }
217
- });
242
+ });
218
243
  }
219
244
 
220
245
  /**
@@ -26,7 +26,7 @@ class Logger {
26
26
  // set default logger to be used in log, warn, error, etc methods
27
27
  #originalUserLogger = { ...console };
28
28
 
29
- #isConsoleIntercepted = false;
29
+ #userLoggerWithOverridenMethods;
30
30
 
31
31
  static #instance;
32
32
 
@@ -197,16 +197,18 @@ class Logger {
197
197
  * @param {*} userLogger
198
198
  */
199
199
  intercept(userLogger) {
200
- /* prevent multiple console interceptions (cause of infinite loop)
201
- actual only for "console", because its used as default output and is intercepted by default */
202
- const isUserLoggerConsole = userLogger.toString?.().toLowerCase() === '[object console]';
203
- if (isUserLoggerConsole && this.#isConsoleIntercepted) {
204
- debug(`Try to intercept console, but it is already intercepted`);
205
- return;
200
+ // STEP 1: reset previously intercepted logger methods to original
201
+ if (this.#userLoggerWithOverridenMethods) {
202
+ for (const method of LOG_METHODS) {
203
+ this.#userLoggerWithOverridenMethods[method] = this.#originalUserLogger[method];
204
+ }
206
205
  }
207
206
 
208
- global.TESTOMATIO_LOGGER_CONSOLE_INTERCEPTED = true;
209
- debug(isUserLoggerConsole ? 'console intercepted' : 'User logger intercepted');
207
+ // STEP 2: intercept new logger
208
+ this.#originalUserLogger = { ...userLogger };
209
+
210
+ const isUserLoggerConsole = userLogger.toString?.().toLowerCase() === '[object console]';
211
+ debug(`Intercepting ${isUserLoggerConsole ? 'console' : 'some user'} logger}`);
210
212
 
211
213
  // override user logger (any, e.g. console) methods to intercept log messages
212
214
  for (const method of LOG_METHODS) {
@@ -219,10 +221,7 @@ class Logger {
219
221
  userLogger[method] = (...args) => this[method](...args);
220
222
  }
221
223
 
222
- /* Playwright
223
- Playwright intercepts console messages by default. Thus when we intercept any logger and provide output by console,
224
- messages are intercepted by Playwright.
225
- */
224
+ this.#userLoggerWithOverridenMethods = userLogger;
226
225
 
227
226
  /*
228
227
  Initial idea was to intercept any logger (tracer, pino, etc),
@@ -232,11 +231,22 @@ class Logger {
232
231
  Also its difficult to understand (actually did not find the way to do it) if logger was already intercepted or not.
233
232
  Thus, decided to intercept only console by default and provide output by default console.
234
233
  It means, if user uses his own logger, its messages will be intercepted,
235
- but the output will be provided by console.
234
+ but the output will be always provided by console.
236
235
  TODO: try to implement the providing output to terminal by user logger
237
236
  */
238
237
  }
239
238
 
239
+ stopInterception() {
240
+ debug('Stop ntercepting logs');
241
+
242
+ // restore original user logger
243
+ if (this.#userLoggerWithOverridenMethods) {
244
+ for (const method of LOG_METHODS) {
245
+ this.#userLoggerWithOverridenMethods[method] = this.#originalUserLogger[method];
246
+ }
247
+ }
248
+ }
249
+
240
250
  /**
241
251
  * Allows to configure logger. Make sure you do it before the logger usage in your code.
242
252
  *
@@ -269,7 +279,6 @@ I found the only ability to get any logs using .task('log', 'message') (this is
269
279
  and then intercept it with:
270
280
  on('task', {
271
281
  log (message) {
272
- console.log(message)
273
282
  return null
274
283
  }
275
284
  })
@@ -298,8 +298,11 @@ function removeColorCodes(input) {
298
298
  return input.replace(/\x1b\[[0-9;]*m/g, '');
299
299
  }
300
300
 
301
- const jestHelpers = {
301
+ const testRunnerHelper = {
302
+ // for Jest
302
303
  getNameOfCurrentlyRunningTest: () => {
304
+ if (global.testomatioTestTitle) return global.testomatioTestTitle;
305
+
303
306
  if (!process.env.JEST_WORKER_ID) return null;
304
307
  try {
305
308
  // TODO: expect?.getState()?.testPath + ' ' + expect?.getState()?.currentTestName
@@ -329,5 +332,5 @@ module.exports = {
329
332
  humanize,
330
333
  removeColorCodes,
331
334
  foundedTestLog,
332
- jestHelpers,
335
+ testRunnerHelper,
333
336
  };
package/lib/xmlReader.js CHANGED
@@ -15,7 +15,7 @@ const {
15
15
  const upload = require('./fileUploader');
16
16
  const pipesFactory = require('./pipe');
17
17
  const adapterFactory = require('./junit-adapter');
18
- const { TESTOMATIO } = require('./config');
18
+ const config = require('./config');
19
19
 
20
20
  const TESTOMATIO_URL = process.env.TESTOMATIO_URL || 'https://app.testomat.io';
21
21
  const { TESTOMATIO_RUNGROUP_TITLE, TESTOMATIO_TITLE, TESTOMATIO_ENV, TESTOMATIO_RUN } = process.env;
@@ -33,7 +33,7 @@ const reduceOptions = {};
33
33
  class XmlReader {
34
34
  constructor(opts = {}) {
35
35
  this.requestParams = {
36
- apiKey: opts.apiKey || TESTOMATIO,
36
+ apiKey: opts.apiKey || config.TESTOMATIO,
37
37
  url: opts.url || TESTOMATIO_URL,
38
38
  title: TESTOMATIO_TITLE,
39
39
  env: TESTOMATIO_ENV,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "1.1.1",
3
+ "version": "1.1.2-beta-fix-config-2",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "main": "./lib/reporter.js",
6
6
  "typings": "typings/index.d.ts",
@@ -12,7 +12,8 @@
12
12
  "@aws-sdk/lib-storage": "^3.279.0",
13
13
  "@octokit/rest": "^19.0.5",
14
14
  "aws-sdk": "^2.1072.0",
15
- "axios": "^0.25.0",
15
+ "axios": "^1.6.2",
16
+ "axios-retry": "^3.9.1",
16
17
  "callsite-record": "^4.1.4",
17
18
  "chalk": "^4.1.0",
18
19
  "commander": "^4.1.1",
@@ -30,8 +31,8 @@
30
31
  "lodash.memoize": "^4.1.2",
31
32
  "lodash.merge": "^4.6.2",
32
33
  "minimatch": "^9.0.3",
33
- "uuid": "^9.0.0",
34
- "promise-retry": "^2.0.1"
34
+ "promise-retry": "^2.0.1",
35
+ "uuid": "^9.0.0"
35
36
  },
36
37
  "files": [
37
38
  "bin",
@@ -52,7 +53,7 @@
52
53
  "test:adapter:jasmine:example": "./tests/adapter/examples/jasmine/passReporterOpts.sh && jasmine './tests/adapter/examples/jasmine/index.test.js' --reporter=./../../../lib/adapter/jasmine.js",
53
54
  "test:adapter:codecept:example": "codeceptjs run --config='./tests/adapter/examples/codecept/codecept.conf.js'",
54
55
  "test:adapter:cucumber:example": "cd ./tests/adapter/examples/cucumber && npx cucumber-js",
55
- "test:storage": "npx mocha tests-storage/artifact-storage.test.js && npx mocha tests-storage/data-storage.test.js && TESTOMATIO_INTERCEPT_CONSOLE_LOGS=true npx mocha tests-storage/logger.test.js && npx mocha tests-storage/reporter-functions.test.js"
56
+ "test:storage": "npx mocha tests-storage/artifact-storage.test.js && npx mocha tests-storage/data-storage.test.js && TESTOMATIO_INTERCEPT_CONSOLE_LOGS=true npx mocha tests-storage/logger.test.js && npx mocha tests-storage/logger-2.test.js && npx mocha tests-storage/reporter-functions.test.js"
56
57
  },
57
58
  "devDependencies": {
58
59
  "@cucumber/cucumber": "^9.3.0",