@testomatio/reporter 1.1.1-beta-codecept-logger → 1.1.1-file-upload.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.
@@ -1,17 +1,11 @@
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
5
  static #instance;
6
6
 
7
- #context;
8
-
9
- constructor() {
10
- this.dataStorage = new DataStorage('keyvalue');
11
- }
12
-
13
7
  /**
14
- *
8
+ *
15
9
  * @returns {KeyValueStorage}
16
10
  */
17
11
  static getInstance() {
@@ -21,20 +15,14 @@ class KeyValueStorage {
21
15
  return this.#instance;
22
16
  }
23
17
 
24
- /**
25
- * @param {string} context - suite title + test title
26
- */
27
- setContext(context) {
28
- this.#context = context;
29
- }
30
-
31
18
  /**
32
19
  * Stores key-value pair and passes it to reporter
33
20
  * @param {{key: string}} keyValue - key-value pair(s) as object
21
+ * @param {*} context - full test title
34
22
  */
35
- put(keyValue) {
23
+ put(keyValue, context = null) {
36
24
  if (!keyValue) return;
37
- this.dataStorage.putData(keyValue, this.#context);
25
+ dataStorage.putData('keyvalue', keyValue, context);
38
26
  }
39
27
 
40
28
  #isKeyValueObject(smth) {
@@ -44,14 +32,11 @@ class KeyValueStorage {
44
32
  /**
45
33
  * Returns key-values pairs for the test as object
46
34
  * @param {*} context testId or test context from test runner
47
- * @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'}
48
36
  */
49
37
  get(context = null) {
50
- context = context || this.#context;
51
- if (!context) return null;
52
-
53
- const keyValuesList = this.dataStorage.getData(context);
54
- if (!keyValuesList || !keyValuesList?.length) return null;
38
+ const keyValuesList = dataStorage.getData('keyvalue', context);
39
+ if (!keyValuesList || !keyValuesList?.length) return {};
55
40
 
56
41
  const keyValues = {};
57
42
  for (const keyValue of keyValuesList) {
@@ -66,7 +51,7 @@ class KeyValueStorage {
66
51
  }
67
52
  }
68
53
 
69
- return Object.keys(keyValues).length ? keyValues : null;
54
+ return keyValues;
70
55
  }
71
56
  }
72
57
 
@@ -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,9 +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
- #dataStorage;
30
-
31
- #context = null;
29
+ #isConsoleIntercepted = false;
32
30
 
33
31
  static #instance;
34
32
 
@@ -46,27 +44,10 @@ class Logger {
46
44
  logLevel = process?.env?.LOG_LEVEL?.toUpperCase() || 'ALL';
47
45
 
48
46
  constructor() {
49
- this.#dataStorage = new DataStorage('log');
50
-
51
47
  // intercept console by default
52
48
  this.intercept(console);
53
49
  }
54
50
 
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;
68
- }
69
-
70
51
  /**
71
52
  * Allows you to define a step inside a test. Step name is attached to the report and
72
53
  * helps to understand the test flow.
@@ -82,7 +63,7 @@ class Logger {
82
63
  }
83
64
  }
84
65
  logs = chalk.blue(`> ${logs}`);
85
- this.#dataStorage.putData(logs, this.#context);
66
+ dataStorage.putData('log', logs);
86
67
  }
87
68
 
88
69
  /**
@@ -91,7 +72,8 @@ class Logger {
91
72
  * @returns {string[]}
92
73
  */
93
74
  getLogs(context) {
94
- const logs = this.#dataStorage.getData(context);
75
+ const logs = dataStorage.getData('log', context);
76
+ if (!logs) return [];
95
77
  return logs;
96
78
  }
97
79
 
@@ -151,7 +133,7 @@ class Logger {
151
133
  logs = this.#stringifyLogs(strings, ...args);
152
134
  }
153
135
  this.#originalUserLogger.log(logs);
154
- this.#dataStorage.putData(logs, this.#context);
136
+ dataStorage.putData('log', logs);
155
137
  }
156
138
 
157
139
  /**
@@ -168,11 +150,12 @@ class Logger {
168
150
 
169
151
  const logs = this.#stringifyLogs(...argsArray);
170
152
 
171
- // skip logs from testomatio reporter itself
172
- if (logs.includes('[TESTOMATIO]')) return;
173
-
174
153
  const colorizedLogs = chalk[LEVELS[level].color](logs);
175
- this.#dataStorage.putData(colorizedLogs, this.#context);
154
+ // do not attach logs from testomatio reporter itself
155
+ if (!logs.includes('[TESTOMATIO]')) {
156
+ dataStorage.putData('log', colorizedLogs);
157
+ }
158
+
176
159
  try {
177
160
  // level.toLowerCase() represents method name (log, warn, error, etc)
178
161
  this.#originalUserLogger[level.toLowerCase()](colorizedLogs);
@@ -218,7 +201,7 @@ class Logger {
218
201
  /* prevent multiple console interceptions (cause of infinite loop)
219
202
  actual only for "console", because its used as default output and is intercepted by default */
220
203
  const isUserLoggerConsole = userLogger.toString?.().toLowerCase() === '[object console]';
221
- if (isUserLoggerConsole && global.TESTOMATIO_LOGGER_CONSOLE_INTERCEPTED) {
204
+ if (isUserLoggerConsole && this.#isConsoleIntercepted) {
222
205
  debug(`Try to intercept console, but it is already intercepted`);
223
206
  return;
224
207
  }
@@ -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) {
@@ -290,6 +298,20 @@ function removeColorCodes(input) {
290
298
  return input.replace(/\x1b\[[0-9;]*m/g, '');
291
299
  }
292
300
 
301
+ const jestHelpers = {
302
+ getIdOfCurrentlyRunningTest: () => {
303
+ if (!process.env.JEST_WORKER_ID) return null;
304
+ try {
305
+ // TODO: expect?.getState()?.testPath + ' ' + expect?.getState()?.currentTestName
306
+ // @ts-expect-error "expect" could only be defined inside Jest environement (forbidden to import it outside)
307
+ // eslint-disable-next-line no-undef
308
+ return expect?.getState()?.currentTestName;
309
+ } catch (e) {
310
+ return null;
311
+ }
312
+ },
313
+ };
314
+
293
315
  module.exports = {
294
316
  isSameTest,
295
317
  fetchSourceCode,
@@ -306,5 +328,6 @@ module.exports = {
306
328
  parseSuite,
307
329
  humanize,
308
330
  removeColorCodes,
309
- foundedTestLog
331
+ foundedTestLog,
332
+ jestHelpers,
310
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.1-beta-codecept-logger",
3
+ "version": "1.1.1-file-upload.1",
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",