@testomatio/reporter 1.2.1-beta β†’ 1.2.1-beta.codecept-id

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +61 -54
  2. package/lib/adapter/codecept.js +136 -57
  3. package/lib/adapter/cucumber/current.js +103 -60
  4. package/lib/adapter/cucumber/legacy.js +27 -12
  5. package/lib/adapter/cucumber.js +2 -2
  6. package/lib/adapter/cypress-plugin/index.js +52 -25
  7. package/lib/adapter/jasmine.js +1 -1
  8. package/lib/adapter/jest.js +49 -11
  9. package/lib/adapter/mocha.js +103 -51
  10. package/lib/adapter/playwright.js +100 -31
  11. package/lib/adapter/webdriver.js +1 -1
  12. package/lib/bin/reportXml.js +14 -13
  13. package/lib/bin/startTest.js +27 -6
  14. package/lib/client.js +193 -69
  15. package/lib/config.js +34 -0
  16. package/lib/constants.js +19 -7
  17. package/lib/data-storage.js +203 -0
  18. package/lib/fileUploader.js +128 -53
  19. package/lib/junit-adapter/adapter.js +0 -2
  20. package/lib/junit-adapter/csharp.js +3 -4
  21. package/lib/junit-adapter/index.js +3 -3
  22. package/lib/junit-adapter/java.js +35 -17
  23. package/lib/junit-adapter/javascript.js +1 -2
  24. package/lib/junit-adapter/python.js +12 -14
  25. package/lib/junit-adapter/ruby.js +1 -2
  26. package/lib/pipe/csv.js +5 -3
  27. package/lib/pipe/github.js +27 -39
  28. package/lib/pipe/gitlab.js +20 -24
  29. package/lib/pipe/html.js +317 -0
  30. package/lib/pipe/index.js +3 -1
  31. package/lib/pipe/testomatio.js +182 -55
  32. package/lib/reporter-functions.js +46 -0
  33. package/lib/reporter.js +11 -9
  34. package/lib/services/artifacts.js +57 -0
  35. package/lib/services/index.js +13 -0
  36. package/lib/services/key-values.js +58 -0
  37. package/lib/services/logger.js +311 -0
  38. package/lib/template/template-draft.hbs +249 -0
  39. package/lib/template/testomatio.hbs +388 -0
  40. package/lib/utils/pipe_utils.js +128 -0
  41. package/lib/{util.js β†’ utils/utils.js} +145 -12
  42. package/lib/xmlReader.js +211 -122
  43. package/package.json +18 -8
  44. package/lib/_ArtifactStorageOld.js +0 -142
  45. package/lib/artifactStorage.js +0 -25
  46. package/lib/dataStorage.js +0 -180
  47. package/lib/logger.js +0 -278
package/README.md CHANGED
@@ -1,6 +1,5 @@
1
1
  # Testomatio Reporter
2
2
 
3
-
4
3
  πŸ‘‹ Hey, do you need some test reporting?
5
4
 
