@testomatio/reporter 0.6.9 → 0.7.0-beta

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 (61) hide show
  1. package/Changelog.md +9 -0
  2. package/README.md +16 -7
  3. package/lib/adapter/codecept.js +1 -1
  4. package/lib/adapter/cucumber/current.js +185 -0
  5. package/lib/adapter/cucumber/legacy.js +136 -0
  6. package/lib/adapter/cucumber.js +15 -135
  7. package/lib/adapter/cypress-plugin/index.js +4 -1
  8. package/lib/adapter/mocha.js +1 -0
  9. package/lib/adapter/webdriver.js +1 -0
  10. package/lib/fileUploader.js +2 -1
  11. package/lib/junit-adapter/csharp.js +18 -0
  12. package/lib/xmlReader.js +71 -3
  13. package/package.json +12 -9
  14. package/testcafe/package-lock.json +863 -0
  15. package/testcafe/package.json +1 -1
  16. package/.eslintrc.js +0 -35
  17. package/.github/workflows/node.js.yml +0 -30
  18. package/.prettierrc.js +0 -12
  19. package/example/codecept/codecept.conf.js +0 -29
  20. package/example/codecept/index_test.js +0 -10
  21. package/example/codecept/jsconfig.json +0 -5
  22. package/example/codecept/sample_test.js +0 -6
  23. package/example/codecept/steps.d.ts +0 -16
  24. package/example/codecept/steps_file.js +0 -10
  25. package/example/core/index.js +0 -15
  26. package/example/jest/index.test.js +0 -9
  27. package/example/jest/jest.config.js +0 -188
  28. package/example/jest/package.json +0 -13
  29. package/example/jest/sample.test.js +0 -13
  30. package/example/jest/yarn.lock +0 -8
  31. package/example/mocha/test/index.test.js +0 -13
  32. package/tests/adapter/config/index.js +0 -10
  33. package/tests/adapter/examples/codecept/codecept.conf.js +0 -33
  34. package/tests/adapter/examples/codecept/index_test.js +0 -11
  35. package/tests/adapter/examples/codecept/jsconfig.json +0 -5
  36. package/tests/adapter/examples/codecept/output/Test_for_suite_2_@Tc2171bd2.failed.png +0 -0
  37. package/tests/adapter/examples/codecept/output/Test_issue_for_suite_1_@Tca70c8c4.failed.png +0 -0
  38. package/tests/adapter/examples/codecept/sample_test.js +0 -7
  39. package/tests/adapter/examples/codecept/steps_file.js +0 -10
  40. package/tests/adapter/examples/jasmine/index.test.js +0 -11
  41. package/tests/adapter/examples/jasmine/passReporterOpts.sh +0 -8
  42. package/tests/adapter/examples/jest/index.test.js +0 -11
  43. package/tests/adapter/examples/jest/jest.config.js +0 -4
  44. package/tests/adapter/examples/mocha/index.test.js +0 -13
  45. package/tests/adapter/examples/mocha/mocha.config.js +0 -4
  46. package/tests/adapter/index.test.js +0 -136
  47. package/tests/adapter/utils/index.js +0 -40
  48. package/tests/data/artifacts/failed_test.png +0 -0
  49. package/tests/data/artifacts/screenshot1.png +0 -0
  50. package/tests/data/cli/RunCest.php +0 -1024
  51. package/tests/data/cli/SnapshotCest.php +0 -97
  52. package/tests/data/codecept.xml +0 -150
  53. package/tests/data/codecept2.xml +0 -25
  54. package/tests/data/java.xml +0 -25
  55. package/tests/data/junit1.xml +0 -70
  56. package/tests/data/minitest.xml +0 -25
  57. package/tests/data/phpunit.xml +0 -65
  58. package/tests/data/pytest.xml +0 -13
  59. package/tests/data/src/services/search_service_test.rb +0 -146
  60. package/tests/util_test.js +0 -51
  61. package/tests/xmlReader_test.js +0 -232
package/Changelog.md CHANGED
@@ -1,3 +1,12 @@
1
+ # 0.7.0
2
+
3
+ * Support for `@cucumber/cucumber` (>= 7.0) added
4
+ * Initial support for C# and NUnit
5
+
6
+ # 0.6.10
7
+
8
+ * Fixed uploading multilpe artifacts in Playwright
9
+
1
10
  # 0.6.9
