@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.
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
 
@@ -153,3 +146,4 @@ To print all reporter logs of a specific pipe:
153
146
  ```
154
147
  DEBUG=@testomatio/reporter:pipe:github
155
148
  ```
149
+
@@ -4,7 +4,7 @@ const TestomatClient = require('../client');
4
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 { logger } = require('../storages/logger');
7
+ const { services } = require('../services');
8
8
 
9
9
  if (!global.codeceptjs) {
10
10
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
@@ -52,8 +52,6 @@ function CodeceptReporter(config) {
52
52
 
53
53
  recorder.startUnlessRunning();
54
54
 
55
- global.testomatioRunningEnvironment = 'codeceptjs';
56
-
57
55
  // Listening to events
58
56
  event.dispatcher.on(event.all.before, () => {
59
57
  // clear tmp dir
@@ -75,11 +73,11 @@ function CodeceptReporter(config) {
75
73
  hookSteps = [];
76
74
  global.testomatioDataStore.steps = [];
77
75
 
78
- logger.setContext(suite.fullTitle());
76
+ services.setContext(suite.fullTitle());
79
77
  });
80
78
 
81
79
  event.dispatcher.on(event.suite.after, () => {
82
- logger.setContext(null);
80
+ services.setContext(null);
83
81
  });
84
82
 
85
83
  event.dispatcher.on(event.hook.started, () => {
@@ -87,13 +85,17 @@ function CodeceptReporter(config) {
87
85
  });
88
86
 
89
87
  event.dispatcher.on(event.hook.passed, () => {
90
- if (suiteHookRunning) hookSteps.push(...global.testomatioDataStore.steps);
91
- if (suiteHookRunning) logger.setContext(null);
88
+ if (suiteHookRunning) {
89
+ hookSteps.push(...global.testomatioDataStore.steps);
90
+ services.setContext(null);
91
+ }
92
92
  });
93
93
 
94
94
  event.dispatcher.on(event.hook.failed, () => {
95
- if (suiteHookRunning) hookSteps.push(...global.testomatioDataStore.steps);
96
- if (suiteHookRunning) logger.setContext(null);
95
+ if (suiteHookRunning) {
96
+ hookSteps.push(...global.testomatioDataStore.steps);
97
+ services.setContext(null);
98
+ }
97
99
  });
98
100
 
99
101
  event.dispatcher.on(event.test.before, test => {
@@ -111,11 +113,12 @@ function CodeceptReporter(config) {
111
113
  // reset steps
112
114
  global.testomatioDataStore.steps = [];
113
115
 
114
- logger.setContext(test.fullTitle());
116
+ services.setContext(test.fullTitle());
115
117
  });
116
118
 
117
119
  event.dispatcher.on(event.test.started, test => {
118
- logger.setContext(test.fullTitle());
120
+ services.setContext(test.fullTitle());
121
+
119
122
  testTimeMap[test.id] = Date.now();
120
123
  if (global.testomatioDataStore) global.testomatioDataStore.currentlyRunningTestId = getIdFromTestTitle(test.title);
121
124
  // start logging
@@ -144,6 +147,9 @@ function CodeceptReporter(config) {
144
147
  const testObj = getTestAndMessage(title);
145
148
 
146
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);
147
153
 
148
154
  client.addTestRun(STATUS.PASSED, {
149
155
  ...stripExampleFromTitle(title),
@@ -153,6 +159,8 @@ function CodeceptReporter(config) {
153
159
  steps: global.testomatioDataStore.steps.join('\n') || null,
154
160
  test_id: testId,
155
161
  logs,
162
+ manuallyAttachedArtifacts,
163
+ meta: keyValues,
156
164
  });
157
165
  // output.stop();
158
166
  });
@@ -195,7 +203,9 @@ function CodeceptReporter(config) {
195
203
  // todo: video must be uploaded later....
196
204
 
197
205
  const logs = getTestLogs(test);
198
- logger.setContext(null);
206
+ const manuallyAttachedArtifacts = services.artifacts.get(test.fullTitle());
207
+ const keyValues = services.keyValues.get(test.fullTitle());
208
+ services.setContext(null);
199
209
 
200
210
  const reportTestPromise = client
201
211
  .addTestRun(STATUS.FAILED, {
@@ -208,6 +218,8 @@ function CodeceptReporter(config) {
208
218
  files,
209
219
  steps: global.testomatioDataStore?.steps?.join('\n') || null,
210
220
  logs,
221
+ manuallyAttachedArtifacts,
222
+ meta: keyValues,
211
223
  })
212
224
  .then(pipes => {
213
225
  testId = pipes.filter(p => p.pipe.includes('Testomatio'))[0]?.result?.data?.test_id;
@@ -351,9 +363,9 @@ function repeat(num) {
351
363
 
352
364
  // TODO: think about moving to some common utils
353
365
  function getTestLogs(test) {
354
- const suiteLogsArr = logger.getLogs(test.parent.fullTitle());
366
+ const suiteLogsArr = services.logger.getLogs(test.parent.fullTitle());
355
367
  const suiteLogs = suiteLogsArr ? suiteLogsArr.join('\n').trim() : '';
356
- const testLogsArr = logger.getLogs(test.fullTitle());
368
+ const testLogsArr = services.logger.getLogs(test.fullTitle());
357
369
  const testLogs = testLogsArr ? testLogsArr.join('\n').trim() : '';
358
370
 
359
371
  let logs = '';
@@ -4,8 +4,9 @@ const chalk = require('chalk');
4
4
  const fs = require('fs');
5
5
  const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../../constants');
6
6
  const TestomatClient = require('../../client');
7
- const logger = require('../../storages/logger');
8
7
  const { parseTest, fileSystem } = require('../../utils/utils');
8
+ const { TESTOMATIO } = require('../../config');
9
+ const { services } = require('../../services');
9
10
 
10
11
  const { GherkinDocumentParser, PickleParser } = formatterHelpers;
11
12
  const { getGherkinScenarioLocationMap, getGherkinStepMap } = GherkinDocumentParser;
@@ -29,10 +30,8 @@ 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 || TESTOMATIO });
33
34
  this.status = STATUS.PASSED;
34
-
35
- global.testomatioRunningEnvironment = 'cucumber:current';
36
35
  }
37
36
 
38
37
  parseEnvelope(envelope) {
@@ -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) {
@@ -4,6 +4,7 @@ const chalk = require('chalk');
4
4
  const { parseTest, fileSystem } = require('../../utils/utils');
5
5
  const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../../constants');
6
6
  const TestomatClient = require('../../client');
7
+ const { TESTOMATIO } = require('../../config');
7
8
 
8
9
  const createTestomatFormatter = apiKey => {
9
10
  if (!apiKey || apiKey === '') {
@@ -151,4 +152,4 @@ const createTestomatFormatter = apiKey => {
151
152
  };
152
153
  };
153
154
 
154
- module.exports = createTestomatFormatter(process.env.TESTOMATIO);
155
+ module.exports = createTestomatFormatter(TESTOMATIO);
@@ -1,18 +1,19 @@
1
1
  const { STATUS } = require('../../constants');
2
2
  const { parseTest, parseSuite } = require('../../utils/utils');
3
3
  const TestomatClient = require('../../client');
4
+ const { TESTOMATIO } = require('../../config');
4
5
 
5
6
  const testomatioReporter = on => {
6
- if (!process.env.TESTOMATIO) {
7
+ if (!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: TESTOMATIO });
11
12
 
12
- on('before:run', async (run) => {
13
+ on('before:run', async run => {
13
14
  // TODO: looks like client.env does not exist
14
15
  if (!client.env) {
15
- client.env = `${run.browser.displayName},${run.system.osName}`
16
+ client.env = `${run.browser.displayName},${run.system.osName}`;
16
17
  }
17
18
  await client.createRun();
18
19
  });
@@ -26,8 +27,9 @@ const testomatioReporter = on => {
26
27
  const lastAttemptIndex = test.attempts.length - 1;
27
28
  const latestAttempt = test.attempts[lastAttemptIndex];
28
29
 
29
- const time = latestAttempt.duration;
30
- 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;
31
33
 
32
34
  let title = test.title.pop();
33
35
  const examples = title.match(/\(example (#\d+)\)/);
@@ -40,23 +42,28 @@ const testomatioReporter = on => {
40
42
  const testId = parseTest(title);
41
43
  const suiteId = parseSuite(suiteTitle);
42
44
 
43
- if (error) {
44
- error.inspect = function() { // eslint-disable-line func-names
45
- if (this && this.codeFrame) {
46
- return this.codeFrame.frame;
47
- }
48
- return '';
49
- }
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
+ };
50
51
  }
51
52
 
53
+ const formattedError = error
54
+ ? {
55
+ message: error.message,
56
+ inspect:
57
+ error.inspect ||
58
+ function () {
59
+ return this.message;
60
+ },
61
+ }
62
+ : '';
63
+
52
64
  const screenshots = Array.isArray(results.screenshots)
53
65
  ? results.screenshots
54
- .filter(
55
- screenshot =>
56
- screenshot?.path &&
57
- screenshot?.path.includes(title) &&
58
- screenshot?.takenAt
59
- )
66
+ .filter(screenshot => screenshot?.path && screenshot?.path.includes(title) && screenshot?.takenAt)
60
67
  .map(screenshot => screenshot.path)
61
68
  : [];
62
69
 
@@ -64,17 +71,30 @@ const testomatioReporter = on => {
64
71
 
65
72
  let state;
66
73
  switch (test.state) {
67
- case 'passed': state = STATUS.PASSED; break;
68
- case 'failed': state = STATUS.FAILED; break;
74
+ case 'passed':
75
+ state = STATUS.PASSED;
76
+ break;
77
+ case 'failed':
78
+ state = STATUS.FAILED;
79
+ break;
69
80
  case 'skipped':
70
- case 'pending':
81
+ case 'pending':
71
82
  default:
72
83
  state = STATUS.SKIPPED;
73
84
  }
74
85
 
75
- addSpecTestsPromises.push(client.addTestRun(state, {
76
- title, time, example, error, files, suite_title: suiteTitle, test_id: testId, suite_id: suiteId
77
- }));
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
+ );
78
98
  }
79
99
 
80
100
  await Promise.all(addSpecTestsPromises);
@@ -1,6 +1,10 @@
1
+ const chalk = require('chalk');
1
2
  const TestomatClient = require('../client');
2
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) {
@@ -16,6 +20,19 @@ class JestReporter {
16
20
  fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
17
21
  }
18
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);
33
+ }
34
+
35
+ // end of test file! (there is also onTestCaseResult listener)
19
36
  onTestResult(test, testResult) {
20
37
  if (!this.client) return;
21
38
 
@@ -31,13 +48,15 @@ class JestReporter {
31
48
  steps = failureMessages[0];
32
49
  }
33
50
  const testId = parseTest(title);
34
- let suite_title;
35
- // this is test without a suite
36
- if (result.fullName === result.title) {
37
- suite_title = testResult.testFilePath.split('/').pop();
38
- } else {
39
- suite_title = result.fullName.replace(result.title, '');
40
- }
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(testResult.fullName);
59
+ const keyValues = services.keyValues.get(testResult.fullName);
41
60
 
42
61
  const deducedStatus = status === 'pending' ? 'skipped' : status;
43
62
  // In jest if test is not matched with test name pattern it is considered as skipped.
@@ -45,11 +64,14 @@ class JestReporter {
45
64
  if (!this._globalConfig.testNamePattern || deducedStatus !== 'skipped') {
46
65
  this.client.addTestRun(deducedStatus, {
47
66
  test_id: testId,
48
- suite_title,
67
+ suite_title: fullSuiteTitle,
49
68
  error,
50
69
  steps,
51
70
  title,
52
71
  time: duration,
72
+ logs,
73
+ manuallyAttachedArtifacts: artifacts,
74
+ meta: keyValues,
53
75
  });
54
76
  }
55
77
  }
@@ -64,4 +86,20 @@ class JestReporter {
64
86
  }
65
87
  }
66
88
 
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}`;
101
+ }
102
+ return logs;
103
+ }
104
+
67
105
  module.exports = JestReporter;
@@ -4,7 +4,8 @@ const chalk = require('chalk');
4
4
  const TestomatClient = require('../client');
5
5
  const { STATUS, TESTOMAT_TMP_STORAGE_DIR } = require('../constants');
6
6
  const { parseTest, fileSystem } = require('../utils/utils');
7
- const { logger } = require('../storages/logger');
7
+ const { TESTOMATIO } = require('../config');
8
+ const { services } = require('../services');
8
9
 
9
10
  const {
10
11
  EVENT_RUN_BEGIN,
@@ -25,7 +26,7 @@ function MochaReporter(runner, opts) {
25
26
  let skipped = 0;
26
27
  // let artifactStore;
27
28
 
28
- const apiKey = opts?.reporterOptions?.apiKey || process.env.TESTOMATIO;
29
+ const apiKey = opts?.reporterOptions?.apiKey || TESTOMATIO;
29
30
 
30
31
  const client = new TestomatClient({ apiKey });
31
32
 
@@ -36,33 +37,41 @@ function MochaReporter(runner, opts) {
36
37
  });
37
38
 
38
39
  runner.on(EVENT_SUITE_BEGIN, async suite => {
39
- logger.setContext(suite.fullTitle());
40
+ services.setContext(suite.fullTitle());
40
41
  });
41
42
 
42
43
  runner.on(EVENT_SUITE_END, async () => {
43
- logger.setContext(null);
44
+ services.setContext(null);
44
45
  });
45
46
 
46
47
  runner.on(EVENT_TEST_BEGIN, async test => {
47
- logger.setContext(test.fullTitle());
48
+ services.setContext(test.fullTitle());
48
49
  });
49
50
 
50
51
  runner.on(EVENT_TEST_END, async () => {
51
- logger.setContext(null);
52
+ services.setContext(null);
52
53
  });
53
54
 
54
55
  runner.on(EVENT_TEST_PASS, async test => {
55
56
  passes += 1;
57
+
56
58
  console.log(chalk.bold.green('✔'), test.fullTitle());
57
59
  const testId = parseTest(test.title);
58
60
 
59
61
  const logs = getTestLogs(test);
62
+ const artifacts = services.artifacts.get(test.fullTitle());
63
+ const keyValues = services.keyValues.get(test.fullTitle());
60
64
 
61
65
  client.addTestRun(STATUS.PASSED, {
62
66
  test_id: testId,
63
- title: test.title,
67
+ suite_title: getSuiteTitle(test),
68
+ title: getTestName(test),
69
+ code: test.body.toString(),
70
+ file: getFile(test),
64
71
  time: test.duration,
65
72
  logs,
73
+ manuallyAttachedArtifacts: artifacts,
74
+ meta: keyValues,
66
75
  });
67
76
  });
68
77
 
@@ -71,7 +80,10 @@ function MochaReporter(runner, opts) {
71
80
  console.log('skip: %s', test.fullTitle());
72
81
  const testId = parseTest(test.title);
73
82
  client.addTestRun(STATUS.SKIPPED, {
74
- title: test.title,
83
+ title: getTestName(test),
84
+ suite_title: getSuiteTitle(test),
85
+ code: test.body.toString(),
86
+ file: getFile(test),
75
87
  test_id: testId,
76
88
  time: test.duration,
77
89
  });
@@ -86,8 +98,11 @@ function MochaReporter(runner, opts) {
86
98
 
87
99
  client.addTestRun(STATUS.FAILED, {
88
100
  error: err,
101
+ suite_title: getSuiteTitle(test),
102
+ file: getFile(test),
89
103
  test_id: testId,
90
- title: test.title,
104
+ title: getTestName(test),
105
+ code: test.body.toString(),
91
106
  time: test.duration,
92
107
  logs,
93
108
  });
@@ -101,9 +116,10 @@ function MochaReporter(runner, opts) {
101
116
  }
102
117
 
103
118
  function getTestLogs(test) {
104
- const suiteLogsArr = logger.getLogs(test.parent.fullTitle());
119
+
120
+ const suiteLogsArr = services.logger.getLogs(test.parent.fullTitle());
105
121
  const suiteLogs = suiteLogsArr ? suiteLogsArr.join('\n').trim() : '';
106
- const testLogsArr = logger.getLogs(test.fullTitle());
122
+ const testLogsArr = services.logger.getLogs(test.fullTitle());
107
123
  const testLogs = testLogsArr ? testLogsArr.join('\n').trim() : '';
108
124
 
109
125
  let logs = '';
@@ -120,3 +136,21 @@ function getTestLogs(test) {
120
136
  Mocha.utils.inherits(MochaReporter, Mocha.reporters.Spec);
121
137
 
122
138
  module.exports = MochaReporter;
139
+
140
+ function getSuiteTitle(test, pathArr = []) {
141
+
142
+ if (test.parent.parent) getSuiteTitle(test.parent, pathArr);
143
+
144
+ pathArr.push(test.parent.title);
145
+
146
+ return pathArr.filter(t => !!t)[0];
147
+ }
148
+
149
+ function getFile(test) {
150
+ return test.parent.file?.replace(process.cwd(), '');
151
+ }
152
+
153
+ function getTestName(test) {
154
+ if (process.env.TESTOMATIO_CREATE === 'fulltitle') return test.fullTitle();
155
+ return test.title;
156
+ }
@@ -17,26 +17,22 @@ class PlaywrightReporter {
17
17
  this.uploads = [];
18
18
  }
19
19
 
20
- onBegin(_config, suite) {
20
+ onBegin(config, suite) {
21
21
  // clean data storage
22
22
  fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
23
23
  if (!this.client) return;
24
24
  this.suite = suite;
25
+ this.config = config;
25
26
  this.client.createRun();
26
27
  }
27
28
 
28
- /*
29
- onTestBegin(test) {
30
- // does not work; value is not to the storage context
31
- global.testTitle = test.title;
32
- } */
33
-
34
29
  onTestEnd(test, result) {
35
30
  if (!this.client) return;
36
31
 
37
- let testId = parseTest(test.title);
38
-
39
32
  const { title } = test;
33
+
34
+ let testId = parseTest(title);
35
+
40
36
  const { error, duration } = result;
41
37
 
42
38
  const suite_title = test.parent ? test.parent.title : null;
@@ -59,7 +55,8 @@ class PlaywrightReporter {
59
55
  title,
60
56
  steps: steps.join('\n'),
61
57
  time: duration,
62
- stack: logs,
58
+ logs,
59
+ // TODO: attach artifacts
63
60
  })
64
61
  .then(pipes => {
65
62
  testId = pipes?.filter(p => p.pipe.includes('Testomatio'))[0]?.result?.data?.test_id;
@@ -77,7 +74,24 @@ class PlaywrightReporter {
77
74
  reportTestPromises.push(reportTestPromise);
78
75
  }
79
76
 
80
- async onEnd(result) {
77
+
78
+ #getArtifactPath(artifact) {
79
+ if (artifact.path) {
80
+ if (path.isAbsolute(artifact.path)) return artifact.path;
81
+
82
+ return path.join(this.config.outputDir || this.config.projects[0].outputDir, artifact.path);
83
+ }
84
+
85
+ if (artifact.body) {
86
+ const fileName = tmpFile();
87
+ fs.writeFileSync(fileName, artifact.body);
88
+ return fileName;
89
+ }
90
+
91
+ return null;
92
+ }
93
+
94
+ async onEnd(result, config) {
81
95
  if (!this.client) return;
82
96
 
83
97
  await Promise.all(reportTestPromises);
@@ -91,11 +105,7 @@ class PlaywrightReporter {
91
105
  const { title, testId, suite_title } = upload;
92
106
 
93
107
  const files = upload.files.map(attachment => {
94
- if (attachment.body) {
95
- const fileName = tmpFile();
96
- fs.writeFileSync(fileName, attachment.body);
97
- }
98
- return { path: attachment.path, title, type: attachment.contentType };
108
+ return { path: this.#getArtifactPath(attachment), title, type: attachment.contentType };
99
109
  });
100
110
 
101
111
  promises.push(
@@ -143,4 +153,20 @@ function tmpFile(prefix = 'tmp.') {
143
153
  return path.join(tmpdir, prefix + crypto.randomBytes(16).toString('hex'));
144
154
  }
145
155
 
156
+ function initPlaywrightForStorage() {
157
+ try {
158
+ // @ts-ignore-next-line
159
+ // eslint-disable-next-line import/no-unresolved
160
+ const { test } = require('@playwright/test');
161
+ // eslint-disable-next-line no-empty-pattern
162
+ test.beforeEach(async ({}, testInfo) => {
163
+ const fullTestTitle = `${testInfo.file}_${testInfo.title}`;
164
+ global.testomatioTestTitle = fullTestTitle;
165
+ });
166
+ } catch (e) {
167
+ // ignore
168
+ }
169
+ }
170
+
146
171
  module.exports = PlaywrightReporter;
172
+ module.exports.initPlaywrightForStorage = initPlaywrightForStorage;
@@ -5,6 +5,7 @@ const chalk = require('chalk');
5
5
  const TestomatClient = require('../client');
6
6
  const { APP_PREFIX, STATUS } = require('../constants');
7
7
  const { version } = require('../../package.json');
8
+ const { TESTOMATIO } = require('../config');
8
9
 
9
10
  console.log(chalk.cyan.bold(` 🤩 Testomat.io Reporter v${version}`));
10
11
 
@@ -20,7 +21,7 @@ program
20
21
 
21
22
  if (opts.envFile) require('dotenv').config(opts.envFile); // eslint-disable-line
22
23
 
23
- const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || process.env.TESTOMATIO;
24
+ const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || TESTOMATIO;
24
25
  const title = process.env.TESTOMATIO_TITLE;
25
26
 
26
27
  if (launch) {