@testomatio/reporter 1.2.0-beta β†’ 1.2.0-beta-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,12 +11,12 @@ Testomat.io Reporter (this npm package) supports:
11
11
 
12
12
  * πŸ„ Integarion with all popular [JavaScript/TypeScript frameworks](./docs/frameworks.md)
13
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
14
+ * πŸ”Ž [Stack traces](./docs/stacktrace.md) and error messages
15
+ * πŸ™ [GitHub](./docs/pipes/github.md) & [GitLab](./docs/pipes/gitlab.md) integration
16
16
  * πŸš… Realtime reports
17
17
  * πŸ—ƒοΈ Other test frameworks supported via [JUNit XML](./docs/junit.md)
18
18
  * πŸšΆβ€β™€οΈ Steps *(work in progress)*
19
- * πŸ“„ Logger *(work in progress, supports Jest for now)*
19
+ * πŸ“„ [Logger](./docs/logger.md) *(work in progress, supports Jest for now)*
20
20
  * ☁️ Custom properties and metadata *(work in progress)*
21
21
  * πŸ’― Free & open-source.
22
22
  * πŸ“Š Public and private Run reports on cloud via [Testomat.io App](https://testomat.io) πŸ‘‡
@@ -85,13 +85,13 @@ or any [other via JUnit](./docs/junit.md) report....
85
85
 
86
86
  ### 2️⃣ Configure Reports
87
87
 
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.
88
+ * [Create report on Testomat.io](./docs/pipes/testomatio.md).
89
+ * [Create brief summary report for GitHub Pull Request](./docs/pipes/github.md) πŸ‘‡
90
+ * [Create brief summary report for GitLab Merge Request](./docs/pipes/gitlab.md).
91
+ * [Configure other pipes](./docs/pipes/md) for other ways to process test results output.
92
92
 
93
93
 
94
- ![GitHub report](./docs/images/github.png)
94
+ ![GitHub report](./docs/pipes/images/github.png)
95
95
 
96
96
  GitHub report published as a comment to Pull Request:
97
97
 
@@ -121,10 +121,14 @@ Bring this reporter on CI and never lose test results again!
121
121
 
122
122
  * πŸ› οΈ [Frameworks](./docs/frameworks.md)
123
123
  * β›² [Pipes](./docs/pipes.md)
124
+ * [Testomat.io](./docs/pipes/testomatio.md)
125
+ * [GitHub](./docs/pipes/github.md)
126
+ * [Gitlab](./docs/pipes/gitlab.md)
127
+ * [CSV](./docs/pipes/csv.md)
124
128
  * πŸ““ [JUnit](./docs/junit.md)
125
129
  * πŸ—„οΈ [Artifacts](./docs/artifacts.md)
126
130
  * πŸ”‚ [Workflows](./docs/workflows.md)
127
- * πŸ”‚ [Logger](./docs/logger.md)
131
+ * πŸ–ŠοΈ [Logger](./docs/logger.md)
128
132
 
129
133
  ## Development
130
134
 
@@ -4,7 +4,7 @@ const fs = require('fs');
4
4
  const os = require('os');
5
5
  const uuid = require('uuid');
6
6
  const { TESTOMAT_ARTIFACT_SUFFIX } = require('./constants');
7
- const { specificTestInfo } = require('./util');
7
+ const { specificTestInfo } = require('./utils/utils');
8
8
 
9
9
  class ArtifactStorage {
10
10
 
@@ -1,9 +1,9 @@
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 } = require('../constants');
5
5
  const upload = require('../fileUploader');
6
- const Output = require('../output');
6
+ const { parseTest: getIdFromTestTitle, fileSystem } = require('../utils/utils');
7
7
 
8
8
  if (!global.codeceptjs) {
9
9
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
@@ -16,9 +16,9 @@ let currentMetaStep = [];
16
16
  let error;
17
17
  let stepShift = 0;
18
18
 
19
- const output = new Output({
20
- filterFn: stack => !stack.includes('codeceptjs/lib/output'), // output from codeceptjs
21
- });
19
+ // const output = new Output({
20
+ // filterFn: stack => !stack.includes('codeceptjs/lib/output'), // output from codeceptjs
21
+ // });
22
22
 
23
23
  let stepStart = new Date();
24
24
 
@@ -51,24 +51,36 @@ function CodeceptReporter(config) {
51
51
 
52
52
  recorder.startUnlessRunning();
53
53
 
54
+ global.testomatioRunningEnvironment = 'codeceptjs';
55
+
54
56
  // Listening to events
55
57
  event.dispatcher.on(event.all.before, () => {
58
+ // clear tmp dir
59
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
60
+
56
61
  recorder.add('Creating new run', () => client.createRun());
57
62
  videos = [];
58
63
  traces = [];
64
+
65
+ if (!global.testomatioDataStore) global.testomatioDataStore = {};
59
66
  });
60
67
 
61
68
  event.dispatcher.on(event.test.before, () => {
62
69
  recorder.add(() => {
63
70
  currentMetaStep = [];
64
- output.reset();
65
- output.start();
71
+ // output.reset();
72
+ // output.start();
66
73
  stepShift = 0;
67
74
  });
75
+
76
+ if (!global.testomatioDataStore) global.testomatioDataStore = {};
77
+ // reset steps
78
+ global.testomatioDataStore.steps = [];
68
79
  });
69
80
 
70
81
  event.dispatcher.on(event.test.started, test => {
71
82
  testTimeMap[test.id] = Date.now();
83
+ if (global.testomatioDataStore) global.testomatioDataStore.currentlyRunningTestId = getIdFromTestTitle(test.title);
72
84
  });
73
85
 
74
86
  event.dispatcher.on(event.all.result, async () => {
@@ -97,10 +109,10 @@ function CodeceptReporter(config) {
97
109
  suite_title: test.parent && test.parent.title,
98
110
  message: testObj.message,
99
111
  time: getDuration(test),
100
- steps: output.text(),
112
+ steps: global.testomatioDataStore.steps.join('\n') || null,
101
113
  test_id: testId,
102
114
  });
103
- output.stop();
115
+ // output.stop();
104
116
  });
105
117
 
106
118
  event.dispatcher.on(event.test.failed, (test, err) => {
@@ -125,7 +137,7 @@ function CodeceptReporter(config) {
125
137
  time: 0,
126
138
  });
127
139
  }
128
- output.stop();
140
+ // output.stop();
129
141
  });
