@testomatio/reporter 2.0.1-beta.4 → 2.0.1-beta.5-timestamp

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 (148) hide show
  1. package/lib/adapter/codecept.js +335 -293
  2. package/lib/adapter/cucumber/current.js +203 -195
  3. package/lib/adapter/cucumber/legacy.js +155 -130
  4. package/lib/adapter/cucumber.js +16 -5
  5. package/lib/adapter/cypress-plugin/index.js +105 -91
  6. package/lib/adapter/jasmine.js +53 -54
  7. package/lib/adapter/jest.js +99 -97
  8. package/lib/adapter/mocha.js +141 -112
  9. package/lib/adapter/playwright.js +231 -199
  10. package/lib/adapter/vitest.js +149 -150
  11. package/lib/adapter/webdriver.js +121 -144
  12. package/lib/bin/cli.js +211 -229
  13. package/lib/bin/reportXml.js +52 -51
  14. package/lib/bin/startTest.js +95 -83
  15. package/lib/bin/uploadArtifacts.js +61 -56
  16. package/lib/client.js +465 -424
  17. package/lib/config.js +23 -18
  18. package/lib/constants.js +44 -50
  19. package/lib/data-storage.js +188 -216
  20. package/lib/junit-adapter/adapter.js +20 -17
  21. package/lib/junit-adapter/csharp.js +14 -28
  22. package/lib/junit-adapter/index.js +25 -27
  23. package/lib/junit-adapter/java.js +53 -41
  24. package/lib/junit-adapter/javascript.js +27 -30
  25. package/lib/junit-adapter/python.js +37 -38
  26. package/lib/junit-adapter/ruby.js +8 -11
  27. package/lib/output.js +52 -44
  28. package/lib/pipe/bitbucket.js +230 -223
  29. package/lib/pipe/csv.js +126 -113
  30. package/lib/pipe/debug.js +99 -118
  31. package/lib/pipe/github.js +213 -218
  32. package/lib/pipe/gitlab.js +206 -183
  33. package/lib/pipe/html.js +321 -258
  34. package/lib/pipe/index.js +66 -94
  35. package/lib/pipe/testomatio.js +474 -429
  36. package/lib/reporter-functions.js +26 -28
  37. package/lib/reporter.js +29 -34
  38. package/lib/services/artifacts.js +51 -55
  39. package/lib/services/index.js +12 -14
  40. package/lib/services/key-values.js +53 -56
  41. package/lib/services/logger.js +245 -226
  42. package/lib/template/testomatio.hbs +1366 -1026
  43. package/lib/uploader.js +364 -295
  44. package/lib/utils/pipe_utils.js +85 -89
  45. package/lib/utils/utils.js +307 -398
  46. package/lib/xmlReader.js +532 -525
  47. package/package.json +21 -64
  48. package/lib/adapter/codecept.d.ts +0 -2
  49. package/lib/adapter/cucumber/current.d.ts +0 -14
  50. package/lib/adapter/cucumber/legacy.d.ts +0 -0
  51. package/lib/adapter/cucumber.d.ts +0 -2
  52. package/lib/adapter/cypress-plugin/index.d.ts +0 -2
  53. package/lib/adapter/jasmine.d.ts +0 -11
  54. package/lib/adapter/jest.d.ts +0 -13
  55. package/lib/adapter/mocha.d.ts +0 -2
  56. package/lib/adapter/nightwatch.d.ts +0 -4
  57. package/lib/adapter/nightwatch.js +0 -80
  58. package/lib/adapter/playwright.d.ts +0 -14
  59. package/lib/adapter/vitest.d.ts +0 -35
  60. package/lib/adapter/webdriver.d.ts +0 -24
  61. package/lib/bin/cli.d.ts +0 -2
  62. package/lib/bin/reportXml.d.ts +0 -2
  63. package/lib/bin/startTest.d.ts +0 -2
  64. package/lib/bin/uploadArtifacts.d.ts +0 -2
  65. package/lib/client.d.ts +0 -76
  66. package/lib/config.d.ts +0 -1
  67. package/lib/constants.d.ts +0 -25
  68. package/lib/data-storage.d.ts +0 -34
  69. package/lib/junit-adapter/adapter.d.ts +0 -9
  70. package/lib/junit-adapter/csharp.d.ts +0 -5
  71. package/lib/junit-adapter/index.d.ts +0 -3
  72. package/lib/junit-adapter/java.d.ts +0 -5
  73. package/lib/junit-adapter/javascript.d.ts +0 -4
  74. package/lib/junit-adapter/python.d.ts +0 -5
  75. package/lib/junit-adapter/ruby.d.ts +0 -4
  76. package/lib/output.d.ts +0 -11
  77. package/lib/package.json +0 -3
  78. package/lib/pipe/bitbucket.d.ts +0 -25
  79. package/lib/pipe/csv.d.ts +0 -47
  80. package/lib/pipe/debug.d.ts +0 -29
  81. package/lib/pipe/github.d.ts +0 -30
  82. package/lib/pipe/gitlab.d.ts +0 -25
  83. package/lib/pipe/html.d.ts +0 -35
  84. package/lib/pipe/index.d.ts +0 -1
  85. package/lib/pipe/testomatio.d.ts +0 -71
  86. package/lib/replay.d.ts +0 -31
  87. package/lib/replay.js +0 -237
  88. package/lib/reporter-functions.d.ts +0 -34
  89. package/lib/reporter.d.ts +0 -232
  90. package/lib/services/artifacts.d.ts +0 -33
  91. package/lib/services/index.d.ts +0 -9
  92. package/lib/services/key-values.d.ts +0 -27
  93. package/lib/services/logger.d.ts +0 -64
  94. package/lib/uploader.d.ts +0 -60
  95. package/lib/utils/pipe_utils.d.ts +0 -41
  96. package/lib/utils/utils.d.ts +0 -54
  97. package/lib/xmlReader.d.ts +0 -92
  98. package/src/adapter/codecept.js +0 -373
  99. package/src/adapter/cucumber/current.js +0 -228
  100. package/src/adapter/cucumber/legacy.js +0 -158
  101. package/src/adapter/cucumber.js +0 -4
  102. package/src/adapter/cypress-plugin/index.js +0 -110
  103. package/src/adapter/jasmine.js +0 -60
  104. package/src/adapter/jest.js +0 -107
  105. package/src/adapter/mocha.cjs +0 -2
  106. package/src/adapter/mocha.js +0 -156
  107. package/src/adapter/nightwatch.js +0 -88
  108. package/src/adapter/playwright.js +0 -254
  109. package/src/adapter/vitest.js +0 -183
  110. package/src/adapter/webdriver.js +0 -142
  111. package/src/bin/cli.js +0 -348
  112. package/src/bin/reportXml.js +0 -77
  113. package/src/bin/startTest.js +0 -124
  114. package/src/bin/uploadArtifacts.js +0 -91
  115. package/src/client.js +0 -508
  116. package/src/config.js +0 -30
  117. package/src/constants.js +0 -53
  118. package/src/data-storage.js +0 -204
  119. package/src/junit-adapter/adapter.js +0 -23
  120. package/src/junit-adapter/csharp.js +0 -28
  121. package/src/junit-adapter/index.js +0 -28
  122. package/src/junit-adapter/java.js +0 -58
  123. package/src/junit-adapter/javascript.js +0 -31
  124. package/src/junit-adapter/python.js +0 -42
  125. package/src/junit-adapter/ruby.js +0 -10
  126. package/src/output.js +0 -57
  127. package/src/pipe/bitbucket.js +0 -252
  128. package/src/pipe/csv.js +0 -140
  129. package/src/pipe/debug.js +0 -119
  130. package/src/pipe/github.js +0 -232
  131. package/src/pipe/gitlab.js +0 -247
  132. package/src/pipe/html.js +0 -373
  133. package/src/pipe/index.js +0 -71
  134. package/src/pipe/testomatio.js +0 -504
  135. package/src/replay.js +0 -245
  136. package/src/reporter-functions.js +0 -55
  137. package/src/reporter.cjs_decprecated +0 -21
  138. package/src/reporter.js +0 -33
  139. package/src/services/artifacts.js +0 -59
  140. package/src/services/index.js +0 -13
  141. package/src/services/key-values.js +0 -59
  142. package/src/services/logger.js +0 -315
  143. package/src/template/emptyData.svg +0 -23
  144. package/src/template/testomatio.hbs +0 -1081
  145. package/src/uploader.js +0 -376
  146. package/src/utils/pipe_utils.js +0 -119
  147. package/src/utils/utils.js +0 -416
  148. package/src/xmlReader.js +0 -614