6
5
  Testomat.io Reporter is a library that integrates with popular **JavaScript and TypeScript** test frameworks to provide a common interface for test reporting. By default, Testomat.io Reporter works with our reporting cloud service [Testomat.io App](https://testomat.io), however it is not locked to it. Reporter can be used as a standalone tool.
@@ -9,18 +8,17 @@ Testomat.io Reporter is a library that integrates with popular **JavaScript and
9
8
 
10
9
  Testomat.io Reporter (this npm package) supports:
11
10
 
12
- * πŸ„ Integarion with all popular [JavaScript/TypeScript frameworks](./docs/frameworks.md)
13
- * πŸ—„οΈ Screenshots, videos, traces [uploaded into S3 bucket](./docs/artifacts.md)
14
- * πŸ”Ž Stack traces and error messages
15
- * πŸ™ [GitHub](./docs/pipes.md#github-pipe) & [GitLab](./docs/pipes.md#gitlab-pipe) integration
16
- * πŸš… Realtime reports
17
- * πŸ—ƒοΈ Other test frameworks supported via [JUNit XML](./docs/junit.md)
18
- * πŸšΆβ€β™€οΈ Steps *(work in progress)*
19
- * πŸ“„ Logger *(work in progress, supports Jest for now)*
20
- * ☁️ Custom properties and metadata *(work in progress)*
21
- * πŸ’― Free & open-source.
22
- * πŸ“Š Public and private Run reports on cloud via [Testomat.io App](https://testomat.io) πŸ‘‡
23
-
11
+ - πŸ„ Integarion with all popular [JavaScript/TypeScript frameworks](./docs/frameworks.md)
12
+ - πŸ—„οΈ Screenshots, videos, traces [uploaded into S3 bucket](./docs/artifacts.md)
13
+ - πŸ”Ž [Stack traces](./docs/stacktrace.md) and error messages
14
+ - πŸ™ [GitHub](./docs/pipes/github.md) & [GitLab](./docs/pipes/gitlab.md) integration
15
+ - πŸš… Realtime reports
16
+ - πŸ—ƒοΈ Other test frameworks supported via [JUNit XML](./docs/junit.md)
17
+ - πŸšΆβ€β™€οΈ Steps _(work in progress)_
18
+ - πŸ“„ [Logger](./docs/logger.md) _(work in progress, supports Jest for now)_
19
+ - ☁️ Custom properties and metadata _(work in progress)_
20
+ - πŸ’― Free & open-source.
21
+ - πŸ“Š Public and private Run reports on cloud via [Testomat.io App](https://testomat.io) πŸ‘‡
24
22
 
25
23
  ![](./docs/images/app.png)
26
24
 
@@ -29,12 +27,12 @@ Testomat.io Reporter (this npm package) supports:
29
27
  Testomat.io Reporter provides common API to store and organize test reports.
30
28
  It can receive test result data from any [test framework](./docs/frameworks.md) and send it to different services via [pipes](./docs/pipes.md).
31
29
 
32
- | 🌊 Input | πŸ“Š Output |
33
- |---------------|----------------------------------------|
34
- | Playwright | Report to GitHub |
35
- | Cypress | Report to GitLab |
36
- | Jest | Report to [Testomat.io](https://testomat.io) |
37
- | ... | ... your custom report |
30
+ | 🌊 Input | πŸ“Š Output |
31
+ | ---------- | -------------------------------------------- |
32
+ | Playwright | Report to GitHub |
33
+ | Cypress | Report to GitLab |
34
+ | Jest | Report to [Testomat.io](https://testomat.io) |
35
+ | ... | ... your custom report |
38
36
 
39
37
  If you use multiple test frameworks and you need to use one customizable reporter, check Testomat.io Reporter, as you can adjust it once and attach it to all your projects.
40
38
 
@@ -46,7 +44,6 @@ Artifacts like screenshots, videos, traces, are **uploaded to your own cloud sto
46
44
 
47
45
  To enable Testomat.io Reporter install `@testomatio/reporter` package
48
46
 
49
-
50
47
  Use one of your favorite package managers:
51
48
 
52
49
  ```
@@ -65,46 +62,52 @@ yarn add @testomatio/reporter --dev
65
62
 
66
63
  ### 1️⃣ Attach Reporter to the Test Runner
67
64
 
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....
65
+ | | | |
66
+ | ----------------------------------------------- | --------------------------------------------- | --------------------------------------------------------- |
67
+ | [Playwright](./docs/frameworks.md#playwright) | [CodeceptJS](./docs/frameworks.md#CodeceptJS) | [Cypress](./docs/frameworks.md#Cypress) |
68
+ | [Jest](./docs/frameworks.md#Jest) | [Mocha](./docs/frameworks.md#Mocha) | [WebDriverIO](./docs/frameworks.md#WebDriverIO) |
69
+ | [TestCafe](./docs/frameworks.md#TestCafe) | [Detox](./docs/frameworks.md#Detox) | [Codeception](https://github.com/testomatio/php-reporter) |
70
+ | [Newman (Postman)](./docs/frameworks.md#Newman) | [JUnit](./docs/junit.md#junit) | [NUnit](./docs/junit.md#nunit) |
71
+ | [PyTest](./docs/junit.md#pytest) | [PHPUnit](./docs/junit.md#phpunit) | [Protractor](./docs/frameworks.md#protractor) |
85
72
 
86
- ### 2️⃣ Configure Reports
73
+ or **any [other via JUnit](./docs/junit.md)** report....
87
74
 
88
- * [Create report on Testomat.io](./docs/pipes.md#testomatio-pipe).
89
- * [Create brief summary report for GitHub Pull Request](./docs/pipes.md#github-pipe) πŸ‘‡
90
- * [Create brief summary report for GitLab Merge Request](./docs/pipes.md#gitlab-pipe).
91
- * [Configure other pipes](./docs/pipes.md) for other ways to process test results output.
75
+ ### 2️⃣ Configure Reports
92
76
 
77
+ - [Create report on Testomat.io](./docs/pipes/testomatio.md).
78
+ - [Create brief summary report for GitHub Pull Request](./docs/pipes/github.md) πŸ‘‡
79
+ - [Create brief summary report for GitLab Merge Request](./docs/pipes/gitlab.md).
80
+ - [Configure other pipes](./docs/pipes/md) for other ways to process test results output.
93
81
 
94
- ![GitHub report](./docs/images/github.png)
82
+ ![GitHub report](./docs/pipes/images/github.png)
95
83
 
96
84
  GitHub report published as a comment to Pull Request:
97
85
 
98
86
  ### 3️⃣ Enable Artifacts Storage
99
87
 
100
- 1. Create bucket on AWS, Google Cloud, or any other cloud storage provider supporting S3 protocol.
88
+ 1. Create bucket on AWS, Google Cloud, or any other cloud storage provider supporting S3 protocol.
101
89
  2. [Pass S3 credentials](./docs/artifacts.md) to reporter to enable artifacts uploading.
102
90
 
103
91
  ### 4️⃣ Use Logger
104
92
 
105
93
  Intercept your logger messages or log anything with our [Logger](./docs/logger.md) (_work in progress_).
106
94
 
107
- ### 5️⃣ Add to CI Pipeline
95
+ ### 5️⃣ TESTOMATIO HTML Report
96
+
97
+ 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.
98
+
99
+ With our reporter, you can:
100
+
101
+ - Easily analyze the results of your test runs in a convenient HTML format.
102
+
103
+ * Visualize data on successful and failed tests, including statistics and error details.
104
+ * Quickly share reports with your team members or stakeholders.
105
+
106
+ ![HTML report](./docs/images/html_reporter_example.gif)
107
+
108
+ Learn more about generating HTML reports [here](./docs/pipes/html.md)
109
+
110
+ ### 6️⃣ Add to CI Pipeline
108
111
 
109
112
  After you tested reporter locally add it to your CI pipeline.
110
113
 
@@ -116,20 +119,23 @@ After you tested reporter locally add it to your CI pipeline.
116
119
 
117
120
  Bring this reporter on CI and never lose test results again!
118
121
 
119
-
120
122
  ## Documentation
121
123
 
122
- * πŸ› οΈ [Frameworks](./docs/frameworks.md)
123
- * β›² [Pipes](./docs/pipes.md)
124
- * πŸ““ [JUnit](./docs/junit.md)
125
- * πŸ—„οΈ [Artifacts](./docs/artifacts.md)
126
- * πŸ”‚ [Workflows](./docs/workflows.md)
127
- * πŸ”‚ [Logger](./docs/logger.md)
124
+ - πŸ› οΈ [Frameworks](./docs/frameworks.md)
125
+ - β›² [Pipes](./docs/pipes.md)
126
+ - [Testomat.io](./docs/pipes/testomatio.md)
127
+ - [GitHub](./docs/pipes/github.md)
128
+ - [Gitlab](./docs/pipes/gitlab.md)
129
+ - [CSV](./docs/pipes/csv.md)
130
+ - [HTML report](./docs/pipes/html.md)
131
+ - πŸ““ [JUnit](./docs/junit.md)
132
+ - πŸ—„οΈ [Artifacts](./docs/artifacts.md)
133
+ - πŸ”‚ [Workflows](./docs/workflows.md)
134
+ - πŸ–ŠοΈ [Logger](./docs/logger.md)
128
135
 
129
136
  ## Development
130
137
 
131
-
132
- ### REST API
138
+ ### REST API
133
139
 
134
140
  Testomat.io App uses REST API to collect data from the reporter.
135
141
 
@@ -144,6 +150,7 @@ To print all reporter logs:
144
150
  ```
145
151
  DEBUG=@testomatio/reporter:*
146
152
  ```
153
+
147
154
  To print all reporter logs of a specific pipe:
148
155
 
149
156
  ```
@@ -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 } = require('../constants');
4
+ const { STATUS, APP_PREFIX, TESTOMAT_TMP_STORAGE_DIR } = require('../constants');
5
5
  const upload = require('../fileUploader');
6
- const Output = require('../output');
6
+ const { parseTest, 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
@@ -16,9 +17,9 @@ let currentMetaStep = [];
16
17
  let error;
17
18
  let stepShift = 0;
18
19
 
19
- const output = new Output({
20
- filterFn: stack => !stack.includes('codeceptjs/lib/output'), // output from codeceptjs
21
- });
20
+ // const output = new Output({
21
+ // filterFn: stack => !stack.includes('codeceptjs/lib/output'), // output from codeceptjs
22
+ // });
22
23
 
23
24
  let stepStart = new Date();
24
25
 
@@ -53,22 +54,73 @@ function CodeceptReporter(config) {
53
54
 
54
55
  // Listening to events
55
56
  event.dispatcher.on(event.all.before, () => {
56
- recorder.add('Creating new run', () => client.createRun());
57
+ // clear tmp dir
58
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
59
+
60
+ // recorder.add('Creating new run', () => );
61
+ client.createRun();
57
62
  videos = [];
58
63
  traces = [];
64
+
65
+ if (!global.testomatioDataStore) global.testomatioDataStore = {};
66
+ });
67
+
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
+ }
59
99
  });
60
100
 
61
- event.dispatcher.on(event.test.before, () => {
101
+ event.dispatcher.on(event.test.before, test => {
102
+ suiteHookRunning = false;
103
+ global.testomatioDataStore.steps = [];
104
+
62
105
  recorder.add(() => {
63
106
  currentMetaStep = [];
64
- output.reset();
65
- output.start();
107
+ // output.reset();
108
+ // output.start();
66
109
  stepShift = 0;
67
110
  });
111
+
112
+ if (!global.testomatioDataStore) global.testomatioDataStore = {};
113
+ // reset steps
114
+ global.testomatioDataStore.steps = [];
115
+
116
+ services.setContext(test.fullTitle());
68
117
  });
69
118
 
70
119
  event.dispatcher.on(event.test.started, test => {
120
+ services.setContext(test.fullTitle());
121
+
71
122
  testTimeMap[test.id] = Date.now();
123
+ // start logging
72
124
  });
73
125
 
74
126
  event.dispatcher.on(event.all.result, async () => {
@@ -92,15 +144,24 @@ function CodeceptReporter(config) {
92
144
  }
93
145
  const testId = parseTest(tags);
94
146
  const testObj = getTestAndMessage(title);
147
+
148
+ const logs = getTestLogs(test);
149
+ const manuallyAttachedArtifacts = services.artifacts.get(test.fullTitle());
150
+ const keyValues = services.keyValues.get(test.fullTitle());
151
+ services.setContext(null);
152
+
95
153
  client.addTestRun(STATUS.PASSED, {
96
154
  ...stripExampleFromTitle(title),
97
155
  suite_title: test.parent && test.parent.title,
98
156
  message: testObj.message,
99
157
  time: getDuration(test),
100
- steps: output.text(),
158
+ steps: global.testomatioDataStore.steps.join('\n') || null,
101
159
  test_id: testId,
160
+ logs,
161
+ manuallyAttachedArtifacts,
162
+ meta: keyValues,
102
163
  });
103
- output.stop();
164
+ // output.stop();
104
165
  });
105
166
 
106
167
  event.dispatcher.on(event.test.failed, (test, err) => {
@@ -125,7 +186,7 @@ function CodeceptReporter(config) {
125
186
  time: 0,
126
187
  });
127
188
  }
128
- output.stop();
189
+ // output.stop();
129
190
  });
130
191
 
131
192
  event.dispatcher.on(event.test.after, test => {
@@ -135,38 +196,44 @@ function CodeceptReporter(config) {
135
196
  failedTests.push(id || title);
136
197
  let testId = parseTest(tags);
137
198
  const testObj = getTestAndMessage(title);
138
- if (error && error.stack && test.steps && test.steps.length) {
139
- error.stack = test.steps[test.steps.length - 1].line();
140
- }
141
199
 
142
200
  const files = [];
143
201
  if (artifacts.screenshot) files.push({ path: artifacts.screenshot, type: 'image/png' });
144
- // todo: video must be uploaded later....
202
+ // todo: video must be uploaded later....
145
203
 
146
-
147
- const reportTestPromise = client.addTestRun(STATUS.FAILED, {
148
- ...stripExampleFromTitle(title),
149
- test_id: testId,
150
- suite_title: test.parent && test.parent.title,
151
- error,
152
- message: testObj.message,
153
- time: getDuration(test),
154
- files,
155
- steps: output.text(),
156
- }).then(pipes => {
157
- testId = pipes.filter(p => p.pipe.includes('Testomatio'))[0]?.result?.data?.test_id;
158
-
159
- debug("artifacts", artifacts);
160
-
161
- for (const aid in artifacts) {
162
- if (aid.startsWith('video')) videos.push({ testId, title, path: artifacts[aid], type: 'video/webm' });
163
- if (aid.startsWith('trace')) traces.push({ testId, title, path: artifacts[aid], type: 'application/zip' });
164
- }
165
- });
204
+ const logs = getTestLogs(test);
205
+ const manuallyAttachedArtifacts = services.artifacts.get(test.fullTitle());
206
+ const keyValues = services.keyValues.get(test.fullTitle());
207
+ services.setContext(null);
208
+
209
+ const reportTestPromise = client
210
+ .addTestRun(STATUS.FAILED, {
211
+ ...stripExampleFromTitle(title),
212
+ test_id: testId,
213
+ suite_title: test.parent && test.parent.title,
214
+ error,
215
+ message: testObj.message,
216
+ time: getDuration(test),
217
+ files,
218
+ steps: global.testomatioDataStore?.steps?.join('\n') || null,
219
+ logs,
220
+ manuallyAttachedArtifacts,
221
+ meta: keyValues,
222
+ })
223
+ .then(pipes => {
224
+ testId = pipes.filter(p => p.pipe.includes('Testomatio'))[0]?.result?.data?.test_id;
225
+
226
+ debug('artifacts', artifacts);
227
+
228
+ for (const aid in artifacts) {
229
+ if (aid.startsWith('video')) videos.push({ testId, title, path: artifacts[aid], type: 'video/webm' });
230
+ if (aid.startsWith('trace')) traces.push({ testId, title, path: artifacts[aid], type: 'application/zip' });
231
+ }
232
+ });
166
233
 
167
234
  reportTestPromises.push(reportTestPromise);
168
235
 
169
- output.stop();
236
+ // output.stop();
170
237
  });
171
238
 
172
239
  event.dispatcher.on(event.test.skipped, test => {
@@ -182,7 +249,7 @@ function CodeceptReporter(config) {
182
249
  message: testObj.message,
183
250
  time: getDuration(test),
184
251
  });
185
- output.stop();
252
+ // output.stop();
186
253
  });
187
254
 
188
255
  event.dispatcher.on(event.step.started, step => {
@@ -207,30 +274,37 @@ function CodeceptReporter(config) {
207
274
  // eslint-disable-next-line no-continue
208
275
  if (!metaSteps[i]) continue;
209
276
  if (metaSteps[i].isBDD()) {
210
- output.push(repeat(stepShift) + chalk.bold(metaSteps[i].toString()) + metaSteps[i].comment);
277
+ // output.push(repeat(stepShift) + chalk.bold(metaSteps[i].toString()) + metaSteps[i].comment);
278
+ global.testomatioDataStore?.steps?.push(
279
+ repeat(stepShift) + chalk.bold(metaSteps[i].toString()) + metaSteps[i].comment,
280
+ );
211
281
  } else {
212
- output.push(repeat(stepShift) + chalk.green.bold(metaSteps[i].toString()));
282
+ // output.push(repeat(stepShift) + chalk.green.bold(metaSteps[i].toString()));
283
+ global.testomatioDataStore?.steps?.push(repeat(stepShift) + chalk.green.bold(metaSteps[i].toString()));
213
284
  }
214
285
  }
215
286
  }
216
287
  currentMetaStep = metaSteps;
217
288
  stepShift = 2 * shift;
218
289
 
219
- const durationMs = (+new Date() - (+stepStart));
290
+ const durationMs = +new Date() - +stepStart;
220
291
  let duration = '';
221
292
  if (durationMs) {
222
293
  duration = repeat(1) + chalk.grey(`(${durationMs}ms)`);
223
294
  }
224
295
 
225
296
  if (step.status === STATUS.FAILED) {
226
- output.push(repeat(stepShift) + chalk.red(step.toString()) + duration);
297
+ // output.push(repeat(stepShift) + chalk.red(step.toString()) + duration);
298
+ global.testomatioDataStore?.steps?.push(repeat(stepShift) + chalk.red(step.toString()) + duration);
227
299
  } else {
228
- output.push(repeat(stepShift) + step.toString() + duration);
300
+ // output.push(repeat(stepShift) + step.toString() + duration);
301
+ global.testomatioDataStore?.steps?.push(repeat(stepShift) + step.toString() + duration);
229
302
  }
230
303
  });
231
304
 
232
305
  event.dispatcher.on(event.step.comment, step => {
233
- output.push(chalk.cyan.bold(step.toString()));
306
+ // output.push(chalk.cyan.bold(step.toString()));
307
+ global.testomatioDataStore?.steps?.push(chalk.cyan.bold(step.toString()));
234
308
  });
235
309
  }
236
310
 
@@ -238,7 +312,7 @@ async function uploadAttachments(client, attachments, messagePrefix, attachmentT
238
312
  if (attachments.length > 0) {
239
313
  console.log(APP_PREFIX, `Attachments: ${messagePrefix} ${attachments.length} ${attachmentType}/-s ...`);
240
314
 
241
- const promises = attachments.map(async (attachment) => {
315
+ const promises = attachments.map(async attachment => {
242
316
  const { testId, title, path, type } = attachment;
243
317
  const file = { path, type, title };
244
318
  return client.addTestRun(undefined, {
@@ -252,18 +326,6 @@ async function uploadAttachments(client, attachments, messagePrefix, attachmentT
252
326
  }
253
327
  }
254
328
 
255
- function parseTest(tags) {
256
- if (tags) {
257
- for (const tag of tags) {
258
- if (tag.startsWith('@T')) {
259
- return tag.substring(2, tag.length);
260
- }
261
- }
262
- }
263
-
264
- return null;
265
- }
266
-
267
329
  function getTestAndMessage(title) {
268
330
  const testObj = { message: '' };
269
331
  const testArr = title.split(/\s(\|\s\{.*?\})/);
@@ -286,4 +348,21 @@ function repeat(num) {
286
348
  return ''.padStart(num, ' ');
287
349
  }
288
350
 
351
+ // TODO: think about moving to some common utils
352
+ function getTestLogs(test) {
353
+ const suiteLogsArr = services.logger.getLogs(test.parent.fullTitle());
354
+ const suiteLogs = suiteLogsArr ? suiteLogsArr.join('\n').trim() : '';
355
+ const testLogsArr = services.logger.getLogs(test.fullTitle());
356
+ const testLogs = testLogsArr ? testLogsArr.join('\n').trim() : '';
357
+
358
+ let logs = '';
359
+ if (suiteLogs) {
360
+ logs += `${chalk.bold('\t--- BeforeSuite ---')}\n${suiteLogs}`;
361
+ }
362
+ if (testLogs) {
363
+ logs += `\n${chalk.bold('\t--- Test ---')}\n${testLogs}`;
364
+ }
365
+ return logs;
366
+ }
367
+
289
368
  module.exports = CodeceptReporter;