130
142
 
131
143
  event.dispatcher.on(event.test.after, test => {
@@ -141,32 +153,33 @@ function CodeceptReporter(config) {
141
153
 
142
154
  const files = [];
143
155
  if (artifacts.screenshot) files.push({ path: artifacts.screenshot, type: 'image/png' });
144
- // todo: video must be uploaded later....
156
+ // todo: video must be uploaded later....
145
157
 
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
- });
158
+ const reportTestPromise = client
159
+ .addTestRun(STATUS.FAILED, {
160
+ ...stripExampleFromTitle(title),
161
+ test_id: testId,
162
+ suite_title: test.parent && test.parent.title,
163
+ error,
164
+ message: testObj.message,
165
+ time: getDuration(test),
166
+ files,
167
+ steps: global.testomatioDataStore?.steps?.join('\n') || null,
168
+ })
169
+ .then(pipes => {
170
+ testId = pipes.filter(p => p.pipe.includes('Testomatio'))[0]?.result?.data?.test_id;
171
+
172
+ debug('artifacts', artifacts);
173
+
174
+ for (const aid in artifacts) {
175
+ if (aid.startsWith('video')) videos.push({ testId, title, path: artifacts[aid], type: 'video/webm' });
176
+ if (aid.startsWith('trace')) traces.push({ testId, title, path: artifacts[aid], type: 'application/zip' });
177
+ }
178
+ });
166
179
 
167
180
  reportTestPromises.push(reportTestPromise);
168
181
 
169
- output.stop();
182
+ // output.stop();
170
183
  });
171
184
 