@@ -1,373 +0,0 @@
1
- import createDebugMessages from 'debug';
2
- import pc from 'picocolors';
3
- import TestomatClient from '../client.js';
4
- import { STATUS, APP_PREFIX, TESTOMAT_TMP_STORAGE_DIR } from '../constants.js';
5
- import { getTestomatIdFromTestTitle, fileSystem } from '../utils/utils.js';
6
- import { services } from '../services/index.js';
7
- import codeceptjs from 'codeceptjs';
8
-
9
- const debug = createDebugMessages('@testomatio/reporter:adapter:codeceptjs');
10
- // @ts-ignore
11
- if (!global.codeceptjs) {
12
- // @ts-ignore
13
- global.codeceptjs = codeceptjs;
14
- }
15
-
16
- // @ts-ignore
17
- const { event, recorder, codecept } = global.codeceptjs;
18
-
19
- let currentMetaStep = [];
20
- let error;
21
- let stepShift = 0;
22
-
23
- // const output = new Output({
24
- // filterFn: stack => !stack.includes('codeceptjs/lib/output'), // output from codeceptjs
25
- // });
26
-
27
- let stepStart = new Date();
28
-
29
- const MAJOR_VERSION = parseInt(codecept.version().match(/\d/)[0], 10);
30
-
31
- const DATA_REGEXP = /[|\s]+?(\{".*\}|\[.*\])/;
32
-
33
- if (MAJOR_VERSION < 3) {
34
- console.log('🔴 This reporter works with CodeceptJS 3+, please update your tests');
35
- }
36
-
37
- function CodeceptReporter(config) {
38
- let failedTests = [];
39
- let videos = [];
40
- let traces = [];
41
- const reportTestPromises = [];
42
-
43
- const testTimeMap = {};
44
- const { apiKey } = config;
45
-
46
- const getDuration = test => {
47
- if (!test.uid) return 0;
48
- if (testTimeMap[test.uid]) {
49
- return Date.now() - testTimeMap[test.uid];
50
- }
51
-
52
- return 0;
53
- };
54
-
55
- const client = new TestomatClient({ apiKey });
56
-
57
- recorder.startUnlessRunning();
58
-
59
- // Listening to events
60
- event.dispatcher.on(event.all.before, () => {
61
- // clear tmp dir
62
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
63
-
64
- // recorder.add('Creating new run', () => );
65
- client.createRun();
66
- videos = [];
67
- traces = [];
68
-
69
- if (!global.testomatioDataStore) global.testomatioDataStore = {};
70
- });
71
-
72
- let hookSteps = [];
73
- let suiteHookRunning = false;
74
-
75
- event.dispatcher.on(event.suite.before, suite => {
76
- suiteHookRunning = true;
77
- hookSteps = [];
78
- global.testomatioDataStore.steps = [];
79
-
80
- services.setContext(suite.fullTitle());
81
- });
82
-
83
- event.dispatcher.on(event.suite.after, () => {
84
- services.setContext(null);
85
- });
86
-
87
- event.dispatcher.on(event.hook.started, () => {
88
- // global.testomatioDataStore.steps = [];
89
- });
90
-
91
- event.dispatcher.on(event.hook.passed, () => {
92
- if (suiteHookRunning) {
93
- hookSteps.push(...global.testomatioDataStore.steps);
94
- services.setContext(null);
95
- }
96
- });
97
-
98
- event.dispatcher.on(event.hook.failed, () => {
99
- if (suiteHookRunning) {
100
- hookSteps.push(...global.testomatioDataStore.steps);
101
- services.setContext(null);
102
- }
103
- });
104
-
105
- event.dispatcher.on(event.test.before, test => {
106
- suiteHookRunning = false;
107
- global.testomatioDataStore.steps = [];
108
-
109
- recorder.add(() => {
110
- currentMetaStep = [];
111
- // output.reset();
112
- // output.start();
113
- stepShift = 0;
114
- });
115
-
116
- if (!global.testomatioDataStore) global.testomatioDataStore = {};
117
- // reset steps
118
- global.testomatioDataStore.steps = [];
119
-
120
- services.setContext(test.fullTitle());
121
- });
122
-
123
- event.dispatcher.on(event.test.started, test => {
124
- services.setContext(test.fullTitle());
125
-
126
- testTimeMap[test.id] = Date.now();
127
- if (!test.uid) return;
128
- testTimeMap[test.uid] = Date.now();
129
- });
130
-
131
- event.dispatcher.on(event.all.result, async () => {
132
- debug('waiting for all tests to be reported');
133
- // all tests were reported and we can upload videos
134
- await Promise.all(reportTestPromises);
135
-
136
- await uploadAttachments(client, videos, '🎞️ Uploading', 'video');
137
- await uploadAttachments(client, traces, '📁 Uploading', 'trace');
138
-
139
- const status = failedTests.length === 0 ? STATUS.PASSED : STATUS.FAILED;
140
- // @ts-ignore
141
- client.updateRunStatus(status);
142
- });
143
-
144
- event.dispatcher.on(event.test.passed, test => {
145
- const { uid, tags, title } = test;
146
- if (uid && failedTests.includes(uid)) {
147
- failedTests = failedTests.filter(failed => uid !== failed);
148
- }
149
- const testObj = getTestAndMessage(title);
150
-
151
- const logs = getTestLogs(test);
152
- const manuallyAttachedArtifacts = services.artifacts.get(test.fullTitle());
153
- const keyValues = services.keyValues.get(test.fullTitle());
154
- services.setContext(null);
155
-
156
- client.addTestRun(STATUS.PASSED, {
157
- ...stripExampleFromTitle(title),
158
- rid: uid,
159
- suite_title: test.parent && test.parent.title,
160
- message: testObj.message,
161
- time: getDuration(test),
162
- steps: global.testomatioDataStore.steps.join('\n') || null,
163
- test_id: getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`),
164
- logs,
165
- manuallyAttachedArtifacts,
166
- meta: keyValues,
167
- });
168
- // output.stop();
169
- });
170
-
171
- event.dispatcher.on(event.test.failed, (test, err) => {
172
- error = err;
173
- });
174
-
175
- event.dispatcher.on(event.hook.failed, (suite, err) => {
176
- error = err;
177
-
178
- if (!suite) return;
179
- if (!suite.tests) return;
180
- for (const test of suite.tests) {
181
- const { uid, tags, title } = test;
182
- failedTests.push(uid || title);
183
- const testId = getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`);
184
-
185
- client.addTestRun(STATUS.FAILED, {
186
- rid: uid,
187
- ...stripExampleFromTitle(title),
188
- suite_title: suite.title,
189
- test_id: testId,
190
- error,
191
- time: 0,
192
- });
193
- }
194
- // output.stop();
195
- });
196
-
197
- event.dispatcher.on(event.test.after, test => {
198
- if (test.state && test.state !== STATUS.FAILED) return;
199
- if (test.err) error = test.err;
200
- const { uid, tags, title, artifacts } = test;
201
- failedTests.push(uid || title);
202
- const testObj = getTestAndMessage(title);
203
-
204
- const files = [];
205
- if (artifacts.screenshot) files.push({ path: artifacts.screenshot, type: 'image/png' });
206
- // todo: video must be uploaded later....
207
-
208
- const logs = getTestLogs(test);
209
- const manuallyAttachedArtifacts = services.artifacts.get(test.fullTitle());
210
- const keyValues = services.keyValues.get(test.fullTitle());
211
- services.setContext(null);
212
-
213
- client.addTestRun(STATUS.FAILED, {
214
- ...stripExampleFromTitle(title),
215
- rid: uid,
216
- test_id: getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`),
217
- suite_title: test.parent && test.parent.title,
218
- error,
219
- message: testObj.message,
220
- time: getDuration(test),
221
- files,
222
- steps: global.testomatioDataStore?.steps?.join('\n') || null,
223
- logs,
224
- manuallyAttachedArtifacts,
225
- meta: keyValues,
226
- });
227
-
228
- debug('artifacts', artifacts);
229
-
230
- for (const aid in artifacts) {
231
- if (aid.startsWith('video')) videos.push({ rid: uid, title, path: artifacts[aid], type: 'video/webm' });
232
- if (aid.startsWith('trace')) traces.push({ rid: uid, title, path: artifacts[aid], type: 'application/zip' });
233
- }
234
-
235
- // output.stop();
236
- });
237
-
238
- event.dispatcher.on(event.test.skipped, test => {
239
- const { uid, tags, title } = test;
240
- if (failedTests.includes(uid || title)) return;
241
-
242
- const testObj = getTestAndMessage(title);
243
- client.addTestRun(STATUS.SKIPPED, {
244
- rid: uid,
245
- ...stripExampleFromTitle(title),
246
- test_id: getTestomatIdFromTestTitle(`${title} ${tags?.join(' ')}`),
247
- suite_title: test.parent && test.parent.title,
248
- message: testObj.message,
249
- time: getDuration(test),
250
- });
251
- // output.stop();
252
- });
253
-
254
- event.dispatcher.on(event.step.started, step => {
255
- stepShift = 0;
256
- step.started = true;
257
- stepStart = new Date();
258
- });
259
-
260
- event.dispatcher.on(event.step.finished, step => {
261
- if (!step.started) return;
262
- let processingStep = step;
263
- const metaSteps = [];
264
- while (processingStep.metaStep) {
265
- metaSteps.unshift(processingStep.metaStep);
266
- processingStep = processingStep.metaStep;
267
- }
268
- const shift = metaSteps.length;
269
-
270
- for (let i = 0; i < Math.max(currentMetaStep.length, metaSteps.length); i++) {
271
- if (currentMetaStep[i] !== metaSteps[i]) {
272
- stepShift = 2 * i;
273
- if (!metaSteps[i]) continue;
274
- if (metaSteps[i].isBDD()) {
275
- // output.push(repeat(stepShift) + pc.bold(metaSteps[i].toString()) + metaSteps[i].comment);
276
- global.testomatioDataStore?.steps?.push(
277
- repeat(stepShift) + pc.bold(metaSteps[i].toString()) + metaSteps[i].comment,
278
- );
279
- } else {
280
- // output.push(repeat(stepShift) + pc.green.bold(metaSteps[i].toString()));
281
- global.testomatioDataStore?.steps?.push(repeat(stepShift) + pc.green(pc.bold(metaSteps[i].toString())));
282
- }
283
- }
284
- }
285
- currentMetaStep = metaSteps;
286
- stepShift = 2 * shift;
287
-
288
- const durationMs = +new Date() - +stepStart;
289
- let duration = '';
290
- if (durationMs) {
291
- duration = repeat(1) + pc.gray(`(${durationMs}ms)`);
292
- }
293
-
294
- if (step.status === STATUS.FAILED) {
295
- // output.push(repeat(stepShift) + pc.red(step.toString()) + duration);
296
- global.testomatioDataStore?.steps?.push(repeat(stepShift) + pc.red(step.toString()) + duration);
297
- } else {
298
- // output.push(repeat(stepShift) + step.toString() + duration);
299
- global.testomatioDataStore?.steps?.push(repeat(stepShift) + step.toString() + duration);
300
- }
301
- });
302
-
303
- event.dispatcher.on(event.step.comment, step => {
304
- // output.push(pc.cyan.bold(step.toString()));
305
- global.testomatioDataStore?.steps?.push(pc.cyan(pc.bold(step.toString())));
306
- });
307
- }
308
-
309
- async function uploadAttachments(client, attachments, messagePrefix, attachmentType) {
310
- if (!attachments?.length) return;
311
-
312
- if (client.uploader.isEnabled) {
313
- console.log(APP_PREFIX, `Attachments: ${messagePrefix} ${attachments.length} ${attachmentType} ...`);
314
- }
315
-
316
- const promises = attachments.map(async attachment => {
317
- const { rid, title, path, type } = attachment;
318
- const file = { path, type, title };
319
-
320
- // we are storing file if upload is disabled
321
- if (!client.uploader.isEnabled) return client.uploader.storeUploadedFile(path, client.runId, rid, false);
322
-
323
- return client.addTestRun(undefined, {
324
- ...stripExampleFromTitle(title),
325
- rid,
326
- files: [file],
327
- });
328
- });
329
-
330
- await Promise.all(promises);
331
- }
332
-
333
- function getTestAndMessage(title) {
334
- const testObj = { message: '' };
335
- const testArr = title.split(/\s(\|\s\{.*?\})/);
336
- testObj.title = testArr[0];
337
-
338
- return testObj;
339
- }
340
-
341
- function stripExampleFromTitle(title) {
342
- const res = title.match(DATA_REGEXP);
343
- if (!res) return { title, example: null };
344
-
345
- const example = JSON.parse(res[1]);
346
- title = title.replace(DATA_REGEXP, '').trim();
347
-
348
- return { title, example };
349
- }
350
-
351
- function repeat(num) {
352
- return ''.padStart(num, ' ');
353
- }
354
-
355
- // TODO: think about moving to some common utils
356
- function getTestLogs(test) {
357
- const suiteLogsArr = services.logger.getLogs(test.parent.fullTitle());
358
- const suiteLogs = suiteLogsArr ? suiteLogsArr.join('\n').trim() : '';
359
- const testLogsArr = services.logger.getLogs(test.fullTitle());
360
- const testLogs = testLogsArr ? testLogsArr.join('\n').trim() : '';
361
-
362
- let logs = '';
363
- if (suiteLogs) {
364
- logs += `${pc.bold('\t--- BeforeSuite ---')}\n${suiteLogs}`;
365
- }
366
- if (testLogs) {
367
- logs += `\n${pc.bold('\t--- Test ---')}\n${testLogs}`;
368
- }
369
- return logs;
370
- }
371
-
372
- export { CodeceptReporter };
373
- export default CodeceptReporter;
@@ -1,228 +0,0 @@
1
- import { Formatter, formatterHelpers } from '@cucumber/cucumber';
2
-
3
- import pc from 'picocolors';
4
- import fs from 'fs';
5
- import { STATUS, TESTOMAT_TMP_STORAGE_DIR } from '../../constants.js';
6
- import TestomatClient from '../../client.js';
7
- import { getTestomatIdFromTestTitle, fileSystem } from '../../utils/utils.js';
8
- import { config } from '../../config.js';
9
- import { services } from '../../services/index.js';
10
-
11
- const { GherkinDocumentParser, PickleParser } = formatterHelpers;
12
- const { getGherkinScenarioLocationMap, getGherkinStepMap } = GherkinDocumentParser;
13
- const { getPickleStepMap } = PickleParser;
14
-
15
- function getTestId(scenario) {
16
- if (scenario) {
17
- for (const tag of scenario.tags) {
18
- const testId = getTestomatIdFromTestTitle(tag.name);
19
- if (testId) return testId;
20
- }
21
- }
22
-
23
- return null;
24
- }
25
-
26
- class CucumberReporter extends Formatter {
27
- constructor(options) {
28
- super(options);
29
- options.eventBroadcaster.on('envelope', this.parseEnvelope.bind(this));
30
- this.failures = [];
31
- this.cases = [];
32
-
33
- this.client = new TestomatClient({ apiKey: options.apiKey || config.TESTOMATIO });
34
- this.client.createRun();
35
- this.status = STATUS.PASSED;
36
- }
37
-
38
- parseEnvelope(envelope) {
39
- if (envelope.testRunStarted) {
40
- fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
41
- }
42
- if (envelope.testCaseStarted && this.client) {
43
- this.onTestCaseStarted(envelope.testCaseStarted);
44
- }
45
- if (envelope.testCaseFinished) this.onTestCaseFinished(envelope.testCaseFinished);
46
- if (envelope.testRunFinished) this.onTestRunFinished(envelope);
47
- }
48
-
49
- onTestCaseStarted(testCaseStarted) {
50
- const testCaseAttempt = this.eventDataCollector.getTestCaseAttempt(testCaseStarted.id);
51
- if (!global.testomatioDataStore) global.testomatioDataStore = {};
52
-
53
- const testTitle = testCaseAttempt.pickle.name + testCaseAttempt.pickle.uri;
54
- services.setContext(testTitle);
55
- }
56
-
57
- onTestCaseFinished(testCaseFinished) {
58
- const testCaseAttempt = this.eventDataCollector.getTestCaseAttempt(testCaseFinished.testCaseStartedId);
59
-
60
- let example;
61
-
62
- let status = STATUS.PASSED;
63
- let color = 'green';
64
- let message;
65
-
66
- this.cases.push(testCaseAttempt);
67
-
68
- if (testCaseAttempt.worstTestStepResult) {
69
- if (testCaseAttempt.worstTestStepResult.status === 'SKIPPED') {
70
- status = STATUS.SKIPPED;
71
- }
72
- // if (testCaseAttempt.worstTestStepResult.status === 'UNDEFINED') {
73
- // status = STATUS.SKIPPED;
74
- // message = 'Undefined steps. Implement missing steps and rerun this scenario';
75
- // }
76
- if (testCaseAttempt.worstTestStepResult.status === 'FAILED') {
77
- message = testCaseAttempt?.worstTestStepResult?.message;
78
- status = STATUS.FAILED;
79
- }
80
- color = getStatusColor(testCaseAttempt.worstTestStepResult.status);
81
- if (status !== STATUS.PASSED) this.failures.push(testCaseAttempt);
82
- }
83
-
84
- if (testCaseAttempt.pickle.astNodeIds.length > 1) {
85
- example = getExample(testCaseAttempt);
86
- // @ts-ignore
87
- testCaseAttempt.example = example;
88
- }
89
-
90
- const scenario = testCaseAttempt.pickle.name;
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);
94
-
95
- let exampleString = '';
96
- if (example) exampleString = ` ${example.join(' | ')}`;
97
- let cliMessage = `${pc.bold(scenario)}${exampleString}: ${pc[color](pc.bold(status.toUpperCase()))} `;
98
-
99
- if (message) cliMessage += pc.gray(message.split('\n')[0]);
100
- console.log(cliMessage);
101
-
102
- if (status !== STATUS.PASSED && status !== STATUS.SKIPPED) {
103
- this.status = STATUS.FAILED;
104
- }
105
-
106
- const time = Object.values(testCaseAttempt.stepResults)
107
- .map(t => t.duration)
108
- .reduce((sum, duration) => sum + duration.seconds * 1000 + duration.nanos / 1000000, 0);
109
-
110
- if (!this.client) return;
111
-
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);
116
-
117
- this.client.addTestRun(status, {
118
- // error: testCaseAttempt.worstTestStepResult.message,
119
- message,
120
- steps: getSteps(testCaseAttempt)
121
- .map(s => s.toString())
122
- .join('\n')
123
- .trim(),
124
- example: { ...example },
125
- logs,
126
- manuallyAttachedArtifacts: artifacts,
127
- meta: keyValues,
128
- title: scenario,
129
- test_id: testId,
130
- time,
131
- });
132
-
133
- services.setContext(null);
134
- }
135
-
136
- onTestRunFinished(envelope) {
137
- if (this.failures.length > 0) {
138
- console.log(pc.bold('\nSUMMARY:\n\n'));
139
-
140
- this.failures.forEach((tc, i) => {
141
- let message = ` ${i + 1}) ${tc.pickle.name}\n`;
142
-
143
- const steps = getSteps(tc);
144
-
145
- steps.forEach(s => {
146
- message += ` ${s.toString()}\n`;
147
- });
148
-
149
- console.log(message);
150
- if (tc?.worstTestStepResult?.message) {
151
- console.log(pc.red(tc?.worstTestStepResult?.message));
152
- }
153
- console.log();
154
- });
155
- }
156
-
157
- const { testRunFinished } = envelope;
158
-
159
- const bgColor = testRunFinished.success ? 'bgGreen' : 'bgRed';
160
- const prefixSummary = `${pc.bold(testRunFinished.success ? ' SUCCESS ' : ' FALIURE ')}`;
161
- console.log();
162
- console.log(pc[bgColor](` ${prefixSummary} | Total Scenarios: ${pc.bold(this.cases.length)} `));
163
-
164
- if (!this.client) return;
165
-
166
- // @ts-ignore
167
- this.client.updateRunStatus(testRunFinished.success ? STATUS.PASSED : STATUS.FAILED);
168
- }
169
- }
170
-
171
- function getSteps(tc) {
172
- const stepIds = Object.keys(tc.stepResults);
173
- const pickleSteps = getPickleStepMap(tc.pickle);
174
- return stepIds
175
- .map(stepId => {
176
- const ts = tc.testCase.testSteps.find(t => t.id === stepId);
177
- if (!ts) return;
178
- if (!ts.pickleStepId) return;
179
- const result = tc.stepResults[stepId];
180
- const pickleStep = pickleSteps[ts.pickleStepId];
181
- const sourceStepId = pickleStep.astNodeIds[0];
182
- const step = {
183
- text: pickleStep.text,
184
- duration: result.duration,
185
- status: result.status,
186
- };
187
- const color = getStatusColor(result.status);
188
- if (sourceStepId && getGherkinStepMap(tc.gherkinDocument)[sourceStepId]) {
189
- step.keyword = getGherkinStepMap(tc.gherkinDocument)[sourceStepId].keyword;
190
- }
191
- step.toString = function toString() {
192
- const duration = step.duration.seconds * 1000 + step.duration.nanos / 1000000;
193
- const durationString = ` ${pc.gray(`(${Number(duration).toFixed(2)}ms)`)}`;
194
- const stepString = `${pc.bold(this.keyword)}${this.text}`.trim();
195
- if (color === 'red') return pc.red(stepString) + durationString;
196
- if (color === 'yellow') return pc.yellow(stepString) + durationString;
197
- return stepString + durationString;
198
- };
199
- return step;
200
- })
201
- .filter(s => !!s);
202
- }
203
-
204
- function getStatusColor(status) {
205
- if (status === 'UNDEFINED') return 'yellow';
206
- if (status === 'SKIPPED') return 'yellow';
207
- if (status === 'FAILED') return 'red';
208
- return 'green';
209
- }
210
-
211
- function getExample(testCaseAttempt) {
212
- const nodesMap = getGherkinScenarioLocationMap(testCaseAttempt.gherkinDocument);
213
- const exampleNodeId = testCaseAttempt.pickle.astNodeIds[1];
214
- if (!nodesMap[exampleNodeId]) return;
215
- const featureDoc = fs.readFileSync(testCaseAttempt.gherkinDocument.uri).toString();
216
- const { line } = nodesMap[exampleNodeId];
217
- const example = featureDoc.split('\n')[line - 1];
218
- if (example) {
219
- return example
220
- .trim()
221
- .split('|')
222
- .filter(r => !!r)
223
- .map(r => r.trim());
224
- }
225
- }
226
-
227
- export { CucumberReporter };
228
- export default CucumberReporter;