2
11
 
3
12
  * Fixed pending tests reports for Cypress
package/README.md CHANGED
@@ -224,6 +224,7 @@ Tested Frameworks:
224
224
  * Python (Pytest)
225
225
  * Minitest (Ruby)
226
226
  * PHPUnit (PHP)
227
+ * NUnit (C#)
227
228
 
228
229
 
229
230
  To import JUnit reports into Testomat.io **NodeJS >=14 is required**.
@@ -231,14 +232,9 @@ To import JUnit reports into Testomat.io **NodeJS >=14 is required**.
231
232
  Package `@testomatio/reporter` should be installed:
232
233
 
233
234
  ```
234
- npm i @testomatio/reporter@latest
235
+ npm i @testomatio/reporter@latest --save-dev
235
236
  ```
236
237
 
237
- For local development it is recommended to install @testomatio/reporter globally:
238
-
239
- ```
240
- npm i -g @testomatio/reporter@latest
241
- ```
242
238
 
243
239
  Run your test framework and generate a JUnit report.
244
240
 
@@ -249,7 +245,12 @@ TESTOMATIO={API_KEY} npx report-xml "{pattern}" --lang={lang}
249
245
  ```
250
246
 
251
247
  * `pattern` - is a glob pattern to match all XML files from report. For instance, `"test/report/**.xml"` or just `report.xml`
252
- * `--lang` option can be specified to identify source code of the project. Example: `--lang=Ruby` or `--lang=Java` or `--lang=Python`.
248
+ * `--lang` option can be specified to identify source code of the project. Example: `--lang=Ruby` or `--lang=Java` or `--lang=Python`. Possible values:
249
+ * `c#`
250
+ * `java`
251
+ * `ruby`
252
+ * `python`
253
+ * `php`
253
254
  * `--java-tests` option is avaiable for Java projects, and can be set if path to tests is different then `src/test/java`. When this option is enable, `lang` option is automatically set to `java`
254
255
  * `--env-file <envfile>` option to load environment variables from .env file. Inside env file TESTOMATIO credentials like `TESTOMATIO` api key or [S3 config](#attaching-test-artifacts) can be stored.
255
256
 
@@ -288,6 +289,14 @@ TESTOMATIO={API_KEY} npx report-xml "target/surefire-reports/*.xml" --java-tests
288
289
 
289
290
  > You can specify `--java-test` option to set a path to tests if they are located in path other than `src/test/java`
290
291
 
292
+ #### Example: NUnit
293
+
294
+ Generate NUnit XML report and run the following code:
295
+
296
+ ```
297
+ TESTOMATIO={API_KEY} npx report-xml "report.xml" --lang="c#"
298
+ ```
299
+
291
300
  #### Example: Ruby on Rails with Minitest
292
301
 
293
302
  ```ruby
@@ -1,5 +1,5 @@
1
1
  if (!global.codeceptjs) {
2
- // eslint-disable-next-line global-require
2
+ // eslint-disable-next-line global-require, import/no-extraneous-dependencies
3
3
  global.codeceptjs = require('codeceptjs');
4
4
  }
5
5
 
@@ -0,0 +1,185 @@
1
+ // eslint-disable-next-line global-require, import/no-extraneous-dependencies
2
+ const { Formatter, formatterHelpers } = require("@cucumber/cucumber");
3
+ const chalk = require('chalk');
4
+ const fs = require('fs');
5
+ const { TestomatClient, TRConstants } = require('../../reporter');
6
+
7
+ const { GherkinDocumentParser, PickleParser } = formatterHelpers
8
+ const {
9
+ getGherkinScenarioLocationMap,
10
+ getGherkinStepMap,
11
+ } = GherkinDocumentParser
12
+ const { getPickleStepMap } = PickleParser
13
+
14
+ class CucumberReporter extends Formatter {
15
+ constructor(options) {
16
+ super(options);
17
+ options.eventBroadcaster.on('envelope', this.parseEnvelope.bind(this))
18
+ this.failures = [];
19
+ this.cases = [];
20
+
21
+ const apiKey = process.env.TESTOMATIO;
22
+ if (!apiKey || apiKey === '') {
23
+ console.log(chalk.red('TESTOMATIO key is empty, ignoring reports'));
24
+ return;
25
+ }
26
+
27
+ this.client = new TestomatClient({ apiKey });
28
+ this.status = TRConstants.PASSED;
29
+
30
+ }
31
+
32
+ parseEnvelope(envelope) {
33
+ if (envelope.testCaseStarted && this.client) this.client.createRun()
34
+ if (envelope.testCaseFinished) this.onTestCaseFinished(envelope.testCaseFinished);
35
+ if (envelope.testRunFinished) this.onTestRunFinished(envelope);
36
+ }
37
+
38
+ onTestCaseFinished(testCaseFinished) {
39
+ const testCaseAttempt = this.eventDataCollector.getTestCaseAttempt(testCaseFinished.testCaseStartedId);
40
+
41
+ let example;
42
+ let status = TRConstants.PASSED;
43
+ let color = 'green';
44
+ let message;
45
+
46
+ this.cases.push(testCaseAttempt);
47
+
48
+ if (testCaseAttempt.worstTestStepResult) {
49
+ if (testCaseAttempt.worstTestStepResult.status === 'SKIPPED') {
50
+ status = TRConstants.SKIPPED;
51
+ }
52
+ if (testCaseAttempt.worstTestStepResult.status === 'UNDEFINED') {
53
+ status = TRConstants.SKIPPED;
54
+ message = 'Undefined steps. Implement missing steps and rerun this scenario';
55
+ }
56
+ if (testCaseAttempt.worstTestStepResult.status === 'FAILED') {
57
+ message = testCaseAttempt?.worstTestStepResult?.message;
58
+ status = TRConstants.FAILED;
59
+ }
60
+ color = getStatusColor(testCaseAttempt.worstTestStepResult.status);
61
+ if (status !== TRConstants.PASSED) this.failures.push(testCaseAttempt);
62
+ }
63
+
64
+ if (testCaseAttempt.pickle.astNodeIds.length > 1) {
65
+ example = getExample(testCaseAttempt);
66
+ testCaseAttempt.example = example;
67
+ }
68
+
69
+ const scenario = testCaseAttempt.pickle.name;
70
+ const testId = testCaseAttempt.pickle.id;
71
+
72
+ let exampleString = '';
73
+ if (example) exampleString = ` ${example.join(' | ')}`
74
+ let cliMessage = `${chalk.bold(scenario)}${exampleString}: ${chalk[color].bold(status.toUpperCase())} `;
75
+
76
+ if (message) cliMessage += chalk.gray(message.split('\n')[0]);
77
+ console.log(cliMessage);
78
+
79
+ if (status !== TRConstants.PASSED && status !== TRConstants.SKIPPED) {
80
+ this.status = TRConstants.FAILED;
81
+ }
82
+
83
+ const time = Object.values(testCaseAttempt.stepResults)
84
+ .map(t => t.duration)
85
+ .reduce((sum, duration) => sum + (duration.seconds * 1000) + (duration.nanos / 1000000), 0)
86
+
87
+ if (!this.client) return;
88
+
89
+ this.client.addTestRun(testId, status, {
90
+ // error: testCaseAttempt.worstTestStepResult.message,
91
+ message,
92
+ steps: getSteps(testCaseAttempt).map(s => s.toString()).join('\n').trim(),
93
+ example: { ...example},
94
+ title: scenario,
95
+ time,
96
+ });
97
+ }
98
+
99
+ onTestRunFinished(envelope) {
100
+ if (this.failures.length > 0) {
101
+ console.log(chalk.bold('\nSUMMARY:\n\n'));
102
+
103
+ this.failures.forEach((tc, i) => {
104
+ let message = ` ${i+1}) ${tc.pickle.name}\n`;
105
+
106
+ const steps = getSteps(tc);
107
+
108
+ steps.forEach(s => {
109
+ message += ` ${s.toString()}\n`
110
+ })
111
+
112
+ console.log(message);
113
+ if (tc?.worstTestStepResult?.message) {
114
+ console.log(chalk.red(tc?.worstTestStepResult?.message));
115
+ }
116
+ console.log();
117
+
118
+ })
119
+ }
120
+
121
+ const { testRunFinished } = envelope;
122
+
123
+ const bgColor = testRunFinished.success ? 'bgGreen' : 'bgRed';
124
+ const prefixSummary = `${chalk.bold(testRunFinished.success ? ' SUCCESS ' : ' FALIURE ')}`;
125
+ console.log();
126
+ console.log(chalk[bgColor](` ${prefixSummary} | Total Scenarios: ${chalk.bold(this.cases.length)} `));
127
+
128
+ if (!this.client) return;
129
+
130
+ this.client.updateRunStatus(testRunFinished.success ? TRConstants.PASSED : TRConstants.FAILED)
131
+ }
132
+ };
133
+
134
+ function getSteps(tc) {
135
+ const stepIds = Object.keys(tc.stepResults);
136
+ const pickleSteps = getPickleStepMap(tc.pickle)
137
+ return stepIds.map(stepId => {
138
+ const ts = tc.testCase.testSteps.find(t => t.id === stepId);
139
+ if (!ts) return;
140
+ if (!ts.pickleStepId) return;
141
+ const result = tc.stepResults[stepId];
142
+ const pickleStep = pickleSteps[ts.pickleStepId];
143
+ const sourceStepId = pickleStep.astNodeIds[0];
144
+ const step = {
145
+ text: pickleStep.text,
146
+ duration: result.duration,
147
+ status: result.status,
148
+ }
149
+ const color = getStatusColor(result.status);
150
+ if (sourceStepId && getGherkinStepMap(tc.gherkinDocument)[sourceStepId]) {
151
+ step.keyword = getGherkinStepMap(tc.gherkinDocument)[sourceStepId].keyword;
152
+ }
153
+ step.toString = function toString() {
154
+ const duration = step.duration.seconds * 1000 + (step.duration.nanos / 1000000)
155
+ const durationString = ` ${ chalk.gray(`(${Number(duration).toFixed(2)}ms)`)}`;
156
+ const stepString = `${chalk.bold(this.keyword)}${this.text}`.trim();
157
+ if (color === 'red') return chalk.red(stepString) + durationString;
158
+ if (color === 'yellow') return chalk.yellow(stepString) + durationString;
159
+ return stepString + durationString;
160
+ }
161
+ return step;
162
+ }).filter(s => !!s)
163
+ }
164
+
165
+ function getStatusColor(status) {
166
+ if (status === 'UNDEFINED') return 'yellow';
167
+ if (status === 'SKIPPED') return 'yellow';
168
+ if (status === 'FAILED') return 'red';
169
+ return 'green'
170
+ }
171
+
172
+ function getExample(testCaseAttempt) {
173
+ const nodesMap = getGherkinScenarioLocationMap(testCaseAttempt.gherkinDocument);
174
+ const exampleNodeId = testCaseAttempt.pickle.astNodeIds[1];
175
+ if (!nodesMap[exampleNodeId]) return;
176
+ const featureDoc = fs.readFileSync(testCaseAttempt.gherkinDocument.uri).toString();
177
+ const { line } = nodesMap[exampleNodeId];
178
+ const example = featureDoc.split('\n')[line-1];
179
+ if (example) {
180
+ return example.trim().split('|').filter(r => !!r).map(r => r.trim());
181
+ };
182
+
183
+ }
184
+
185
+ module.exports = CucumberReporter;
@@ -0,0 +1,136 @@
1
+ // eslint-disable-next-line import/no-unresolved
2
+ const { Formatter } = require('cucumber');
3
+ const chalk = require('chalk');
4
+ const { TestomatClient, TRConstants } = require('../../reporter');
5
+ const { parseTest } = require('../../util');
6
+
7
+ const createTestomatFormatter = apiKey => {
8
+ if (!apiKey || apiKey === '') {
9
+ console.log(chalk.red('TESTOMATIO key is empty, ignoring reports'));
10
+ }
11
+
12
+ const documents = {};
13
+ const dataTableMap = {};
14
+
15
+ const addDocument = gherkinDocument => {
16
+ documents[gherkinDocument.uri] = gherkinDocument.document;
17
+ };
18
+
19
+ const getTitle = scenario => {
20
+ let { name } = scenario;
21
+ if (scenario.tags.length) {
22
+ let tags = '';
23
+ for (const tag of scenario.tags) {
24
+ tags = `${tags} ${tag.name}`;
25
+ }
26
+ name = `${name}${tags}`;
27
+ }
28
+ return name;
29
+ };
30
+
31
+ const getFeature = uri => documents[uri].feature;
32
+
33
+ const getScenario = location => {
34
+ const { children } = getFeature(location.uri);
35
+ for (const scenario of children) {
36
+ if (scenario.type === 'Scenario' && scenario.location.line === location.line) {
37
+ return scenario;
38
+ }
39
+ if (scenario.type === 'ScenarioOutline') {
40
+ for (const example of scenario.examples) {
41
+ for (const tableBody of example.tableBody) {
42
+ if (tableBody.location.line === location.line) {
43
+ return scenario;
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+
50
+ return null;
51
+ };
52
+
53
+ const loadDataTable = (scenario, uri) => {
54
+ if (scenario.type === 'ScenarioOutline') {
55
+ for (const example of scenario.examples) {
56
+ for (const tableBody of example.tableBody) {
57
+ const dataMap = example.tableHeader.cells.reduce((acc, cell, index) => {
58
+ acc[cell.value] = tableBody.cells[index].value;
59
+ return acc;
60
+ }, {});
61
+
62
+ dataTableMap[`${uri}:${tableBody.location.line}`] = JSON.stringify(dataMap);
63
+ }
64
+ }
65
+ }
66
+ };
67
+
68
+ const getDataTableMap = (scenario, sourceLocation) => {
69
+ const key = `${sourceLocation.uri}:${sourceLocation.line}`;
70
+ if (!dataTableMap[key]) {
71
+ loadDataTable(scenario, sourceLocation.uri);
72
+ }
73
+
74
+ return dataTableMap[key] || '';
75
+ };
76
+
77
+ const getTestId = scenario => {
78
+ if (scenario) {
79
+ for (const tag of scenario.tags) {
80
+ const testId = parseTest(tag.name);
81
+ if (testId) return testId;
82
+ }
83
+ }
84
+
85
+ return null;
86
+ };
87
+
88
+ return class TestomatFormatter extends Formatter {
89
+ constructor(options) {
90
+ super(options);
91
+
92
+ if (!apiKey) return;
93
+
94
+ this.client = new TestomatClient({ apiKey });
95
+ this.status = TRConstants.PASSED;
96
+
97
+ options.eventBroadcaster.on('gherkin-document', addDocument);
98
+ options.eventBroadcaster.on('test-run-started', () => this.client.createRun());
99
+ options.eventBroadcaster.on('test-case-finished', this.onTestCaseFinished.bind(this));
100
+ options.eventBroadcaster.on('test-run-finished', () => this.client.updateRunStatus(this.status));
101
+ }
102
+
103
+ onTestCaseFinished(event) {
104
+ const scenario = getScenario(event.sourceLocation);
105
+ const testId = getTestId(scenario);
106
+ const status = event.result.status === 'undefined' ? TRConstants.SKIPPED : event.result.status;
107
+
108
+ let example = getDataTableMap(scenario, event.sourceLocation);
109
+ if (example) example = JSON.parse(example);
110
+
111
+ if (!scenario.name) return;
112
+
113
+ let message = '';
114
+ let cliMessage = `- ${scenario.name}: ${chalk.bold(status.toUpperCase())}`;
115
+
116
+ if (event.result.status === 'undefined') {
117
+ cliMessage += chalk.yellow(
118
+ ' (undefined steps. Run Cucumber without this formatter and implement missing steps)',
119
+ );
120
+ message = 'Undefined steps. Implement missing steps and rerun this scenario';
121
+ }
122
+ console.log(cliMessage);
123
+ if (status !== TRConstants.PASSED && status !== TRConstants.SKIPPED) {
124
+ this.status = TRConstants.FAILED;
125
+ }
126
+ this.client.addTestRun(testId, status, {
127
+ error: event.result.exception,
128
+ message,
129
+ example,
130
+ title: getTitle(scenario),
131
+ });
132
+ }
133
+ };
134
+ };
135
+
136
+ module.exports = createTestomatFormatter(process.env.TESTOMATIO);
@@ -1,136 +1,16 @@
1
- // eslint-disable-next-line import/no-unresolved
2
- const { Formatter } = require('cucumber');
3
- const chalk = require('chalk');
4
- const { TestomatClient, TRConstants } = require('../reporter');
5
- const { parseTest } = require('../util');
6
-
7
- const createTestomatFormatter = apiKey => {
8
- if (!apiKey || apiKey === '') {
9
- console.log(chalk.red('TESTOMATIO key is empty, ignoring reports'));
1
+ try {
2
+ // eslint-disable-next-line import/no-unresolved
3
+ require.resolve("@cucumber/cucumber");
4
+ // eslint-disable-next-line global-require, import/no-extraneous-dependencies
5
+ module.exports = require('./cucumber/current');
6
+ } catch (_e) {
7
+ try {
8
+ // eslint-disable-next-line global-require, import/no-extraneous-dependencies
9
+ require.resolve('cucumber');
10
+ // eslint-disable-next-line global-require, import/no-extraneous-dependencies
11
+ module.exports = require('./cucumber/legacy');
12
+ } catch (_err) {
13
+ console.error('Cucumber packages: "@cucumber/cucumber" or "cucumber" were not detected. Report won\'t be sent');
14
+ module.exports = {}
10
15
  }
11
-
12
- const documents = {};
13
- const dataTableMap = {};
14
-
15
- const addDocument = gherkinDocument => {
16
- documents[gherkinDocument.uri] = gherkinDocument.document;
17
- };
18
-
19
- const getTitle = scenario => {
20
- let { name } = scenario;
21
- if (scenario.tags.length) {
22
- let tags = '';
23
- for (const tag of scenario.tags) {
24
- tags = `${tags} ${tag.name}`;
25
- }
26
- name = `${name}${tags}`;
27
- }
28
- return name;
29
- };
30
-
31
- const getFeature = uri => documents[uri].feature;
32
-
33
- const getScenario = location => {
34
- const { children } = getFeature(location.uri);
35
- for (const scenario of children) {
36
- if (scenario.type === 'Scenario' && scenario.location.line === location.line) {
37
- return scenario;
38
- }
39
- if (scenario.type === 'ScenarioOutline') {
40
- for (const example of scenario.examples) {
41
- for (const tableBody of example.tableBody) {
42
- if (tableBody.location.line === location.line) {
43
- return scenario;
44
- }
45
- }
46
- }
47
- }
48
- }
49
-
50
- return null;
51
- };
52
-
53
- const loadDataTable = (scenario, uri) => {
54
- if (scenario.type === 'ScenarioOutline') {
55
- for (const example of scenario.examples) {
56
- for (const tableBody of example.tableBody) {
57
- const dataMap = example.tableHeader.cells.reduce((acc, cell, index) => {
58
- acc[cell.value] = tableBody.cells[index].value;
59
- return acc;
60
- }, {});
61
-
62
- dataTableMap[`${uri}:${tableBody.location.line}`] = JSON.stringify(dataMap);
63
- }
64
- }
65
- }
66
- };
67
-
68
- const getDataTableMap = (scenario, sourceLocation) => {
69
- const key = `${sourceLocation.uri}:${sourceLocation.line}`;
70
- if (!dataTableMap[key]) {
71
- loadDataTable(scenario, sourceLocation.uri);
72
- }
73
-
74
- return dataTableMap[key] || '';
75
- };
76
-
77
- const getTestId = scenario => {
78
- if (scenario) {
79
- for (const tag of scenario.tags) {
80
- const testId = parseTest(tag.name);
81
- if (testId) return testId;
82
- }
83
- }
84
-
85
- return null;
86
- };
87
-
88
- return class TestomatFormatter extends Formatter {
89
- constructor(options) {
90
- super(options);
91
-
92
- if (!apiKey) return;
93
-
94
- this.client = new TestomatClient({ apiKey });
95
- this.status = TRConstants.PASSED;
96
-
97
- options.eventBroadcaster.on('gherkin-document', addDocument);
98
- options.eventBroadcaster.on('test-run-started', () => this.client.createRun());
99
- options.eventBroadcaster.on('test-case-finished', this.onTestCaseFinished.bind(this));
100
- options.eventBroadcaster.on('test-run-finished', () => this.client.updateRunStatus(this.status));
101
- }
102
-
103
- onTestCaseFinished(event) {
104
- const scenario = getScenario(event.sourceLocation);
105
- const testId = getTestId(scenario);
106
- const status = event.result.status === 'undefined' ? TRConstants.SKIPPED : event.result.status;
107
-
108
- let example = getDataTableMap(scenario, event.sourceLocation);
109
- if (example) example = JSON.parse(example);
110
-
111
- if (!scenario.name) return;
112
-
113
- let message = '';
114
- let cliMessage = `- ${scenario.name}: ${chalk.bold(status.toUpperCase())}`;
115
-
116
- if (event.result.status === 'undefined') {
117
- cliMessage += chalk.yellow(
118
- ' (undefined steps. Run Cucumber without this formatter and implement missing steps)',
119
- );
120
- message = 'Undefined steps. Implement missing steps and rerun this scenario';
121
- }
122
- console.log(cliMessage);
123
- if (status !== TRConstants.PASSED && status !== TRConstants.SKIPPED) {
124
- this.status = TRConstants.FAILED;
125
- }
126
- this.client.addTestRun(testId, status, {
127
- error: event.result.exception,
128
- message,
129
- example,
130
- title: getTitle(scenario),
131
- });
132
- }
133
- };
134
- };
135
-
136
- module.exports = createTestomatFormatter(process.env.TESTOMATIO);
16
+ }
@@ -55,11 +55,14 @@ const testomatioReporter = on => {
55
55
 
56
56
  const files = [...videos, ...screenshots];
57
57
 
58
+ let state;
58
59
  switch (test.state) {
59
60
  case 'passed': state = TRConstants.PASSED; break;
60
61
  case 'failed': state = TRConstants.FAILED; break;
61
62
  case 'skipped':
62
- case 'pending': state = TRConstants.SKIPPED;
63
+ case 'pending':
64
+ default:
65
+ state = TRConstants.SKIPPED;
63
66
  }
64
67
 
65
68
  addSpecTestsPromises.push(client.addTestRun(testId, state, {
@@ -1,3 +1,4 @@
1
+ // eslint-disable-next-line global-require, import/no-extraneous-dependencies
1
2
  const Mocha = require('mocha');
2
3
  const TestomatClient = require('../client');
3
4
  const TRConstants = require('../constants');
@@ -1,3 +1,4 @@
1
+ // eslint-disable-next-line global-require, import/no-extraneous-dependencies
1
2
  const WDIOReporter = require('@wdio/reporter').default;
2
3
  const TestomatClient = require('../client');
3
4
  const { parseTest } = require('../util');
@@ -2,6 +2,7 @@ const AWS = require('aws-sdk');
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
4
  const chalk = require('chalk');
5
+ const { randomUUID } = require('crypto');
5
6
  const memoize = require('lodash.memoize');
6
7
  const { APP_PREFIX } = require('./constants');
7
8
 
@@ -55,7 +56,7 @@ const uploadUsingS3 = async (filePath, runId) => {
55
56
  const s3 = new AWS.S3(config);
56
57
  const file = fs.readFileSync(filePath);
57
58
 
58
- Key = `${runId}/${Key || path.basename(filePath)}`;
59
+ Key = `${runId}/${randomUUID()}-${Key || path.basename(filePath)}`;
59
60
  const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
60
61
 
61
62
  try {
@@ -0,0 +1,18 @@
1
+ const Adapter = require('./adapter');
2
+
3
+ class CSharpAdapter extends Adapter {
4
+
5
+ formatTest(t) {
6
+ const title = t.title.replace(/\(.*?\)/, '').trim();
7
+ const example = t.title.match(/\((.*?)\)/);
8
+ if (example) t.example = { ...example[1].split(',')};
9
+ const suite = t.suite_title.split('.')
10
+ t.suite_title = suite.pop();
11
+ t.file = suite.join('/');
12
+ t.title = title.trim();
13
+ return t;
14
+ }
15
+ }
16
+
17
+
18
+ module.exports = CSharpAdapter;