172
185
  event.dispatcher.on(event.test.skipped, test => {
@@ -182,7 +195,7 @@ function CodeceptReporter(config) {
182
195
  message: testObj.message,
183
196
  time: getDuration(test),
184
197
  });
185
- output.stop();
198
+ // output.stop();
186
199
  });
187
200
 
188
201
  event.dispatcher.on(event.step.started, step => {
@@ -207,30 +220,37 @@ function CodeceptReporter(config) {
207
220
  // eslint-disable-next-line no-continue
208
221
  if (!metaSteps[i]) continue;
209
222
  if (metaSteps[i].isBDD()) {
210
- output.push(repeat(stepShift) + chalk.bold(metaSteps[i].toString()) + metaSteps[i].comment);
223
+ // output.push(repeat(stepShift) + chalk.bold(metaSteps[i].toString()) + metaSteps[i].comment);
224
+ global.testomatioDataStore?.steps?.push(
225
+ repeat(stepShift) + chalk.bold(metaSteps[i].toString()) + metaSteps[i].comment,
226
+ );
211
227
  } else {
212
- output.push(repeat(stepShift) + chalk.green.bold(metaSteps[i].toString()));
228
+ // output.push(repeat(stepShift) + chalk.green.bold(metaSteps[i].toString()));
229
+ global.testomatioDataStore?.steps?.push(repeat(stepShift) + chalk.green.bold(metaSteps[i].toString()));
213
230
  }
214
231
  }
215
232
  }
216
233
  currentMetaStep = metaSteps;
217
234
  stepShift = 2 * shift;
218
235
 
219
- const durationMs = (+new Date() - (+stepStart));
236
+ const durationMs = +new Date() - (+stepStart);
220
237
  let duration = '';
221
238
  if (durationMs) {
222
239
  duration = repeat(1) + chalk.grey(`(${durationMs}ms)`);
223
240
  }
224
241
 
225
242
  if (step.status === STATUS.FAILED) {
226
- output.push(repeat(stepShift) + chalk.red(step.toString()) + duration);
243
+ // output.push(repeat(stepShift) + chalk.red(step.toString()) + duration);
244
+ global.testomatioDataStore?.steps?.push(repeat(stepShift) + chalk.red(step.toString()) + duration);
227
245
  } else {
228
- output.push(repeat(stepShift) + step.toString() + duration);
246
+ // output.push(repeat(stepShift) + step.toString() + duration);
247
+ global.testomatioDataStore?.steps?.push(repeat(stepShift) + step.toString() + duration);
229
248
  }
230
249
  });
231
250
 
232
251
  event.dispatcher.on(event.step.comment, step => {
233
- output.push(chalk.cyan.bold(step.toString()));
252
+ // output.push(chalk.cyan.bold(step.toString()));
253
+ global.testomatioDataStore?.steps?.push(chalk.cyan.bold(step.toString()));
234
254
  });
235
255
  }
236
256
 
@@ -1,35 +1,59 @@
1
- // eslint-disable-next-line global-require, import/no-extraneous-dependencies
2
- const { Formatter, formatterHelpers } = require("@cucumber/cucumber");
1
+ // eslint-disable-next-line global-require, import/no-extraneous-dependencies, import/no-unresolved
2
+ const { Formatter, formatterHelpers } = require('@cucumber/cucumber');
3
3
  const chalk = require('chalk');
4
4
  const fs = require('fs');
5
- const { STATUS } = require('../../constants');
5
+ const { STATUS, TESTOMAT_TMP_STORAGE } = require('../../constants');
6
6
  const TestomatClient = require('../../client');
7
+ const logger = require('../../logger');
8
+ const { parseTest, fileSystem } = require('../../utils/utils');
9
+
10
+ const { GherkinDocumentParser, PickleParser } = formatterHelpers;
11
+ const { getGherkinScenarioLocationMap, getGherkinStepMap } = GherkinDocumentParser;
12
+ const { getPickleStepMap } = PickleParser;
13
+
14
+ function getTestId(scenario) {
15
+ if (scenario) {
16
+ for (const tag of scenario.tags) {
17
+ const testId = parseTest(tag.name);
18
+ if (testId) return testId;
19
+ }
20
+ }
7
21
 
8
- const { GherkinDocumentParser, PickleParser } = formatterHelpers
9
- const {
10
- getGherkinScenarioLocationMap,
11
- getGherkinStepMap,
12
- } = GherkinDocumentParser
13
- const { getPickleStepMap } = PickleParser
22
+ return null;
23
+ }
14
24
 
