@testomatio/reporter 1.2.0-beta-3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -65,23 +65,16 @@ yarn add @testomatio/reporter --dev
65
65
 
66
66
  ### 1️⃣ Attach Reporter to the Test Runner
67
67
 
68
- * #### [Playwright](./docs/frameworks.md#playwright)
69
- * #### [CodeceptJS](./docs/frameworks.md#CodeceptJS)
70
- * #### [Cypress](./docs/frameworks.md#Cypress)
71
- * #### [Jest](./docs/frameworks.md#Jest)
72
- * #### [Mocha](./docs/frameworks.md#Mocha)
73
- * #### [WebDriverIO](./docs/frameworks.md#WebDriverIO)
74
- * #### [TestCafe](./docs/frameworks.md#TestCafe)
75
- * #### [Detox](./docs/frameworks.md#Detox)
76
- * #### [Codeception](https://github.com/testomatio/php-reporter)
77
- * #### [Newman (Postman)](./docs/frameworks.md#Newman)
78
- * #### [JUnit](./docs/junit.md#junit)
79
- * #### [NUnit](./docs/junit.md#nunit)
80
- * #### [PyTest](./docs/junit.md#pytest)
81
- * #### [PHPUnit](./docs/junit.md#phpunit)
82
- * #### [Protractor](./docs/frameworks.md#protractor)
83
-
84
- or any [other via JUnit](./docs/junit.md) report....
68
+ | | | |
69
+ |--|--|--|
70
+ | [Playwright](./docs/frameworks.md#playwright) | [CodeceptJS](./docs/frameworks.md#CodeceptJS) | [Cypress](./docs/frameworks.md#Cypress) |
71
+ | [Jest](./docs/frameworks.md#Jest) | [Mocha](./docs/frameworks.md#Mocha) | [WebDriverIO](./docs/frameworks.md#WebDriverIO) |
72
+ | [TestCafe](./docs/frameworks.md#TestCafe) | [Detox](./docs/frameworks.md#Detox) | [Codeception](https://github.com/testomatio/php-reporter) |
73
+ | [Newman (Postman)](./docs/frameworks.md#Newman) | [JUnit](./docs/junit.md#junit) | [NUnit](./docs/junit.md#nunit) |
74
+ | [PyTest](./docs/junit.md#pytest) | [PHPUnit](./docs/junit.md#phpunit) | [Protractor](./docs/frameworks.md#protractor) |
75
+
76
+
77
+ or **any [other via JUnit](./docs/junit.md)** report....
85
78
 
86
79
  ### 2️⃣ Configure Reports
87
80
 
@@ -104,7 +97,21 @@ GitHub report published as a comment to Pull Request:
104
97
 
105
98
  Intercept your logger messages or log anything with our [Logger](./docs/logger.md) (_work in progress_).
106
99
 
107
- ### 5️⃣ Add to CI Pipeline
100
+ ### 5️⃣ TESTOMATIO HTML Report
101
+
102
+ Testomatio now features a custom reporting tool that allows you to generate a standalone HTML/CSS report for easy visualization of your test runs. This mode provides a quick way to gain a clear and visually appealing overview of your test execution.
103
+
104
+ With our reporter, you can:
105
+
106
+ - Easily analyze the results of your test runs in a convenient HTML format.
107
+ - Visualize data on successful and failed tests, including statistics and error details.
108
+ - Quickly share reports with your team members or stakeholders.
109
+
110
+ ![HTML report](./docs/images/html_reporter_example.gif)
111
+
112
+ Learn more about generating HTML reports [here](./docs/pipes/html.md)
113
+
114
+ ### 6️⃣ Add to CI Pipeline
108
115
 
109
116
  After you tested reporter locally add it to your CI pipeline.
110
117
 
@@ -125,6 +132,7 @@ Bring this reporter on CI and never lose test results again!
125
132
  * [GitHub](./docs/pipes/github.md)
126
133
  * [Gitlab](./docs/pipes/gitlab.md)
127
134
  * [CSV](./docs/pipes/csv.md)
135
+ * [HTML report](./docs/pipes/html.md)
128
136
  * 📓 [JUnit](./docs/junit.md)
129
137
  * 🗄️ [Artifacts](./docs/artifacts.md)
130
138
  * 🔂 [Workflows](./docs/workflows.md)
@@ -153,3 +161,4 @@ To print all reporter logs of a specific pipe:
153
161
  ```
154
162
  DEBUG=@testomatio/reporter:pipe:github
155
163
  ```
164
+
@@ -1,9 +1,10 @@
1
1
  const debug = require('debug')('@testomatio/reporter:adapter:codeceptjs');
2
2
  const chalk = require('chalk');
3
3
  const TestomatClient = require('../client');
4
- const { STATUS, APP_PREFIX, TESTOMAT_TMP_STORAGE } = require('../constants');
4
+ const { STATUS, APP_PREFIX, TESTOMAT_TMP_STORAGE_DIR } = require('../constants');
5
5
  const upload = require('../fileUploader');
6
6
  const { parseTest: getIdFromTestTitle, fileSystem } = require('../utils/utils');
7
+ const { services } = require('../services');
7
8
 
8
9
  if (!global.codeceptjs) {
9
10
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
@@ -51,21 +52,56 @@ function CodeceptReporter(config) {
51
52
 
52
53
  recorder.startUnlessRunning();
53
54
 
54
- global.testomatioRunningEnvironment = 'codeceptjs';
55
-
56
55
  // Listening to events
57
56
  event.dispatcher.on(event.all.before, () => {
58
57
  // clear tmp dir
59
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
58
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
60
59
 
61
- recorder.add('Creating new run', () => client.createRun());
60
+ // recorder.add('Creating new run', () => );
61
+ client.createRun();
62
62
  videos = [];
63
63
  traces = [];
64
64
 
65
65
  if (!global.testomatioDataStore) global.testomatioDataStore = {};
66
66
  });
67
67
 
68
- event.dispatcher.on(event.test.before, () => {
68
+ let hookSteps = [];
69
+ let suiteHookRunning = false;
70
+
71
+ event.dispatcher.on(event.suite.before, suite => {
72
+ suiteHookRunning = true;
73
+ hookSteps = [];
74
+ global.testomatioDataStore.steps = [];
75
+
76
+ services.setContext(suite.fullTitle());
77
+ });
78
+
79
+ event.dispatcher.on(event.suite.after, () => {
80
+ services.setContext(null);
81
+ });
82
+
83
+ event.dispatcher.on(event.hook.started, () => {
84
+ // global.testomatioDataStore.steps = [];
85
+ });
86
+
87
+ event.dispatcher.on(event.hook.passed, () => {
88
+ if (suiteHookRunning) {
89
+ hookSteps.push(...global.testomatioDataStore.steps);
90
+ services.setContext(null);
91
+ }
92
+ });
93
+
94
+ event.dispatcher.on(event.hook.failed, () => {
95
+ if (suiteHookRunning) {
96
+ hookSteps.push(...global.testomatioDataStore.steps);
97
+ services.setContext(null);
98
+ }
99
+ });
100
+
101
+ event.dispatcher.on(event.test.before, test => {
102
+ suiteHookRunning = false;
103
+ global.testomatioDataStore.steps = [];
104
+
69
105
  recorder.add(() => {
70
106
  currentMetaStep = [];
71
107
  // output.reset();
@@ -76,11 +112,16 @@ function CodeceptReporter(config) {
76
112
  if (!global.testomatioDataStore) global.testomatioDataStore = {};
77
113
  // reset steps
78
114
  global.testomatioDataStore.steps = [];
115
+
116
+ services.setContext(test.fullTitle());
79
117
  });
80
118
 
81
119
  event.dispatcher.on(event.test.started, test => {
120
+ services.setContext(test.fullTitle());
121
+
82
122
  testTimeMap[test.id] = Date.now();
83
123
  if (global.testomatioDataStore) global.testomatioDataStore.currentlyRunningTestId = getIdFromTestTitle(test.title);
124
+ // start logging
84
125
  });
85
126
 
86
127
  event.dispatcher.on(event.all.result, async () => {
@@ -104,6 +145,12 @@ function CodeceptReporter(config) {
104
145
  }
105
146
  const testId = parseTest(tags);
106
147
  const testObj = getTestAndMessage(title);
148
+
149
+ const logs = getTestLogs(test);
150
+ const manuallyAttachedArtifacts = services.artifacts.get(test.fullTitle());
151
+ const keyValues = services.keyValues.get(test.fullTitle());
152
+ services.setContext(null);
153
+
107
154
  client.addTestRun(STATUS.PASSED, {
108
155
  ...stripExampleFromTitle(title),
109
156
  suite_title: test.parent && test.parent.title,
@@ -111,6 +158,9 @@ function CodeceptReporter(config) {
111
158
  time: getDuration(test),
112
159
  steps: global.testomatioDataStore.steps.join('\n') || null,
113
160
  test_id: testId,
161
+ logs,
162
+ manuallyAttachedArtifacts,
163
+ meta: keyValues,
114
164
  });
115
165
  // output.stop();
116
166
  });
@@ -147,14 +197,16 @@ function CodeceptReporter(config) {
147
197
  failedTests.push(id || title);
148
198
  let testId = parseTest(tags);
149
199
  const testObj = getTestAndMessage(title);
150
- if (error && error.stack && test.steps && test.steps.length) {
151
- error.stack = test.steps[test.steps.length - 1].line();
152
- }
153
200
 
154
201
  const files = [];
155
202
  if (artifacts.screenshot) files.push({ path: artifacts.screenshot, type: 'image/png' });
156
203
  // todo: video must be uploaded later....
157
204
 
205
+ const logs = getTestLogs(test);
206
+ const manuallyAttachedArtifacts = services.artifacts.get(test.fullTitle());
207
+ const keyValues = services.keyValues.get(test.fullTitle());
208
+ services.setContext(null);
209
+
158
210
  const reportTestPromise = client
159
211
  .addTestRun(STATUS.FAILED, {
160
212
  ...stripExampleFromTitle(title),
@@ -165,6 +217,9 @@ function CodeceptReporter(config) {
165
217
  time: getDuration(test),
166
218
  files,
167
219
  steps: global.testomatioDataStore?.steps?.join('\n') || null,
220
+ logs,
221
+ manuallyAttachedArtifacts,
222
+ meta: keyValues,
168
223
  })
169
224
  .then(pipes => {
170
225
  testId = pipes.filter(p => p.pipe.includes('Testomatio'))[0]?.result?.data?.test_id;
@@ -233,7 +288,7 @@ function CodeceptReporter(config) {
233
288
  currentMetaStep = metaSteps;
234
289
  stepShift = 2 * shift;
235
290
 
236
- const durationMs = +new Date() - (+stepStart);
291
+ const durationMs = +new Date() - +stepStart;
237
292
  let duration = '';
238
293
  if (durationMs) {
239
294
  duration = repeat(1) + chalk.grey(`(${durationMs}ms)`);
@@ -258,7 +313,7 @@ async function uploadAttachments(client, attachments, messagePrefix, attachmentT
258
313
  if (attachments.length > 0) {
259
314
  console.log(APP_PREFIX, `Attachments: ${messagePrefix} ${attachments.length} ${attachmentType}/-s ...`);
260
315
 
261
- const promises = attachments.map(async (attachment) => {
316
+ const promises = attachments.map(async attachment => {
262
317
  const { testId, title, path, type } = attachment;
263
318
  const file = { path, type, title };
264
319
  return client.addTestRun(undefined, {
@@ -306,4 +361,21 @@ function repeat(num) {
306
361
  return ''.padStart(num, ' ');
307
362
  }
308
363
 
364
+ // TODO: think about moving to some common utils
365
+ function getTestLogs(test) {
366
+ const suiteLogsArr = services.logger.getLogs(test.parent.fullTitle());
367
+ const suiteLogs = suiteLogsArr ? suiteLogsArr.join('\n').trim() : '';
368
+ const testLogsArr = services.logger.getLogs(test.fullTitle());
369
+ const testLogs = testLogsArr ? testLogsArr.join('\n').trim() : '';
370
+
371
+ let logs = '';
372
+ if (suiteLogs) {
373
+ logs += `${chalk.bold('\t--- BeforeSuite ---')}\n${suiteLogs}`;
374
+ }
375
+ if (testLogs) {
376
+ logs += `\n${chalk.bold('\t--- Test ---')}\n${testLogs}`;
377
+ }
378
+ return logs;
379
+ }
380
+
309
381
  module.exports = CodeceptReporter;
@@ -2,10 +2,11 @@
2
2
  const { Formatter, formatterHelpers } = require('@cucumber/cucumber');
3
3
  const chalk = require('chalk');
4
4
  const fs = require('fs');
5
- const { STATUS, TESTOMAT_TMP_STORAGE } = require('../../constants');
5
+ const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../../constants');
6
6
  const TestomatClient = require('../../client');
7
- const logger = require('../../logger');
8
7
  const { parseTest, fileSystem } = require('../../utils/utils');
8
+ const config = require('../../config');
9
+ const { services } = require('../../services');
9
10
 
10
11
  const { GherkinDocumentParser, PickleParser } = formatterHelpers;
11
12
  const { getGherkinScenarioLocationMap, getGherkinStepMap } = GherkinDocumentParser;
@@ -29,15 +30,13 @@ class CucumberReporter extends Formatter {
29
30
  this.failures = [];
30
31
  this.cases = [];
31
32
 
32
- this.client = new TestomatClient({ apiKey: options.apiKey || process.env.TESTOMATIO });
33
+ this.client = new TestomatClient({ apiKey: options.apiKey || config.TESTOMATIO });
33
34
  this.status = STATUS.PASSED;
34
-
35
- global.testomatioRunningEnvironment = 'cucumber:current';
36
35
  }
37
36
 
38
37
  parseEnvelope(envelope) {
39
38
  if (envelope.testRunStarted) {
40
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
39
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
41
40
  }
42
41
  if (envelope.testCaseStarted && this.client) {
43
42
  this.client.createRun();
@@ -49,9 +48,10 @@ class CucumberReporter extends Formatter {
49
48
 
50
49
  onTestCaseStarted(testCaseStarted) {
51
50
  const testCaseAttempt = this.eventDataCollector.getTestCaseAttempt(testCaseStarted.id);
52
- const testId = getTestId(testCaseAttempt.pickle);
53
51
  if (!global.testomatioDataStore) global.testomatioDataStore = {};
54
- global.testomatioDataStore.currentlyRunningTestId = testId;
52
+
53
+ const testTitle = testCaseAttempt.pickle.name + testCaseAttempt.pickle.uri;
54
+ services.setContext(testTitle);
55
55
  }
56
56
 
57
57
  onTestCaseFinished(testCaseFinished) {
@@ -109,7 +109,10 @@ class CucumberReporter extends Formatter {
109
109
 
110
110
  if (!this.client) return;
111
111
 
112
- const logs = logger.getLogs(testId);
112
+ const testTitle = testCaseAttempt.pickle.name + testCaseAttempt.pickle.uri;
113
+ const logs = services.logger.getLogs(testTitle).join('\n');
114
+ const artifacts = services.artifacts.get(testTitle);
115
+ const keyValues = services.keyValues.get(testTitle);
113
116
 
114
117
  this.client.addTestRun(status, {
115
118
  // error: testCaseAttempt.worstTestStepResult.message,
@@ -119,11 +122,15 @@ class CucumberReporter extends Formatter {
119
122
  .join('\n')
120
123
  .trim(),
121
124
  example: { ...example },
122
- stack: logs,
125
+ logs,
126
+ manuallyAttachedArtifacts: artifacts,
127
+ meta: keyValues,
123
128
  title: scenario,
124
129
  test_id: testId,
125
130
  time,
126
131
  });
132
+
133
+ services.setContext(null);
127
134
  }
128
135
 
129
136
  onTestRunFinished(envelope) {
@@ -2,8 +2,9 @@
2
2
  const { Formatter } = require('cucumber');
3
3
  const chalk = require('chalk');
4
4
  const { parseTest, fileSystem } = require('../../utils/utils');
5
- const { STATUS, TESTOMAT_TMP_STORAGE } = require('../../constants');
5
+ const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../../constants');
6
6
  const TestomatClient = require('../../client');
7
+ const config = require('../../config');
7
8
 
8
9
  const createTestomatFormatter = apiKey => {
9
10
  if (!apiKey || apiKey === '') {
@@ -97,7 +98,7 @@ const createTestomatFormatter = apiKey => {
97
98
 
98
99
  options.eventBroadcaster.on('gherkin-document', addDocument);
99
100
  options.eventBroadcaster.on('test-run-started', () => {
100
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
101
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
101
102
  this?.client?.createRun();
102
103
  });
103
104
  options.eventBroadcaster.on('test-case-finished', this.onTestCaseFinished.bind(this));
@@ -151,4 +152,4 @@ const createTestomatFormatter = apiKey => {
151
152
  };
152
153
  };
153
154
 
154
- module.exports = createTestomatFormatter(process.env.TESTOMATIO);
155
+ module.exports = createTestomatFormatter(config.TESTOMATIO);
@@ -1,17 +1,19 @@
1
1
  const { STATUS } = require('../../constants');
2
2
  const { parseTest, parseSuite } = require('../../utils/utils');
3
3
  const TestomatClient = require('../../client');
4
+ const config = require('../../config');
4
5
 
5
6
  const testomatioReporter = on => {
6
- if (!process.env.TESTOMATIO) {
7
+ if (!config.TESTOMATIO) {
7
8
  console.log('TESTOMATIO key is empty, ignoring reports');
8
- return
9
+ return;
9
10
  }
10
- const client = new TestomatClient({ apiKey: process.env.TESTOMATIO });
11
+ const client = new TestomatClient({ apiKey: config.TESTOMATIO });
11
12
 
12
- on('before:run', async (run) => {
13
+ on('before:run', async run => {
14
+ // TODO: looks like client.env does not exist
13
15
  if (!client.env) {
14
- client.env = `${run.browser.displayName},${run.system.osName}`
16
+ client.env = `${run.browser.displayName},${run.system.osName}`;
15
17
  }
16
18
  await client.createRun();
17
19
  });
@@ -25,8 +27,9 @@ const testomatioReporter = on => {
25
27
  const lastAttemptIndex = test.attempts.length - 1;
26
28
  const latestAttempt = test.attempts[lastAttemptIndex];
27
29
 
28
- const time = latestAttempt.duration;
29
- const error = latestAttempt.error;
30
+ // latestAttempt.duration && latestAttempt.error were available in adapters version up to 13 JFYI
31
+ const time = latestAttempt.duration || latestAttempt.wallClockDuration || test.duration;
32
+ let error = latestAttempt.error;
30
33
 
31
34
  let title = test.title.pop();
32
35
  const examples = title.match(/\(example (#\d+)\)/);
@@ -39,35 +42,59 @@ const testomatioReporter = on => {
39
42
  const testId = parseTest(title);
40
43
  const suiteId = parseSuite(suiteTitle);
41
44
 
42
- if (error) {
43
- error.inspect = function() { // eslint-disable-line func-names
44
- if (this && this.codeFrame) {
45
- return this.codeFrame.frame;
46
- }
47
- return '';
48
- }
45
+ if (!error && test.displayError) {
46
+ error = { message: test.displayError };
47
+ error.inspect = function () {
48
+ // eslint-disable-line func-names
49
+ return this.message;
50
+ };
49
51
  }
50
52
 
51
- const screenshots = results.screenshots
52
- .filter(screenshot => screenshot.path.includes(title))
53
- .filter(screenshot => screenshot.testAttemptIndex === lastAttemptIndex)
54
- .map(screenshot => screenshot.path);
53
+ const formattedError = error
54
+ ? {
55
+ message: error.message,
56
+ inspect:
57
+ error.inspect ||
58
+ function () {
59
+ return this.message;
60
+ },
61
+ }
62
+ : '';
63
+
64
+ const screenshots = Array.isArray(results.screenshots)
65
+ ? results.screenshots
66
+ .filter(screenshot => screenshot?.path && screenshot?.path.includes(title) && screenshot?.takenAt)
67
+ .map(screenshot => screenshot.path)
68
+ : [];
55
69
 
56
70
  const files = [...videos, ...screenshots];
57
71
 
58
72
  let state;
59
73
  switch (test.state) {
60
- case 'passed': state = STATUS.PASSED; break;
61
- case 'failed': state = STATUS.FAILED; break;
74
+ case 'passed':
75
+ state = STATUS.PASSED;
76
+ break;
77
+ case 'failed':
78
+ state = STATUS.FAILED;
79
+ break;
62
80
  case 'skipped':
63
- case 'pending':
81
+ case 'pending':
64
82
  default:
65
83
  state = STATUS.SKIPPED;
66
84
  }
67
85
 
68
- addSpecTestsPromises.push(client.addTestRun(state, {
69
- title, time, example, error, files, suite_title: suiteTitle, test_id: testId, suite_id: suiteId
70
- }));
86
+ addSpecTestsPromises.push(
87
+ client.addTestRun(state, {
88
+ title,
89
+ time,
90
+ example,
91
+ error: formattedError,
92
+ files,
93
+ suite_title: suiteTitle,
94
+ test_id: testId,
95
+ suite_id: suiteId,
96
+ }),
97
+ );
71
98
  }
72
99
 
73
100
  await Promise.all(addSpecTestsPromises);
@@ -1,6 +1,10 @@
1
+ const chalk = require('chalk');
1
2
  const TestomatClient = require('../client');
2
- const { STATUS, TESTOMAT_TMP_STORAGE } = require('../constants');
3
+ const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../constants');
3
4
  const { parseTest, ansiRegExp, fileSystem } = require('../utils/utils');
5
+ const { services } = require('../services');
6
+ const debug = require('debug')('@testomatio/reporter:adapter-jest');
7
+ const path = require('path');
4
8
 
5
9
  class JestReporter {
6
10
  constructor(globalConfig, options) {
@@ -11,22 +15,24 @@ class JestReporter {
11
15
  this.client.createRun();
12
16
  }
13
17
 
14
- static getIdOfCurrentlyRunningTest() {
15
- if (!process.env.JEST_WORKER_ID) return null;
16
- try {
17
- // @ts-expect-error "expect" could only be defined inside Jest environement (forbidden to import it outside)
18
- // eslint-disable-next-line no-undef
19
- if (expect && expect?.getState()?.currentTestName) return parseTest(expect?.getState()?.currentTestName);
20
- } catch (e) {
21
- return null;
22
- }
23
- }
24
-
25
18
  onRunStart() {
26
19
  // clear tmp dir
27
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
20
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
21
+ }
22
+
23
+ // start of test file (including beforeAll)
24
+ onTestStart(testFile) {
25
+ debug('Start running test file:', testFile.path);
26
+ services.setContext(testFile.path);
27
+ }
28
+
29
+ // start of the test (including beforeEach)
30
+ onTestCaseStart(test, testCase) {
31
+ debug('Start running test:', testCase.fullName);
32
+ services.setContext(testCase.fullName);
28
33
  }
29
34
 
35
+ // end of test file! (there is also onTestCaseResult listener)
30
36
  onTestResult(test, testResult) {
31
37
  if (!this.client) return;
32
38
 
@@ -42,13 +48,15 @@ class JestReporter {
42
48
  steps = failureMessages[0];
43
49
  }
44
50
  const testId = parseTest(title);
45
- let suite_title;
46
- // this is test without a suite
47
- if (result.fullName === result.title) {
48
- suite_title = testResult.testFilePath.split('/').pop();
49
- } else {
50
- suite_title = result.fullName.replace(result.title, '');
51
- }
51
+
52
+ // suite titles from most outer to most inner, separated by space
53
+ let fullSuiteTitle = testResult.ancestorTitles?.join(' ');
54
+ // if no suite titles, use file name
55
+ if (!fullSuiteTitle && testResult.testFilePath) fullSuiteTitle = path.basename(testResult.testFilePath);
56
+
57
+ const logs = getTestLogs(result);
58
+ const artifacts = services.artifacts.get(result.fullName);
59
+ const keyValues = services.keyValues.get(result.fullName);
52
60
 
53
61
  const deducedStatus = status === 'pending' ? 'skipped' : status;
54
62
  // In jest if test is not matched with test name pattern it is considered as skipped.
@@ -56,11 +64,14 @@ class JestReporter {
56
64
  if (!this._globalConfig.testNamePattern || deducedStatus !== 'skipped') {
57
65
  this.client.addTestRun(deducedStatus, {
58
66
  test_id: testId,
59
- suite_title,
67
+ suite_title: fullSuiteTitle,
60
68
  error,
61
69
  steps,
62
70
  title,
63
71
  time: duration,
72
+ logs,
73
+ manuallyAttachedArtifacts: artifacts,
74
+ meta: keyValues,
64
75
  });
65
76
  }
66
77
  }
@@ -72,10 +83,23 @@ class JestReporter {
72
83
  const { numFailedTests } = results;
73
84
  const status = numFailedTests === 0 ? STATUS.PASSED : STATUS.FAILED;
74
85
  this.client.updateRunStatus(status);
86
+ }
87
+ }
75
88
 
76
- // clear tmp dir
77
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
89
+ function getTestLogs(testResult) {
90
+ const suiteLogsArr = services.logger.getLogs(testResult.testFilePath);
91
+ const suiteLogs = suiteLogsArr ? suiteLogsArr.join('\n').trim() : '';
92
+ const testLogsArr = services.logger.getLogs(testResult.fullName);
93
+ const testLogs = testLogsArr ? testLogsArr.join('\n').trim() : '';
94
+
95
+ let logs = '';
96
+ if (suiteLogs) {
97
+ logs += `${chalk.bold('\t--- Suite ---')}\n${suiteLogs}`;
98
+ }
99
+ if (testLogs) {
100
+ logs += `\n${chalk.bold('\t--- Test ---')}\n${testLogs}`;
78
101
  }
102
+ return logs;
79
103
  }
80
104
 
81
105
  module.exports = JestReporter;