@testomatio/reporter 1.2.1-beta → 1.2.1-beta.codecept-id.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.
Files changed (47) hide show
  1. package/README.md +61 -54
  2. package/lib/adapter/codecept.js +140 -61
  3. package/lib/adapter/cucumber/current.js +103 -60
  4. package/lib/adapter/cucumber/legacy.js +27 -12
  5. package/lib/adapter/cucumber.js +2 -2
  6. package/lib/adapter/cypress-plugin/index.js +52 -25
  7. package/lib/adapter/jasmine.js +1 -1
  8. package/lib/adapter/jest.js +49 -11
  9. package/lib/adapter/mocha.js +103 -51
  10. package/lib/adapter/playwright.js +100 -31
  11. package/lib/adapter/webdriver.js +1 -1
  12. package/lib/bin/reportXml.js +14 -13
  13. package/lib/bin/startTest.js +27 -6
  14. package/lib/client.js +193 -69
  15. package/lib/config.js +34 -0
  16. package/lib/constants.js +19 -7
  17. package/lib/data-storage.js +203 -0
  18. package/lib/fileUploader.js +128 -53
  19. package/lib/junit-adapter/adapter.js +0 -2
  20. package/lib/junit-adapter/csharp.js +3 -4
  21. package/lib/junit-adapter/index.js +3 -3
  22. package/lib/junit-adapter/java.js +35 -17
  23. package/lib/junit-adapter/javascript.js +1 -2
  24. package/lib/junit-adapter/python.js +12 -14
  25. package/lib/junit-adapter/ruby.js +1 -2
  26. package/lib/pipe/csv.js +5 -3
  27. package/lib/pipe/github.js +27 -39
  28. package/lib/pipe/gitlab.js +20 -24
  29. package/lib/pipe/html.js +317 -0
  30. package/lib/pipe/index.js +3 -1
  31. package/lib/pipe/testomatio.js +182 -55
  32. package/lib/reporter-functions.js +46 -0
  33. package/lib/reporter.js +11 -9
  34. package/lib/services/artifacts.js +57 -0
  35. package/lib/services/index.js +13 -0
  36. package/lib/services/key-values.js +58 -0
  37. package/lib/services/logger.js +311 -0
  38. package/lib/template/template-draft.hbs +249 -0
  39. package/lib/template/testomatio.hbs +388 -0
  40. package/lib/utils/pipe_utils.js +128 -0
  41. package/lib/{util.js → utils/utils.js} +145 -12
  42. package/lib/xmlReader.js +211 -122
  43. package/package.json +18 -8
  44. package/lib/_ArtifactStorageOld.js +0 -142
  45. package/lib/artifactStorage.js +0 -25
  46. package/lib/dataStorage.js +0 -180
  47. package/lib/logger.js +0 -278
@@ -11,7 +11,10 @@ const debug = require('debug')('@testomatio/reporter:util');
11
11
  * @returns {String|null} testId
12
12
  */