15
25
  class CucumberReporter extends Formatter {
16
26
  constructor(options) {
17
27
  super(options);
18
- options.eventBroadcaster.on('envelope', this.parseEnvelope.bind(this))
28
+ options.eventBroadcaster.on('envelope', this.parseEnvelope.bind(this));
19
29
  this.failures = [];
20
30
  this.cases = [];
21
31
 
22
- this.client = new TestomatClient();
32
+ this.client = new TestomatClient({ apiKey: options.apiKey || process.env.TESTOMATIO });
23
33
  this.status = STATUS.PASSED;
24
34
 
35
+ global.testomatioRunningEnvironment = 'cucumber:current';
25
36
  }
26
37
 
27
38
  parseEnvelope(envelope) {
28
- if (envelope.testCaseStarted && this.client) this.client.createRun()
39
+ if (envelope.testRunStarted) {
40
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
41
+ }
42
+ if (envelope.testCaseStarted && this.client) {
43
+ this.client.createRun();
44
+ this.onTestCaseStarted(envelope.testCaseStarted);
45
+ }
29
46
  if (envelope.testCaseFinished) this.onTestCaseFinished(envelope.testCaseFinished);
30
47
  if (envelope.testRunFinished) this.onTestRunFinished(envelope);
31
48
  }
32
49
 
50
+ onTestCaseStarted(testCaseStarted) {
51
+ const testCaseAttempt = this.eventDataCollector.getTestCaseAttempt(testCaseStarted.id);
52
+ const testId = getTestId(testCaseAttempt.pickle);
53
+ if (!global.testomatioDataStore) global.testomatioDataStore = {};
54
+ global.testomatioDataStore.currentlyRunningTestId = testId;
55
+ }
56
+
33
57
  onTestCaseFinished(testCaseFinished) {
34
58
  const testCaseAttempt = this.eventDataCollector.getTestCaseAttempt(testCaseFinished.testCaseStartedId);
35
59
 
@@ -45,10 +69,10 @@ class CucumberReporter extends Formatter {
45
69
  if (testCaseAttempt.worstTestStepResult.status === 'SKIPPED') {
46
70
  status = STATUS.SKIPPED;
47
71
  }
48
- if (testCaseAttempt.worstTestStepResult.status === 'UNDEFINED') {
49
- status = STATUS.SKIPPED;
50
- message = 'Undefined steps. Implement missing steps and rerun this scenario';
51
- }
72
+ // if (testCaseAttempt.worstTestStepResult.status === 'UNDEFINED') {
73
+ // status = STATUS.SKIPPED;
74
+ // message = 'Undefined steps. Implement missing steps and rerun this scenario';
75
+ // }
52
76
  if (testCaseAttempt.worstTestStepResult.status === 'FAILED') {
53
77
  message = testCaseAttempt?.worstTestStepResult?.message;
54
78
  status = STATUS.FAILED;
@@ -64,10 +88,12 @@ class CucumberReporter extends Formatter {
64
88
  }
65
89
 
66
90
  const scenario = testCaseAttempt.pickle.name;
67
- const testId = testCaseAttempt.pickle.id;
91
+ // this may broke something (it is supposed to work, but I am sure it did not)
92
+ // const testId = testCaseAttempt.pickle.id;
93
+ const testId = getTestId(testCaseAttempt.pickle);
68
94
 
69
95
  let exampleString = '';
70
- if (example) exampleString = ` ${example.join(' | ')}`
96
+ if (example) exampleString = ` ${example.join(' | ')}`;
71
97
  let cliMessage = `${chalk.bold(scenario)}${exampleString}: ${chalk[color].bold(status.toUpperCase())} `;
72
98
 
73
99
  if (message) cliMessage += chalk.gray(message.split('\n')[0]);
@@ -79,15 +105,21 @@ class CucumberReporter extends Formatter {
79
105
 
80
106
  const time = Object.values(testCaseAttempt.stepResults)
81
107
  .map(t => t.duration)
82
- .reduce((sum, duration) => sum + (duration.seconds * 1000) + (duration.nanos / 1000000), 0)
108
+ .reduce((sum, duration) => sum + duration.seconds * 1000 + duration.nanos / 1000000, 0);
83
109
 
84
110
  if (!this.client) return;
85
111
 
112
+ const logs = logger.getLogs(testId);
113
+
86
114
  this.client.addTestRun(status, {
87
115
  // error: testCaseAttempt.worstTestStepResult.message,
88
116
  message,
89
- steps: getSteps(testCaseAttempt).map(s => s.toString()).join('\n').trim(),
90
- example: { ...example},
117
+ steps: getSteps(testCaseAttempt)
118
+ .map(s => s.toString())
119
+ .join('\n')
120
+ .trim(),
121
+ example: { ...example },
122
+ stack: logs,
91
123
  title: scenario,
92
124
  test_id: testId,
93
125
  time,
@@ -99,21 +131,20 @@ class CucumberReporter extends Formatter {
99
131
  console.log(chalk.bold('\nSUMMARY:\n\n'));
100
132
 
101
133
  this.failures.forEach((tc, i) => {
102
- let message = ` ${i+1}) ${tc.pickle.name}\n`;
134
+ let message = ` ${i + 1}) ${tc.pickle.name}\n`;
103
135
 
104
136
  const steps = getSteps(tc);
105
137
 
106
138
  steps.forEach(s => {
107
- message += ` ${s.toString()}\n`
108
- })
139
+ message += ` ${s.toString()}\n`;
140
+ });
109
141
 
110
142
  console.log(message);
111
143
  if (tc?.worstTestStepResult?.message) {
112
144
  console.log(chalk.red(tc?.worstTestStepResult?.message));
113
145
  }
114
146
  console.log();
115
-
116
- })
147
+ });
117
148
  }
118
149
 
119
150
  const { testRunFinished } = envelope;
@@ -125,46 +156,48 @@ class CucumberReporter extends Formatter {
125
156
 
126
157
  if (!this.client) return;
127
158
 
128
- this.client.updateRunStatus(testRunFinished.success ? STATUS.PASSED : STATUS.FAILED)
159
+ this.client.updateRunStatus(testRunFinished.success ? STATUS.PASSED : STATUS.FAILED);
129
160
  }
130
161
  }
131
162
 
132
163
  function getSteps(tc) {
133
164
  const stepIds = Object.keys(tc.stepResults);
134
- const pickleSteps = getPickleStepMap(tc.pickle)
135
- return stepIds.map(stepId => {
136
- const ts = tc.testCase.testSteps.find(t => t.id === stepId);
137
- if (!ts) return;
138
- if (!ts.pickleStepId) return;
139
- const result = tc.stepResults[stepId];
140
- const pickleStep = pickleSteps[ts.pickleStepId];
141
- const sourceStepId = pickleStep.astNodeIds[0];
142
- const step = {
143
- text: pickleStep.text,
144
- duration: result.duration,
145
- status: result.status,
146
- }
147
- const color = getStatusColor(result.status);
148
- if (sourceStepId && getGherkinStepMap(tc.gherkinDocument)[sourceStepId]) {
149
- step.keyword = getGherkinStepMap(tc.gherkinDocument)[sourceStepId].keyword;
150
- }
151
- step.toString = function toString() {
152
- const duration = step.duration.seconds * 1000 + (step.duration.nanos / 1000000)
153
- const durationString = ` ${ chalk.gray(`(${Number(duration).toFixed(2)}ms)`)}`;
154
- const stepString = `${chalk.bold(this.keyword)}${this.text}`.trim();
155
- if (color === 'red') return chalk.red(stepString) + durationString;
156
- if (color === 'yellow') return chalk.yellow(stepString) + durationString;
157
- return stepString + durationString;
158
- }
159
- return step;
160
- }).filter(s => !!s)
165
+ const pickleSteps = getPickleStepMap(tc.pickle);
166
+ return stepIds
167
+ .map(stepId => {
168
+ const ts = tc.testCase.testSteps.find(t => t.id === stepId);
169
+ if (!ts) return;
170
+ if (!ts.pickleStepId) return;
171
+ const result = tc.stepResults[stepId];
172
+ const pickleStep = pickleSteps[ts.pickleStepId];
173
+ const sourceStepId = pickleStep.astNodeIds[0];
174
+ const step = {
175
+ text: pickleStep.text,
176
+ duration: result.duration,
177
+ status: result.status,
178
+ };
179
+ const color = getStatusColor(result.status);
180
+ if (sourceStepId && getGherkinStepMap(tc.gherkinDocument)[sourceStepId]) {
181
+ step.keyword = getGherkinStepMap(tc.gherkinDocument)[sourceStepId].keyword;
182
+ }
183
+ step.toString = function toString() {
184
+ const duration = step.duration.seconds * 1000 + step.duration.nanos / 1000000;
185
+ const durationString = ` ${chalk.gray(`(${Number(duration).toFixed(2)}ms)`)}`;
186
+ const stepString = `${chalk.bold(this.keyword)}${this.text}`.trim();
187
+ if (color === 'red') return chalk.red(stepString) + durationString;
188
+ if (color === 'yellow') return chalk.yellow(stepString) + durationString;
189
+ return stepString + durationString;
190
+ };
191
+ return step;
192
+ })
193
+ .filter(s => !!s);
161
194
  }
162
195
 
163
196
  function getStatusColor(status) {
164
197
  if (status === 'UNDEFINED') return 'yellow';
165
198
  if (status === 'SKIPPED') return 'yellow';
166
199
  if (status === 'FAILED') return 'red';
167
- return 'green'
200
+ return 'green';
168
201
  }
169
202
 
170
203
  function getExample(testCaseAttempt) {
@@ -173,11 +206,14 @@ function getExample(testCaseAttempt) {
173
206
  if (!nodesMap[exampleNodeId]) return;
174
207
  const featureDoc = fs.readFileSync(testCaseAttempt.gherkinDocument.uri).toString();
175
208
  const { line } = nodesMap[exampleNodeId];
176
- const example = featureDoc.split('\n')[line-1];
209
+ const example = featureDoc.split('\n')[line - 1];
177
210
  if (example) {
178
- return example.trim().split('|').filter(r => !!r).map(r => r.trim());
179
- };
180
-
211
+ return example
212
+ .trim()
213
+ .split('|')
214
+ .filter(r => !!r)
215
+ .map(r => r.trim());
216
+ }
181
217
  }
182
218
 
183
219
  module.exports = CucumberReporter;
@@ -1,8 +1,8 @@
1
1
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies, import/no-unresolved
2
2
  const { Formatter } = require('cucumber');
3
3
  const chalk = require('chalk');
4
- const { parseTest } = require('../../util');
5
- const { STATUS } = require('../../constants');
4
+ const { parseTest, fileSystem } = require('../../utils/utils');
5
+ const { STATUS, TESTOMAT_TMP_STORAGE } = require('../../constants');
6
6
  const TestomatClient = require('../../client');
7
7
 
8
8
  const createTestomatFormatter = apiKey => {
@@ -96,9 +96,23 @@ const createTestomatFormatter = apiKey => {
96
96
  this.status = STATUS.PASSED.toString();
97
97
 
98
98
  options.eventBroadcaster.on('gherkin-document', addDocument);
99
- options.eventBroadcaster.on('test-run-started', () => this?.client?.createRun());
99
+ options.eventBroadcaster.on('test-run-started', () => {
100
+ fileSystem.clearDir(TESTOMAT_TMP_STORAGE.mainDir);
101
+ this?.client?.createRun();
102
+ });
100
103
  options.eventBroadcaster.on('test-case-finished', this.onTestCaseFinished.bind(this));
104
+ options.eventBroadcaster.on('test-case-started', this.onTestCaseStarted.bind(this));
101
105
  options.eventBroadcaster.on('test-run-finished', () => this?.client?.updateRunStatus(this.status));
106
+
107
+ global.testomatioRunningEnvironment = 'cucumber:legacy';
108
+ }
109
+
110
+ onTestCaseStarted(event) {
111
+ const scenario = getScenario(event.sourceLocation);
112
+ const testId = getTestId(scenario);
113
+
114
+ if (!global.testomatioDataStore) global.testomatioDataStore = {};
115
+ global.testomatioDataStore.currentlyRunningTestId = testId;
102
116
  }
103
117
 
104
118
  onTestCaseFinished(event) {
@@ -111,15 +125,15 @@ const createTestomatFormatter = apiKey => {
111
125
 
112
126
  if (!scenario.name) return;
113
127
 
114
- let message = '';
115
- let cliMessage = `- ${scenario.name}: ${chalk.bold(status.toUpperCase())}`;
128
+ const message = '';
129
+ const cliMessage = `- ${scenario.name}: ${chalk.bold(status.toUpperCase())}`;
116
130
 
117
- if (event.result.status === 'undefined') {
118
- cliMessage += chalk.yellow(
119
- ' (undefined steps. Run Cucumber without this formatter and implement missing steps)',
120
- );
121
- message = 'Undefined steps. Implement missing steps and rerun this scenario';
122
- }
131
+ // if (event.result.status === 'undefined') {
132
+ // cliMessage += chalk.yellow(
133
+ // ' (undefined steps. Run Cucumber without this formatter and implement missing steps)',
134
+ // );
135
+ // message = 'Undefined steps. Implement missing steps and rerun this scenario';
136
+ // }
123
137
  console.log(cliMessage);
124
138
  if (status !== STATUS.PASSED && status !== STATUS.SKIPPED) {
125
139
  this.status = STATUS.FAILED;
@@ -1,5 +1,5 @@
1
1
  const { STATUS } = require('../../constants');
2
- const { parseTest, parseSuite } = require('../../util');
2
+ const { parseTest, parseSuite } = require('../../utils/utils');
3
3
  const TestomatClient = require('../../client');
4
4
 
5
5
  const testomatioReporter = on => {
@@ -1,5 +1,5 @@
1
1
  const TestomatClient = require('../client');
2
- const { parseTest, ansiRegExp } = require('../util');
2
+ const { parseTest, ansiRegExp } = require('../utils/utils');
3
3
  const { STATUS } = require('../constants');
4
4
 
5
5
  class JasmineReporter {
@@ -1,6 +1,6 @@
1
1
  const TestomatClient = require('../client');
2
2
  const { STATUS, TESTOMAT_TMP_STORAGE } = require('../constants');
3
- const { parseTest, ansiRegExp, fileSystem } = require('../util');
3
+ const { parseTest, ansiRegExp, fileSystem } = require('../utils/utils');
4
4
 
5
5
  class JestReporter {
6
6
  constructor(globalConfig, options) {
@@ -12,8 +12,14 @@ class JestReporter {
12
12
  }
13
13
 
14
14
  static getIdOfCurrentlyRunningTest() {
15
- // @ts-expect-error "expect" could only be defined inside Jest environement (forbidden to import it outside)
16
- return parseTest(expect?.getState()?.currentTestName) || null; // eslint-disable-line
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
+ }
17
23
  }
18
24
 
19
25
  onRunStart() {
@@ -36,12 +42,21 @@ class JestReporter {
36
42
  steps = failureMessages[0];
37
43
  }
38
44
  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
+ }
52
+
39
53
  const deducedStatus = status === 'pending' ? 'skipped' : status;
40
54
  // In jest if test is not matched with test name pattern it is considered as skipped.
41
55
  // So adding a check if it is skipped for real or because of test pattern
42
56
  if (!this._globalConfig.testNamePattern || deducedStatus !== 'skipped') {
43
57
  this.client.addTestRun(deducedStatus, {
44
58
  test_id: testId,
59
+ suite_title,
45
60
  error,
46
61
  steps,
47
62
  title,