@testomatio/reporter 1.1.0-beta.mocha-create.9 → 1.1.0-rc.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.
@@ -1,24 +1,28 @@
1
- const debug = require('debug')('@testomatio/reporter:key-value-storage');
2
- const DataStorage = require('./data-storage');
1
+ const debug = require('debug')('@testomatio/reporter:services-key-value');
2
+ const { dataStorage } = require('../data-storage');
3
3
 
4
4
  class KeyValueStorage {
5
- constructor() {
6
- this.dataStorage = new DataStorage('keyvalue');
5
+ static #instance;
7
6
 
8
- // singleton
9
- if (!KeyValueStorage.instance) {
10
- KeyValueStorage.instance = this;
7
+ /**
8
+ *
9
+ * @returns {KeyValueStorage}
10
+ */
11
+ static getInstance() {
12
+ if (!this.#instance) {
13
+ this.#instance = new KeyValueStorage();
11
14
  }
15
+ return this.#instance;
12
16
  }
13
17
 
14
18
  /**
15
19
  * Stores key-value pair and passes it to reporter
16
20
  * @param {{key: string}} keyValue - key-value pair(s) as object
17
- * @param {*} context testId or test title
21
+ * @param {*} context - full test title
18
22
  */
19
23
  put(keyValue, context = null) {
20
24
  if (!keyValue) return;
21
- this.dataStorage.putData(keyValue, context);
25
+ dataStorage.putData('keyvalue', keyValue, context);
22
26
  }
23
27
 
24
28
  #isKeyValueObject(smth) {
@@ -28,13 +32,11 @@ class KeyValueStorage {
28
32
  /**
29
33
  * Returns key-values pairs for the test as object
30
34
  * @param {*} context testId or test context from test runner
31
- * @returns {Object} key-values pairs as object, e.g. {priority: 'high', browser: 'chrome'}
35
+ * @returns {{[key: string]: string} | {}} key-values pairs as object, e.g. {priority: 'high', browser: 'chrome'}
32
36
  */
33
- get(context) {
34
- if (!context) return null;
35
-
36
- const keyValuesList = this.dataStorage.getData(context);
37
- if (!keyValuesList || !keyValuesList?.length) return null;
37
+ get(context = null) {
38
+ const keyValuesList = dataStorage.getData('keyvalue', context);
39
+ if (!keyValuesList || !keyValuesList?.length) return {};
38
40
 
39
41
  const keyValues = {};
40
42
  for (const keyValue of keyValuesList) {
@@ -49,10 +51,8 @@ class KeyValueStorage {
49
51
  }
50
52
  }
51
53
 
52
- return Object.keys(keyValues).length ? keyValues : null;
54
+ return keyValues;
53
55
  }
54
56
  }
55
57
 
56
- KeyValueStorage.instance = null;
57
-
58
- module.exports = new KeyValueStorage();
58
+ module.exports.keyValueStorage = KeyValueStorage.getInstance();
@@ -1,6 +1,6 @@
1
1
  const chalk = require('chalk');
2
- const debug = require('debug')('@testomatio/reporter:logger');
3
- const DataStorage = require('./data-storage');
2
+ const debug = require('debug')('@testomatio/reporter:services-logger');
3
+ const { dataStorage } = require('../data-storage');
4
4
 
5
5
  const LOG_METHODS = ['assert', 'debug', 'error', 'info', 'log', 'trace', 'warn'];
6
6
  const LEVELS = {
@@ -26,18 +26,26 @@ class Logger {
26
26
  // set default logger to be used in log, warn, error, etc methods
27
27
  #originalUserLogger = { ...console };
28
28
 
29
- #dataStorage = new DataStorage('log');
29
+ #isConsoleIntercepted = false;
30
+
31
+ static #instance;
32
+
33
+ /**
34
+ *
35
+ * @returns {Logger}
36
+ */
37
+ static getInstance() {
38
+ if (!this.#instance) {
39
+ this.#instance = new Logger();
40
+ }
41
+ return this.#instance;
42
+ }
30
43
 
31
44
  logLevel = process?.env?.LOG_LEVEL?.toUpperCase() || 'ALL';
32
45
 
33
46
  constructor() {
34
47
  // intercept console by default
35
48
  this.intercept(console);
36
-
37
- // singleton
38
- if (!Logger.instance) {
39
- Logger.instance = this;
40
- }
41
49
  }
42
50
 
43
51
  /**
@@ -55,17 +63,18 @@ class Logger {
55
63
  }
56
64
  }
57
65
  logs = chalk.blue(`> ${logs}`);
58
- this.#dataStorage.putData(logs);
66
+ dataStorage.putData('log', logs);
59
67
  }
60
68
 
61
69
  /**
62
70
  *
63
- * @param {*} context testId or test context from test runner
64
- * @returns
71
+ * @param {string} context testId or test context from test runner
72
+ * @returns {string[]}
65
73
  */
66
74
  getLogs(context) {
67
- const logs = this.#dataStorage.getData(context);
68
- return logs || '';
75
+ const logs = dataStorage.getData('log', context);
76
+ if (!logs) return [];
77
+ return logs;
69
78
  }
70
79
 
71
80
  #stringifyLogs(...args) {
@@ -124,7 +133,7 @@ class Logger {
124
133
  logs = this.#stringifyLogs(strings, ...args);
125
134
  }
126
135
  this.#originalUserLogger.log(logs);
127
- this.#dataStorage.putData(logs);
136
+ dataStorage.putData('log', logs);
128
137
  }
129
138
 
130
139
  /**
@@ -140,8 +149,13 @@ class Logger {
140
149
  if (severity < LEVELS[this.logLevel]?.severity) return;
141
150
 
142
151
  const logs = this.#stringifyLogs(...argsArray);
152
+
143
153
  const colorizedLogs = chalk[LEVELS[level].color](logs);
144
- this.#dataStorage.putData(colorizedLogs);
154
+ // do not attach logs from testomatio reporter itself
155
+ if (!logs.includes('[TESTOMATIO]')) {
156
+ dataStorage.putData('log', colorizedLogs);
157
+ }
158
+
145
159
  try {
146
160
  // level.toLowerCase() represents method name (log, warn, error, etc)
147
161
  this.#originalUserLogger[level.toLowerCase()](colorizedLogs);
@@ -187,7 +201,7 @@ class Logger {
187
201
  /* prevent multiple console interceptions (cause of infinite loop)
188
202
  actual only for "console", because its used as default output and is intercepted by default */
189
203
  const isUserLoggerConsole = userLogger.toString?.().toLowerCase() === '[object console]';
190
- if (isUserLoggerConsole && global.TESTOMATIO_LOGGER_CONSOLE_INTERCEPTED) {
204
+ if (isUserLoggerConsole && this.#isConsoleIntercepted) {
191
205
  debug(`Try to intercept console, but it is already intercepted`);
192
206
  return;
193
207
  }
@@ -239,11 +253,7 @@ class Logger {
239
253
  }
240
254
  }
241
255
 
242
- Logger.instance = null;
243
-
244
- const logger = new Logger();
245
-
246
- module.exports = logger;
256
+ module.exports.logger = Logger.getInstance();
247
257
 
248
258
  // TODO: parse passed arguments as {level: 'str', message: 'str'} because some loggers use such syntax;
249
259
  // upd: did not face such loggers, but still could be useful
@@ -288,3 +298,6 @@ Finally, in the test it will look like:
288
298
 
289
299
  Parallelization in Cypress is only available if using Cypress Dashboard??
290
300
  */
301
+
302
+ // TODO: add time to logs
303
+ // TODO: add logger name to logs?
@@ -141,7 +141,15 @@ const fetchSourceCode = (contents, opts = {}) => {
141
141
  // remove special chars from title
142
142
  if (!lineIndex && opts.title) {
143
143
  const title = opts.title.replace(/[([@].*/g, '');
144
- lineIndex = lines.findIndex(l => l.includes(title));
144
+
145
+ if (opts.lang === 'java') {
146
+ lineIndex = lines.findIndex(l => l.includes(`test${title}`));
147
+ if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`@DisplayName("${title}`));
148
+ if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
149
+ if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`${title}(`));
150
+ } else {
151
+ lineIndex = lines.findIndex(l => l.includes(title));
152
+ }
145
153
  }
146
154
 
147
155
  if (opts.prepend) {
@@ -294,9 +302,10 @@ const jestHelpers = {
294
302
  getIdOfCurrentlyRunningTest: () => {
295
303
  if (!process.env.JEST_WORKER_ID) return null;
296
304
  try {
305
+ // TODO: expect?.getState()?.testPath + ' ' + expect?.getState()?.currentTestName
297
306
  // @ts-expect-error "expect" could only be defined inside Jest environement (forbidden to import it outside)
298
307
  // eslint-disable-next-line no-undef
299
- if (expect && expect?.getState()?.currentTestName) return parseTest(expect?.getState()?.currentTestName);
308
+ return expect?.getState()?.currentTestName;
300
309
  } catch (e) {
301
310
  return null;
302
311
  }
@@ -312,7 +321,6 @@ module.exports = {
312
321
  fetchFilesFromStackTrace,
313
322
  fileSystem,
314
323
  getCurrentDateTime,
315
- jestHelpers,
316
324
  specificTestInfo,
317
325
  isValidUrl,
318
326
  ansiRegExp,
@@ -320,5 +328,6 @@ module.exports = {
320
328
  parseSuite,
321
329
  humanize,
322
330
  removeColorCodes,
323
- foundedTestLog
331
+ foundedTestLog,
332
+ jestHelpers,
324
333
  };
package/lib/xmlReader.js CHANGED
@@ -1,35 +1,36 @@
1
1
  const debug = require('debug')('@testomatio/reporter:xml');
2
- const path = require("path");
2
+ const path = require('path');
3
3
  const chalk = require('chalk');
4
- const fs = require("fs");
5
- const { XMLParser } = require("fast-xml-parser");
4
+ const fs = require('fs');
5
+ const { XMLParser } = require('fast-xml-parser');
6
6
  const { APP_PREFIX, STATUS } = require('./constants');
7
- const { fetchFilesFromStackTrace,
8
- fetchIdFromOutput,
9
- fetchSourceCode,
10
- fetchSourceCodeFromStackTrace,
11
- fetchIdFromCode,
12
- humanize
13
- } = require('./utils/utils');
7
+ const {
8
+ fetchFilesFromStackTrace,
9
+ fetchIdFromOutput,
10
+ fetchSourceCode,
11
+ fetchSourceCodeFromStackTrace,
12
+ fetchIdFromCode,
13
+ humanize,
14
+ } = require('./utils/utils');
14
15
  const upload = require('./fileUploader');
15
16
  const pipesFactory = require('./pipe');
16
17
  const adapterFactory = require('./junit-adapter');
18
+ const { TESTOMATIO } = require('./config');
17
19
 
18
- const TESTOMATIO_URL = process.env.TESTOMATIO_URL || "https://app.testomat.io";
19
- const { TESTOMATIO_RUNGROUP_TITLE, TESTOMATIO_TITLE, TESTOMATIO_ENV, TESTOMATIO_RUN, TESTOMATIO } = process.env;
20
+ const TESTOMATIO_URL = process.env.TESTOMATIO_URL || 'https://app.testomat.io';
21
+ const { TESTOMATIO_RUNGROUP_TITLE, TESTOMATIO_TITLE, TESTOMATIO_ENV, TESTOMATIO_RUN } = process.env;
20
22
 
21
23
  const options = {
22
24
  ignoreDeclaration: true,
23
25
  ignoreAttributes: false,
24
26
  alwaysCreateTextNode: false,
25
- attributeNamePrefix: "",
27
+ attributeNamePrefix: '',
26
28
  parseTagValue: true,
27
29
  };
28
30
 
29
31
  const reduceOptions = {};
30
32
 
31
33
  class XmlReader {
32
-
33
34
  constructor(opts = {}) {
34
35
  this.requestParams = {
35
36
  apiKey: opts.apiKey || TESTOMATIO,
@@ -39,18 +40,18 @@ class XmlReader {
39
40
  group_title: TESTOMATIO_RUNGROUP_TITLE,
40
41
  };
41
42
  this.runId = opts.runId || TESTOMATIO_RUN;
42
- this.adapter = adapterFactory(opts.lang?.toLowerCase(), opts)
43
+ this.adapter = adapterFactory(opts.lang?.toLowerCase(), opts);
43
44
  if (!this.adapter) throw new Error('XML adapter for this format not found');
44
45
 
45
46
  this.opts = opts || {};
46
- this.store = {}
47
+ this.store = {};
47
48
  this.pipes = pipesFactory(opts, this.store);
48
49
 
49
50
  this.parser = new XMLParser(options);
50
- this.tests = []
51
- this.stats = {}
51
+ this.tests = [];
52
+ this.stats = {};
52
53
  this.stats.language = opts.lang?.toLowerCase();
53
- this.filesToUpload = {}
54
+ this.filesToUpload = {};
54
55
 
55
56
  this.version = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json')).toString()).version;
56
57
  console.log(APP_PREFIX, `Testomatio Reporter v${this.version}`);
@@ -81,8 +82,8 @@ class XmlReader {
81
82
  } else if (jsonResult.assemblies) {
82
83
  return this.processXUnit(jsonResult.assemblies);
83
84
  } else {
84
- console.log(jsonResult)
85
- throw new Error("Format can't be parsed")
85
+ console.log(jsonResult);
86
+ throw new Error("Format can't be parsed");
86
87
  }
87
88
 
88
89
  return this.processJUnit(jsonSuite);
@@ -95,7 +96,7 @@ class XmlReader {
95
96
  const resultTests = processTestSuite(testsuite);
96
97
 
97
98
  const hasFailures = resultTests.filter(t => t.status === 'failed').length > 0;
98
- const status = (failures > 0 || errors > 0 || hasFailures) ? 'failed' : 'passed';
99
+ const status = failures > 0 || errors > 0 || hasFailures ? 'failed' : 'passed';
99
100
 
100
101
  this.tests = this.tests.concat(resultTests);
101
102
 
@@ -134,21 +135,22 @@ class XmlReader {
134
135
  let defs = jsonSuite?.TestRun?.TestDefinitions?.UnitTest;
135
136
  if (!Array.isArray(defs)) defs = [defs].filter(d => !!d);
136
137
 
137
- const tests = defs.map(td => {
138
- const title = td.name.replace(/\(.*?\)/, '').trim();
139
- let example = td.name.match(/\((.*?)\)/);
140
- if (example) example = { ...example[1].split(',') };
141
- const suite = td.TestMethod.className.split(', ')[0].split('.');
142
- const suite_title = suite.pop();
143
- return {
144
- title,
145
- example,
146
- file: suite.join('/'),
147
- description: td.Description,
148
- suite_title,
149
- id: td.Execution.id,
150
- }
151
- }) || [];
138
+ const tests =
139
+ defs.map(td => {
140
+ const title = td.name.replace(/\(.*?\)/, '').trim();
141
+ let example = td.name.match(/\((.*?)\)/);
142
+ if (example) example = { ...example[1].split(',') };
143
+ const suite = td.TestMethod.className.split(', ')[0].split('.');
144
+ const suite_title = suite.pop();
145
+ return {
146
+ title,
147
+ example,
148
+ file: suite.join('/'),
149
+ description: td.Description,
150
+ suite_title,
151
+ id: td.Execution.id,
152
+ };
153
+ }) || [];
152
154
 
153
155
  let result = jsonSuite?.TestRun?.Results?.UnitTestResult;
154
156
  if (!Array.isArray(result)) result = [result].filter(d => !!d);
@@ -159,10 +161,9 @@ class XmlReader {
159
161
  run_time: parseFloat(td.duration) * 1000,
160
162
  status: td.outcome,
161
163
  stack: td.Output.StdOut,
162
- files: td?.ResultFiles?.ResultFile?.map(rf => rf.path)
164
+ files: td?.ResultFiles?.ResultFile?.map(rf => rf.path),
163
165
  }));
164
166
 
165
-
166
167
  results.forEach(r => {
167
168
  const test = tests.find(t => t.id === r.id) || {};
168
169
  r.suite_title = test.suite_title;
@@ -222,7 +223,7 @@ class XmlReader {
222
223
 
223
224
  if (testCase.failure) {
224
225
  message = testCase.failure.message;
225
- stack = testCase.failure['stack-trace']
226
+ stack = testCase.failure['stack-trace'];
226
227
  }
227
228
  if (testCase.reason) {
228
229
  message = testCase.reason.message;
@@ -249,7 +250,6 @@ class XmlReader {
249
250
  suite_title,
250
251
  run_time,
251
252
  });
252
-
253
253
  });
254
254
  });
255
255
  });
@@ -282,12 +282,12 @@ class XmlReader {
282
282
  passed_count: 0,
283
283
  failed_count: 0,
284
284
  skipped_count: 0,
285
- }
285
+ };
286
286
  this.tests.forEach(t => {
287
287
  this.stats.tests_count++;
288
288
  if (t.status === 'passed') this.stats.passed_count++;
289
289
  if (t.status === 'failed') this.stats.failed_count++;
290
- })
290
+ });
291
291
  if (this.stats.failed_count) this.stats.status = 'failed';
292
292
 
293
293
  return this.stats;
@@ -296,7 +296,7 @@ class XmlReader {
296
296
  fetchSourceCode() {
297
297
  this.tests.forEach(t => {
298
298
  try {
299
- const file = this.adapter.getFilePath(t)
299
+ const file = this.adapter.getFilePath(t);
300
300
  if (!file) return;
301
301
 
302
302
  if (!this.stats.language) {
@@ -309,16 +309,16 @@ class XmlReader {
309
309
  }
310
310
 
311
311
  if (!fs.existsSync(file)) {
312
- debug('Failed to open file with the source code', file)
312
+ debug('Failed to open file with the source code', file);
313
313
  return;
314
314
  }
315
315
  const contents = fs.readFileSync(file).toString();
316
- t.code = fetchSourceCode(contents, { ...t, lang: this.stats.language })
316
+ t.code = fetchSourceCode(contents, { ...t, lang: this.stats.language });
317
317
  if (t.code) debug('Fetched code for test %s', t.title);
318
- t.test_id = fetchIdFromCode(t.code, { lang: this.stats.language })
318
+ t.test_id = fetchIdFromCode(t.code, { lang: this.stats.language });
319
319
  if (t.test_id) debug('Fetched test id %s for test %s', t.test_id, t.title);
320
320
  } catch (err) {
321
- debug(err)
321
+ debug(err);
322
322
  }
323
323
  });
324
324
  }
@@ -326,21 +326,22 @@ class XmlReader {
326
326
  formatTests() {
327
327
  this.tests.forEach(t => {
328
328
  if (t.file) {
329
- t.file = t.file.replace(process.cwd() + path.sep, '')
329
+ t.file = t.file.replace(process.cwd() + path.sep, '');
330
330
  }
331
331
 
332
- this.adapter.formatTest(t)
332
+ this.adapter.formatTest(t);
333
333
 
334
334
  t.title = humanize(t.title);
335
335
  });
336
336
  }
337
337
 
338
338
  formatErrors() {
339
- this.tests.filter(t => !!t.stack).forEach(t => {
340
- t.stack = this.formatStack(t)
341
- t.message = this.adapter.formatMessage(t);
342
- });
343
-
339
+ this.tests
340
+ .filter(t => !!t.stack)
341
+ .forEach(t => {
342
+ t.stack = this.formatStack(t);
343
+ t.message = this.adapter.formatMessage(t);
344
+ });
344
345
  }
345
346
 
346
347
  formatStack(t) {
@@ -358,7 +359,7 @@ class XmlReader {
358
359
  async uploadArtifacts() {
359
360
  for (const test of this.tests.filter(t => !!t.stack)) {
360
361
  let files = [];
361
- if (test.files?.length) files = test.files.map(f => path.join(process.cwd(), f))
362
+ if (test.files?.length) files = test.files.map(f => path.join(process.cwd(), f));
362
363
  files = [...files, ...fetchFilesFromStackTrace(test.stack)];
363
364
 
364
365
  if (!files.length) continue;
@@ -377,7 +378,7 @@ class XmlReader {
377
378
  group_title: this.requestParams.group_title,
378
379
  };
379
380
 
380
- debug("Run", runParams);
381
+ debug('Run', runParams);
381
382
 
382
383
  return Promise.all(this.pipes.map(p => p.createRun(runParams)));
383
384
  }
@@ -390,12 +391,10 @@ class XmlReader {
390
391
  this.formatErrors();
391
392
  this.formatTests();
392
393
 
393
- debug(
394
- 'Uploading data',
395
- {
396
- ...this.stats,
397
- tests: this.tests,
398
- })
394
+ debug('Uploading data', {
395
+ ...this.stats,
396
+ tests: this.tests,
397
+ });
399
398
 
400
399
  const dataString = {
401
400
  ...this.stats,
@@ -410,59 +409,62 @@ class XmlReader {
410
409
 
411
410
  module.exports = XmlReader;
412
411
 
413
-
414
412
  function reduceTestCases(prev, item) {
415
413
  let testCases = item.testcase;
416
414
  if (!testCases) testCases = item['test-case'];
417
415
  if (!Array.isArray(testCases)) {
418
- testCases = [testCases]
416
+ testCases = [testCases];
419
417
  }
420
418
  const suiteOutput = item['system-out'] || item.output || item.log || '';
421
419
  const suiteErr = item['system-err'] || item.output || item.log || '';
422
- testCases.filter(t => !!t).forEach(testCaseItem => {
423
- const file = testCaseItem.file || item.filepath || '';
424
-
425
- let stack = '';
426
- let message = '';
427
- if (testCaseItem.error) stack = testCaseItem.error;
428
- if (testCaseItem.failure) stack = testCaseItem.failure;
429
- if (testCaseItem?.failure?.['stack-trace']) stack = testCaseItem.failure['stack-trace'];
430
- if (testCaseItem?.failure?.message) message = testCaseItem.failure.message;
431
- if (testCaseItem?.error?.message) message = testCaseItem.error.message;
432
-
433
- if (testCaseItem.failure && testCaseItem.failure['#text']) stack = testCaseItem.failure['#text'];
434
- if (testCaseItem.error && testCaseItem.error['#text']) stack = testCaseItem.error['#text'];
435
- if (!message) message = stack.trim().split('\n')[0];
436
-
437
- // eslint-disable-next-line
438
- stack = `${testCaseItem['system-out'] || testCaseItem.output || testCaseItem.log || ''}\n\n${stack}\n\n${suiteOutput}\n\n${suiteErr}`.trim()
439
- const testId = fetchIdFromOutput(stack);
440
-
441
- let status = STATUS.PASSED.toString();
442
- if ('failure' in testCaseItem || 'error' in testCaseItem) status = STATUS.FAILED;
443
- if ('skipped' in testCaseItem) status = STATUS.SKIPPED;
444
-
445
- prev.push({
446
- create: true,
447
- file,
448
- stack,
449
- test_id: testId,
450
- message,
451
- line: testCaseItem.lineno,
452
- // seconds are used in junit reports, but ms are used by testomatio
453
- run_time: parseFloat(testCaseItem.time || testCaseItem.duration) * 1000,
454
- status,
455
- title: testCaseItem.name,
456
- suite_title: reduceOptions.preferClassname ? testCaseItem.classname : (item.name || testCaseItem.classname),
457
- })
458
- });
420
+ testCases
421
+ .filter(t => !!t)
422
+ .forEach(testCaseItem => {
423
+ const file = testCaseItem.file || item.filepath || '';
424
+
425
+ let stack = '';
426
+ let message = '';
427
+ if (testCaseItem.error) stack = testCaseItem.error;
428
+ if (testCaseItem.failure) stack = testCaseItem.failure;
429
+ if (testCaseItem?.failure?.['stack-trace']) stack = testCaseItem.failure['stack-trace'];
430
+ if (testCaseItem?.failure?.message) message = testCaseItem.failure.message;
431
+ if (testCaseItem?.error?.message) message = testCaseItem.error.message;
432
+
433
+ if (testCaseItem.failure && testCaseItem.failure['#text']) stack = testCaseItem.failure['#text'];
434
+ if (testCaseItem.error && testCaseItem.error['#text']) stack = testCaseItem.error['#text'];
435
+ if (!message) message = stack.trim().split('\n')[0];
436
+
437
+ // eslint-disable-next-line
438
+ stack = `${
439
+ testCaseItem['system-out'] || testCaseItem.output || testCaseItem.log || ''
440
+ }\n\n${stack}\n\n${suiteOutput}\n\n${suiteErr}`.trim();
441
+ const testId = fetchIdFromOutput(stack);
442
+
443
+ let status = STATUS.PASSED.toString();
444
+ if ('failure' in testCaseItem || 'error' in testCaseItem) status = STATUS.FAILED;
445
+ if ('skipped' in testCaseItem) status = STATUS.SKIPPED;
446
+
447
+ prev.push({
448
+ create: true,
449
+ file,
450
+ stack,
451
+ test_id: testId,
452
+ message,
453
+ line: testCaseItem.lineno,
454
+ // seconds are used in junit reports, but ms are used by testomatio
455
+ run_time: parseFloat(testCaseItem.time || testCaseItem.duration) * 1000,
456
+ status,
457
+ title: testCaseItem.name,
458
+ suite_title: reduceOptions.preferClassname ? testCaseItem.classname : item.name || testCaseItem.classname,
459
+ });
460
+ });
459
461
  return prev;
460
462
  }
461
463
 
462
464
  function processTestSuite(testsuite) {
463
465
  if (!testsuite) return [];
464
- if (testsuite.testsuite) return processTestSuite(testsuite.testsuite)
465
- if (testsuite['test-suite']) return processTestSuite(testsuite['test-suite'])
466
+ if (testsuite.testsuite) return processTestSuite(testsuite.testsuite);
467
+ if (testsuite['test-suite']) return processTestSuite(testsuite['test-suite']);
466
468
 
467
469
  let suites = testsuite;
468
470
  if (!Array.isArray(testsuite)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "1.1.0-beta.mocha-create.9",
3
+ "version": "1.1.0-rc.2",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "main": "./lib/reporter.js",
6
6
  "typings": "typings/index.d.ts",
@@ -52,7 +52,7 @@
52
52
  "test:adapter:jasmine:example": "./tests/adapter/examples/jasmine/passReporterOpts.sh && jasmine './tests/adapter/examples/jasmine/index.test.js' --reporter=./../../../lib/adapter/jasmine.js",
53
53
  "test:adapter:codecept:example": "codeceptjs run --config='./tests/adapter/examples/codecept/codecept.conf.js'",
54
54
  "test:adapter:cucumber:example": "cd ./tests/adapter/examples/cucumber && npx cucumber-js",
55
- "test:storage": "npx mocha ./tests-storage/**"
55
+ "test:storage": "npx mocha tests-storage/artifact-storage.test.js && npx mocha tests-storage/data-storage.test.js && npx mocha tests-storage/logger.test.js && npx mocha tests-storage/reporter-functions.test.js"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@cucumber/cucumber": "^9.3.0",