13
13
  const parseTest = testTitle => {
14
- const captures = testTitle.match(/@T([\w\d]+)/);
14
+ if (!testTitle) return null;
15
+
16
+ const captures = testTitle.match(/\@T[\w\d]{8}/);
17
+
15
18
  if (captures) {
16
19
  return captures[1];
17
20
  }
@@ -25,7 +28,7 @@ const parseTest = testTitle => {
25
28
  * @returns {String|null} suiteId
26
29
  */
27
30
  const parseSuite = suiteTitle => {
28
- const captures = suiteTitle.match(/@S([\w\d]+)/);
31
+ const captures = suiteTitle.match(/\@S[\w\d]{8}/);
29
32
  if (captures) {
30
33
  return captures[1];
31
34
  }
@@ -52,11 +55,20 @@ const isValidUrl = s => {
52
55
  }
53
56
  };
54
57
 
58
+ const fileMatchRegex = /file:(\/\/?[^:\s]+?\.(png|avi|webm|jpg|html|txt))/gi;
59
+
55
60
  const fetchFilesFromStackTrace = (stack = '') => {
56
- const files = stack.matchAll(/file:?\/(\/.*?\.(png|avi|webm|jpg|html|txt))/g);
57
- return Array.from(files)
58
- .map(f => f[1])
59
- .filter(f => fs.existsSync(f));
61
+ const files = Array.from(stack.matchAll(fileMatchRegex))
62
+ .map(f => f[1].trim())
63
+ .map(f => (f.startsWith('//') ? f.substring(1) : f));
64
+
65
+ debug('Found files in stack trace: ', files);
66
+
67
+ return files.filter(f => {
68
+ const isFile = fs.existsSync(f);
69
+ if (!isFile) debug('File %s could not be found and uploaded as artifact', f);
70
+ return isFile;
71
+ });
60
72
  };
61
73
 
62
74
  const fetchSourceCodeFromStackTrace = (stack = '') => {
@@ -84,11 +96,41 @@ const fetchSourceCodeFromStackTrace = (stack = '') => {
84
96
 
85
97
  if (!source) return '';
86
98
 
87
- return source.split('\n')
99
+ return source
100
+ .split('\n')
88
101
  .map((l, i) => {
89
102
  if (i === prepend) return `${line} > ${chalk.bold(l)}`;
90
- return `${line - prepend + i} | ${l}`
91
- }).join('\n');
103
+ return `${line - prepend + i} | ${l}`;
104
+ })
105
+ .join('\n');
106
+ };
107
+
108
+ const TEST_ID_REGEX = /@T([\w\d]{8})/;
109
+
110
+ const fetchIdFromCode = (code, opts = {}) => {
111
+ const comments = code
112
+ .split('\n')
113
+ .map(l => l.trim())
114
+ .filter(l => {
115
+ switch (opts.lang) {
116
+ case 'ruby':
117
+ case 'python':
118
+ return l.startsWith('# ');
119
+ default:
120
+ return l.startsWith('// ');
121
+ }
122
+ });
123
+
124
+ return comments.find(c => c.match(TEST_ID_REGEX))?.match(TEST_ID_REGEX)?.[1];
125
+ };
126
+
127
+ const fetchIdFromOutput = output => {
128
+ const lines = output
129
+ .split('\n')
130
+ .map(l => l.trim())
131
+ .filter(l => l.startsWith('tid://'));
132
+
133
+ return lines.find(c => c.match(TEST_ID_REGEX))?.match(TEST_ID_REGEX)?.[1];
92
134
  };
93
135
 
94
136
  const fetchSourceCode = (contents, opts = {}) => {
@@ -103,7 +145,15 @@ const fetchSourceCode = (contents, opts = {}) => {
103
145
  // remove special chars from title
104
146
  if (!lineIndex && opts.title) {
105
147
  const title = opts.title.replace(/[([@].*/g, '');
106
- lineIndex = lines.findIndex(l => l.includes(title));
148
+
149
+ if (opts.lang === 'java') {
150
+ lineIndex = lines.findIndex(l => l.includes(`test${title}`));
151
+ if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`@DisplayName("${title}`));
152
+ if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
153
+ if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`${title}(`));
154
+ } else {
155
+ lineIndex = lines.findIndex(l => l.includes(title));
156
+ }
107
157
  }
108
158
 
109
159
  if (opts.prepend) {
@@ -112,7 +162,7 @@ const fetchSourceCode = (contents, opts = {}) => {
112
162
 
113
163
  if (lineIndex) {
114
164
  const result = [];
115
- for (let i = lineIndex; i < (lineIndex + limit); i++) {
165
+ for (let i = lineIndex; i < lineIndex + limit; i++) {
116
166
  if (lines[i] === undefined) continue;
117
167
 
118
168
  if (i > lineIndex + 2 && !opts.prepend) {
@@ -186,13 +236,92 @@ const fileSystem = {
186
236
  } else {
187
237
  debug(`Trying to delete ${dirPath} but it doesn't exist`);
188
238
  }
189
- }
239
+ },
240
+ };
241
+
242
+ const foundedTestLog = (app, tests) => {
243
+ const n = tests.length;
244
+
245
+ return n === 1 ? console.log(app, `✅ We found one test!`) : console.log(app, `✅ We found ${n} tests!`);
246
+ };
247
+
248
+ const humanize = text => {
249
+ text = decamelize(text);
250
+ return text
251
+ .replace(/_./g, match => ` ${match.charAt(1).toUpperCase()}`)
252
+ .trim()
253
+ .replace(/^(.)|\s(.)/g, $1 => $1.toUpperCase())
254
+ .trim()
255
+ .replace(/\sA\s/g, ' a ') // replace a|the
256
+ .replace(/\sThe\s/g, ' the ') // replace a|the
257
+ .replace(/^Test\s/, '')
258
+ .replace(/^Should\s/, '');
259
+ };
260
+
261
+ /**
262
+ * From https://github.com/sindresorhus/decamelize/blob/main/index.js
263
+ * @param {*} text
264
+ * @returns
265
+ */
266
+ const decamelize = text => {
267
+ const separator = '_';
268
+ const replacement = `$1${separator}$2`;
269
+
270
+ // Split lowercase sequences followed by uppercase character.
271
+ // `dataForUSACounties` → `data_For_USACounties`
272
+ // `myURLstring → `my_URLstring`
273
+ let decamelized = text.replace(/([\p{Lowercase_Letter}\d])(\p{Uppercase_Letter})/gu, replacement);
274
+
275
+ // Lowercase all single uppercase characters. As we
276
+ // want to preserve uppercase sequences, we cannot
277
+ // simply lowercase the separated string at the end.
278
+ // `data_For_USACounties` → `data_for_USACounties`
279
+ decamelized = decamelized.replace(
280
+ /((?<![\p{Uppercase_Letter}\d])[\p{Uppercase_Letter}\d](?![\p{Uppercase_Letter}\d]))/gu,
281
+ $0 => $0.toLowerCase(),
282
+ );
283
+
284
+ // Remaining uppercase sequences will be separated from lowercase sequences.
285
+ // `data_For_USACounties` → `data_for_USA_counties`
286
+ return decamelized.replace(
287
+ /(\p{Uppercase_Letter}+)(\p{Uppercase_Letter}\p{Lowercase_Letter}+)/gu,
288
+ (_, $1, $2) => $1 + separator + $2.toLowerCase(),
289
+ );
290
+ };
291
+
292
+ /**
293
+ * Used to remove color codes
294
+ * @param {*} input
295
+ * @returns
296
+ */
297
+ function removeColorCodes(input) {
298
+ // eslint-disable-next-line no-control-regex
299
+ return input.replace(/\x1b\[[0-9;]*m/g, '');
300
+ }
301
+
302
+ const testRunnerHelper = {
303
+ // for Jest
304
+ getNameOfCurrentlyRunningTest: () => {
305
+ if (global.testomatioTestTitle) return global.testomatioTestTitle;
306
+
307
+ if (!process.env.JEST_WORKER_ID) return null;
308
+ try {
309
+ // TODO: expect?.getState()?.testPath + ' ' + expect?.getState()?.currentTestName
310
+ // @ts-expect-error "expect" could only be defined inside Jest environement (forbidden to import it outside)
311
+ // eslint-disable-next-line no-undef
312
+ return expect?.getState()?.currentTestName;
313
+ } catch (e) {
314
+ return null;
315
+ }
316
+ },
190
317
  };
191
318
 
192
319
  module.exports = {
193
320
  isSameTest,
194
321
  fetchSourceCode,
195
322
  fetchSourceCodeFromStackTrace,
323
+ fetchIdFromCode,
324
+ fetchIdFromOutput,
196
325
  fetchFilesFromStackTrace,
197
326
  fileSystem,
198
327
  getCurrentDateTime,
@@ -201,4 +330,8 @@ module.exports = {
201
330
  ansiRegExp,
202
331
  parseTest,
203
332
  parseSuite,
333
+ humanize,
334
+ removeColorCodes,
335
+ foundedTestLog,
336
+ testRunnerHelper,
204
337
  };