@testomatio/reporter 2.0.1-beta.3 → 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,470 +1,379 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.validateSuiteId = exports.testRunnerHelper = exports.specificTestInfo = exports.parseSuite = exports.isValidUrl = exports.humanize = exports.getTestomatIdFromTestTitle = exports.getCurrentDateTime = exports.foundedTestLog = exports.fileSystem = exports.fetchFilesFromStackTrace = exports.fetchIdFromOutput = exports.fetchIdFromCode = exports.fetchSourceCodeFromStackTrace = exports.fetchSourceCode = exports.isSameTest = exports.ansiRegExp = exports.SUITE_ID_REGEX = exports.TEST_ID_REGEX = void 0;
40
- exports.getPackageVersion = getPackageVersion;
41
- exports.formatStep = formatStep;
42
- exports.readLatestRunId = readLatestRunId;
43
- exports.removeColorCodes = removeColorCodes;
44
- exports.storeRunId = storeRunId;
45
- const url_1 = require("url");
46
- const path_1 = __importStar(require("path"));
47
- const picocolors_1 = __importDefault(require("picocolors"));
48
- const fs_1 = __importDefault(require("fs"));
49
- const is_valid_path_1 = __importDefault(require("is-valid-path"));
50
- const debug_1 = __importDefault(require("debug"));
51
- const os_1 = __importDefault(require("os"));
52
- const url_2 = require("url");
53
- const debug = (0, debug_1.default)('@testomatio/reporter:util');
54
- // Use __dirname directly since we're compiling to CommonJS
55
- // prettier-ignore
56
- // @ts-ignore
57
- // eslint-disable-next-line max-len
1
+ const { URL } = require('url');
2
+ const { sep, basename } = require('path');
3
+ const chalk = require('chalk');
4
+ const fs = require('fs');
5
+ const isValid = require('is-valid-path');
6
+ const path = require('path');
7
+ const os = require('os');
8
+ const debug = require('debug')('@testomatio/reporter:util');
9
+
58
10
  /**
59
11
  * @param {String} testTitle - Test title
60
12
  *
61
13
  * @returns {String|null} testId
62
14
  */
63
15
  const getTestomatIdFromTestTitle = testTitle => {
64
- if (!testTitle)
65
- return null;
66
- const captures = testTitle.match(/@T[\w\d]{8}/);
67
- if (captures) {
68
- return captures[0];
69
- }
70
- return null;
16
+ if (!testTitle) return null;
17
+
18
+ const captures = testTitle.match(/@T[\w\d]{8}/);
19
+
20
+ if (captures) {
21
+ return captures[0];
22
+ }
23
+
24
+ return null;
71
25
  };
72
- exports.getTestomatIdFromTestTitle = getTestomatIdFromTestTitle;
26
+
73
27
  /**
74
28
  * @param {String} suiteTitle - suite title
75
29
  *
76
30
  * @returns {String|null} suiteId
77
31
  */
78
32
  const parseSuite = suiteTitle => {
79
- const captures = suiteTitle.match(/@S[\w\d]{8}/);
80
- if (captures) {
81
- return captures[0];
82
- }
83
- return null;
84
- };
85
- exports.parseSuite = parseSuite;
86
- /**
87
- * Validates TESTOMATIO_SUITE environment variable format
88
- * @param {String} suiteId - suite ID to validate
89
- * @returns {String|null} validated suite ID or null if invalid
90
- */
91
- const validateSuiteId = suiteId => {
92
- if (!suiteId)
93
- return null;
94
- const match = suiteId.match(exports.SUITE_ID_REGEX);
95
- return match ? match[0] : null;
33
+ const captures = suiteTitle.match(/@S[\w\d]{8}/);
34
+ if (captures) {
35
+ return captures[1];
36
+ }
37
+
38
+ return null;
96
39
  };
97
- exports.validateSuiteId = validateSuiteId;
40
+
98
41
  const ansiRegExp = () => {
99
- const pattern = [
100
- '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
101
- '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))',
102
- ].join('|');
103
- return new RegExp(pattern, 'g');
42
+ const pattern = [
43
+ '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
44
+ '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))',
45
+ ].join('|');
46
+
47
+ return new RegExp(pattern, 'g');
104
48
  };
105
- exports.ansiRegExp = ansiRegExp;
49
+
106
50
  const isValidUrl = s => {
107
- try {
108
- new url_1.URL(s);
109
- return true;
110
- }
111
- catch (err) {
112
- return false;
113
- }
51
+ try {
52
+ // eslint-disable-next-line no-new
53
+ new URL(s);
54
+ return true;
55
+ } catch (err) {
56
+ return false;
57
+ }
114
58
  };
115
- exports.isValidUrl = isValidUrl;
116
- const fileMatchRegex = /file:(\/+(?:[A-Za-z]:[\\/]|\/)?[^\s]*?\.(png|avi|webm|jpg|html|txt))/gi;
117
- const fetchFilesFromStackTrace = (stack = '', checkExists = true) => {
118
- const files = Array.from(stack.matchAll(fileMatchRegex))
119
- .map(f => f[1].trim())
120
- .map(f => f.replace(/^\/+/, '/').replace(/^\/([A-Za-z]:)/, '$1')) // Remove extra slashes, handle Windows paths
121
- .map(f => {
122
- // Convert Windows paths to Linux paths for testing purposes
123
- if (f.match(/^[A-Za-z]:[\\\/]/)) {
124
- // Convert Windows path to Linux equivalent for test scenarios
125
- return f.replace(/^[A-Za-z]:[\\\/]/, '/').replace(/\\/g, '/');
126
- }
127
- return f;
128
- });
129
- debug('Found files in stack trace: ', files);
130
- return files.filter(f => {
131
- if (!checkExists)
132
- return true;
133
- const isFile = fs_1.default.existsSync(f);
134
- if (!isFile)
135
- debug('File %s could not be found and uploaded as artifact', f);
136
- return isFile;
137
- });
59
+
60
+ const fileMatchRegex = /file:(\/\/?[^:\s]+?\.(png|avi|webm|jpg|html|txt))/gi;
61
+
62
+ const fetchFilesFromStackTrace = (stack = '') => {
63
+ const files = Array.from(stack.matchAll(fileMatchRegex))
64
+ .map(f => f[1].trim())
65
+ .map(f => (f.startsWith('//') ? f.substring(1) : f));
66
+
67
+ debug('Found files in stack trace: ', files);
68
+
69
+ return files.filter(f => {
70
+ const isFile = fs.existsSync(f);
71
+ if (!isFile) debug('File %s could not be found and uploaded as artifact', f);
72
+ return isFile;
73
+ });
138
74
  };
139
- exports.fetchFilesFromStackTrace = fetchFilesFromStackTrace;
75
+
140
76
  const fetchSourceCodeFromStackTrace = (stack = '') => {
141
- const stackLines = stack
142
- .split('\n')
143
- .filter(l => l.includes(':'))
144
- // .map(l => l.match(/\[(.*?)\]/)?.[1] || l) // minitest format
145
- // .map(l => l.split(':')[0])
146
- .map(l => l.trim())
147
- .map(l => l.split(' ').find(p => p.includes(':')) || '')
148
- .filter(l => (0, is_valid_path_1.default)(l?.split(':')[0]))
149
- // // filter out 3rd party libs
150
- .filter(l => !l?.includes(`vendor${path_1.sep}`))
151
- .filter(l => !l?.includes(`node_modules${path_1.sep}`))
152
- .filter(l => fs_1.default.existsSync(l.split(':')[0]))
153
- .filter(l => fs_1.default.lstatSync(l.split(':')[0]).isFile());
154
- if (!stackLines.length)
155
- return '';
156
- const [file, line] = stackLines[0].split(':');
157
- const prepend = 3;
158
- const source = fetchSourceCode(fs_1.default.readFileSync(file).toString(), { line, prepend, limit: 7 });
159
- if (!source)
160
- return '';
161
- return source
162
- .split('\n')
163
- .map((l, i) => {
164
- if (i === prepend)
165
- return `${line} > ${picocolors_1.default.bold(l)}`;
166
- return `${+line - prepend + i} | ${l}`;
77
+ const stackLines = stack
78
+ .split('\n')
79
+ .filter(l => l.includes(':'))
80
+ // .map(l => l.match(/\[(.*?)\]/)?.[1] || l) // minitest format
81
+ // .map(l => l.split(':')[0])
82
+ .map(l => l.trim())
83
+ .map(l => l.split(' ').find(p => p.includes(':')) || '')
84
+ .filter(l => isValid(l?.split(':')[0]))
85
+
86
+ // // filter out 3rd party libs
87
+ .filter(l => !l?.includes(`vendor${sep}`))
88
+ .filter(l => !l?.includes(`node_modules${sep}`))
89
+ .filter(l => fs.existsSync(l.split(':')[0]))
90
+ .filter(l => fs.lstatSync(l.split(':')[0]).isFile());
91
+
92
+ if (!stackLines.length) return '';
93
+
94
+ const [file, line] = stackLines[0].split(':');
95
+
96
+ const prepend = 3;
97
+ const source = fetchSourceCode(fs.readFileSync(file).toString(), { line, prepend, limit: 7 });
98
+
99
+ if (!source) return '';
100
+
101
+ return source
102
+ .split('\n')
103
+ .map((l, i) => {
104
+ if (i === prepend) return `${line} > ${chalk.bold(l)}`;
105
+ return `${line - prepend + i} | ${l}`;
167
106
  })
168
- .join('\n');
107
+ .join('\n');
169
108
  };
170
- exports.fetchSourceCodeFromStackTrace = fetchSourceCodeFromStackTrace;
171
- exports.TEST_ID_REGEX = /@T([\w\d]{8})/;
172
- exports.SUITE_ID_REGEX = /@S([\w\d]{8})/;
109
+
110
+ const TEST_ID_REGEX = /@T([\w\d]{8})/;
111
+
173
112
  const fetchIdFromCode = (code, opts = {}) => {
174
- const comments = code
175
- .split('\n')
176
- .map(l => l.trim())
177
- .filter(l => {
178
- switch (opts.lang) {
179
- case 'ruby':
180
- case 'python':
181
- return l.startsWith('# ');
182
- default:
183
- return l.startsWith('// ');
184
- }
113
+ const comments = code
114
+ .split('\n')
115
+ .map(l => l.trim())
116
+ .filter(l => {
117
+ switch (opts.lang) {
118
+ case 'ruby':
119
+ case 'python':
120
+ return l.startsWith('# ');
121
+ default:
122
+ return l.startsWith('// ');
123
+ }
185
124
  });
186
- return comments.find(c => c.match(exports.TEST_ID_REGEX))?.match(exports.TEST_ID_REGEX)?.[1];
125
+
126
+ return comments.find(c => c.match(TEST_ID_REGEX))?.match(TEST_ID_REGEX)?.[1];
187
127
  };
188
- exports.fetchIdFromCode = fetchIdFromCode;
128
+
189
129
  const fetchIdFromOutput = output => {
190
- const TID_FULL_PATTERN = new RegExp(`tid:\\/\\/.*?(${exports.TEST_ID_REGEX.source})`);
191
- return output.match(TID_FULL_PATTERN)?.[2];
130
+ const TID_FULL_PATTERN = new RegExp(`tid:\\/\\/.*?(${TEST_ID_REGEX.source})`);
131
+
132
+ return output.match(TID_FULL_PATTERN)?.[2];
192
133
  };
193
- exports.fetchIdFromOutput = fetchIdFromOutput;
134
+
194
135
  const fetchSourceCode = (contents, opts = {}) => {
195
- if (!opts.title && !opts.line)
196
- return '';
197
- // code fragment is 20 lines
198
- const limit = opts.limit || 50;
199
- let lineIndex;
200
- if (opts.line)
201
- lineIndex = opts.line - 1;
202
- const lines = contents.split('\n');
203
- // remove special chars from title
204
- if (!lineIndex && opts.title) {
205
- const title = opts.title.replace(/[([@].*/g, '');
206
- if (opts.lang === 'java') {
207
- lineIndex = lines.findIndex(l => l.includes(`test${title}`));
208
- if (lineIndex === -1)
209
- lineIndex = lines.findIndex(l => l.includes(`@DisplayName("${title}`));
210
- if (lineIndex === -1)
211
- lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
212
- if (lineIndex === -1)
213
- lineIndex = lines.findIndex(l => l.includes(`${title}(`));
214
- }
215
- else if (opts.lang === 'csharp') {
216
- if (lineIndex === -1)
217
- lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
218
- if (lineIndex === -1)
219
- lineIndex = lines.findIndex(l => l.includes(`${title}(`));
220
- }
221
- else {
222
- lineIndex = lines.findIndex(l => l.includes(title));
223
- }
224
- }
225
- if (opts.prepend) {
226
- lineIndex -= opts.prepend;
136
+ if (!opts.title && !opts.line) return '';
137
+
138
+ // code fragment is 20 lines
139
+ const limit = opts.limit || 50;
140
+ let lineIndex;
141
+ if (opts.line) lineIndex = opts.line - 1;
142
+ const lines = contents.split('\n');
143
+
144
+ // remove special chars from title
145
+ if (!lineIndex && opts.title) {
146
+ const title = opts.title.replace(/[([@].*/g, '');
147
+
148
+ if (opts.lang === 'java') {
149
+ lineIndex = lines.findIndex(l => l.includes(`test${title}`));
150
+ if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`@DisplayName("${title}`));
151
+ if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
152
+ if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`${title}(`));
153
+ } else {
154
+ lineIndex = lines.findIndex(l => l.includes(title));
227
155
  }
228
- if (lineIndex) {
229
- const result = [];
230
- for (let i = lineIndex; i < lineIndex + limit; i++) {
231
- if (lines[i] === undefined)
232
- continue;
233
- if (i > lineIndex + 2 && !opts.prepend) {
234
- // annotation
235
- if (opts.lang === 'php' && lines[i].trim().startsWith('#['))
236
- break;
237
- if (opts.lang === 'php' && lines[i].includes(' private function '))
238
- break;
239
- if (opts.lang === 'php' && lines[i].includes(' protected function '))
240
- break;
241
- if (opts.lang === 'php' && lines[i].includes(' public function '))
242
- break;
243
- if (opts.lang === 'python' && lines[i].trim().match(/^@\w+/))
244
- break;
245
- if (opts.lang === 'python' && lines[i].includes(' def '))
246
- break;
247
- if (opts.lang === 'ruby' && lines[i].includes(' def '))
248
- break;
249
- if (opts.lang === 'ruby' && lines[i].includes(' test '))
250
- break;
251
- if (opts.lang === 'ruby' && lines[i].includes(' it '))
252
- break;
253
- if (opts.lang === 'ruby' && lines[i].includes(' specify '))
254
- break;
255
- if (opts.lang === 'ruby' && lines[i].includes(' context '))
256
- break;
257
- if (opts.lang === 'ts' && lines[i].includes(' it('))
258
- break;
259
- if (opts.lang === 'ts' && lines[i].includes(' test('))
260
- break;
261
- if (opts.lang === 'js' && lines[i].includes(' it('))
262
- break;
263
- if (opts.lang === 'js' && lines[i].includes(' test('))
264
- break;
265
- if (opts.lang === 'java' && lines[i].trim().match(/^@\w+/))
266
- break;
267
- if (opts.lang === 'java' && lines[i].includes(' public void '))
268
- break;
269
- if (opts.lang === 'java' && lines[i].includes(' class '))
270
- break;
271
- }
272
- result.push(lines[i]);
273
- }
274
- return result.join('\n');
156
+ }
157
+
158
+ if (opts.prepend) {
159
+ lineIndex -= opts.prepend;
160
+ }
161
+
162
+ if (lineIndex) {
163
+ const result = [];
164
+ for (let i = lineIndex; i < lineIndex + limit; i++) {
165
+ if (lines[i] === undefined) continue;
166
+
167
+ if (i > lineIndex + 2 && !opts.prepend) {
168
+ // annotation
169
+ if (opts.lang === 'php' && lines[i].trim().startsWith('#[')) break;
170
+ if (opts.lang === 'php' && lines[i].includes(' private function ')) break;
171
+ if (opts.lang === 'php' && lines[i].includes(' protected function ')) break;
172
+ if (opts.lang === 'php' && lines[i].includes(' public function ')) break;
173
+ if (opts.lang === 'python' && lines[i].trim().match(/^@\w+/)) break;
174
+ if (opts.lang === 'python' && lines[i].includes(' def ')) break;
175
+ if (opts.lang === 'ruby' && lines[i].includes(' def ')) break;
176
+ if (opts.lang === 'ruby' && lines[i].includes(' test ')) break;
177
+ if (opts.lang === 'ruby' && lines[i].includes(' it ')) break;
178
+ if (opts.lang === 'ruby' && lines[i].includes(' specify ')) break;
179
+ if (opts.lang === 'ruby' && lines[i].includes(' context ')) break;
180
+ if (opts.lang === 'ts' && lines[i].includes(' it(')) break;
181
+ if (opts.lang === 'ts' && lines[i].includes(' test(')) break;
182
+ if (opts.lang === 'js' && lines[i].includes(' it(')) break;
183
+ if (opts.lang === 'js' && lines[i].includes(' test(')) break;
184
+ if (opts.lang === 'java' && lines[i].trim().match(/^@\w+/)) break;
185
+ if (opts.lang === 'java' && lines[i].includes(' public void ')) break;
186
+ if (opts.lang === 'java' && lines[i].includes(' class ')) break;
187
+ }
188
+ result.push(lines[i]);
275
189
  }
190
+ return result.join('\n');
191
+ }
276
192
  };
277
- exports.fetchSourceCode = fetchSourceCode;
278
- const isSameTest = (test, t) => typeof t === 'object' &&
279
- typeof test === 'object' &&
280
- t.title === test.title &&
281
- t.suite_title === test.suite_title &&
282
- Object.values(t.example || {}) === Object.values(test.example || {}) &&
283
- t.test_id === test.test_id;
284
- exports.isSameTest = isSameTest;
193
+
194
+ const isSameTest = (test, t) =>
195
+ typeof t === 'object' &&
196
+ typeof test === 'object' &&
197
+ t.title === test.title &&
198
+ t.suite_title === test.suite_title &&
199
+ Object.values(t.example || {}) === Object.values(test.example || {}) &&
200
+ t.test_id === test.test_id;
201
+
285
202
  const getCurrentDateTime = () => {
286
- const today = new Date();
287
- return `${today.getFullYear()}_${today.getMonth() + 1}_${today.getDate()}_${today.getHours()}_${today.getMinutes()}_${today.getSeconds()}`;
203
+ const today = new Date();
204
+
205
+ return `${today.getFullYear()}_${
206
+ today.getMonth() + 1
207
+ }_${today.getDate()}_${today.getHours()}_${today.getMinutes()}_${today.getSeconds()}`;
288
208
  };
289
- exports.getCurrentDateTime = getCurrentDateTime;
209
+
290
210
  /**
291
211
  * @param {Object} test - Test adapter object
292
212
  *
293
213
  * @returns {String|null} testInfo as one string
294
214
  */
295
215
  const specificTestInfo = test => {
296
- // TODO: afterEach has another context.... need to add specific handler, maybe...
297
- if (test?.title && test?.file) {
298
- return `${(0, path_1.basename)(test.file).split('.').join('#')}#${test.title.split(' ').join('#')}`;
299
- }
300
- return null;
216
+ // TODO: afterEach has another context.... need to add specific handler, maybe...
217
+ if (test?.title && test?.file) {
218
+ return `${basename(test.file).split('.').join('#')}#${test.title.split(' ').join('#')}`;
219
+ }
220
+
221
+ return null;
301
222
  };
302
- exports.specificTestInfo = specificTestInfo;
223
+
303
224
  const fileSystem = {
304
- createDir(dirPath) {
305
- if (!fs_1.default.existsSync(dirPath)) {
306
- fs_1.default.mkdirSync(dirPath, { recursive: true });
307
- debug('Created dir: ', dirPath);
308
- }
309
- },
310
- clearDir(dirPath) {
311
- if (fs_1.default.existsSync(dirPath)) {
312
- fs_1.default.rmSync(dirPath, { recursive: true });
313
- debug(`Dir ${dirPath} was deleted`);
314
- }
315
- else {
316
- debug(`Trying to delete ${dirPath} but it doesn't exist`);
317
- }
318
- },
225
+ createDir(dirPath) {
226
+ if (!fs.existsSync(dirPath)) {
227
+ fs.mkdirSync(dirPath, { recursive: true });
228
+ debug('Created dir: ', dirPath);
229
+ }
230
+ },
231
+ clearDir(dirPath) {
232
+ if (fs.existsSync(dirPath)) {
233
+ fs.rmSync(dirPath, { recursive: true });
234
+ debug(`Dir ${dirPath} was deleted`);
235
+ } else {
236
+ debug(`Trying to delete ${dirPath} but it doesn't exist`);
237
+ }
238
+ },
319
239
  };
320
- exports.fileSystem = fileSystem;
240
+
321
241
  const foundedTestLog = (app, tests) => {
322
- const n = tests.length;
323
- return n === 1 ? console.log(app, `✅ We found one test!`) : console.log(app, `✅ We found ${n} tests!`);
242
+ const n = tests.length;
243
+
244
+ return n === 1 ? console.log(app, `✅ We found one test!`) : console.log(app, `✅ We found ${n} tests!`);
324
245
  };
325
- exports.foundedTestLog = foundedTestLog;
246
+
326
247
  const humanize = text => {
327
- // if there are no spaces, decamelize
328
- if (!text.trim().includes(' '))
329
- text = decamelize(text);
330
- return text
331
- .replace(/_./g, match => ` ${match.charAt(1).toUpperCase()}`)
332
- .trim()
333
- .replace(/^(.)|\s(.)/g, $1 => $1.toUpperCase())
334
- .trim()
335
- .replace(/\sA\s/g, ' a ') // replace a|the
336
- .replace(/\sThe\s/g, ' the ') // replace a|the
337
- .replace(/^Test\s/, '')
338
- .replace(/^Should\s/, '');
248
+ // if there are no spaces, decamelize
249
+ if (!text.trim().includes(' ')) text = decamelize(text);
250
+
251
+ return text
252
+ .replace(/_./g, match => ` ${match.charAt(1).toUpperCase()}`)
253
+ .trim()
254
+ .replace(/^(.)|\s(.)/g, $1 => $1.toUpperCase())
255
+ .trim()
256
+ .replace(/\sA\s/g, ' a ') // replace a|the
257
+ .replace(/\sThe\s/g, ' the ') // replace a|the
258
+ .replace(/^Test\s/, '')
259
+ .replace(/^Should\s/, '');
339
260
  };
340
- exports.humanize = humanize;
261
+
341
262
  /**
342
263
  * From https://github.com/sindresorhus/decamelize/blob/main/index.js
343
264
  * @param {*} text
344
265
  * @returns
345
266
  */
346
267
  const decamelize = text => {
347
- const separator = '_';
348
- const replacement = `$1${separator}$2`;
349
- // Split lowercase sequences followed by uppercase character.
350
- // `dataForUSACounties` `data_For_USACounties`
351
- // `myURLstring → `my_URLstring`
352
- let decamelized = text.replace(/([\p{Lowercase_Letter}\d])(\p{Uppercase_Letter})/gu, replacement);
353
- // Lowercase all single uppercase characters. As we
354
- // want to preserve uppercase sequences, we cannot
355
- // simply lowercase the separated string at the end.
356
- // `data_For_USACounties` `data_for_USACounties`
357
- decamelized = decamelized.replace(/((?<![\p{Uppercase_Letter}\d])[\p{Uppercase_Letter}\d](?![\p{Uppercase_Letter}\d]))/gu, $0 => $0.toLowerCase());
358
- // Remaining uppercase sequences will be separated from lowercase sequences.
359
- // `data_For_USACounties` → `data_for_USA_counties`
360
- return decamelized.replace(/(\p{Uppercase_Letter}+)(\p{Uppercase_Letter}\p{Lowercase_Letter}+)/gu, (_, $1, $2) => $1 + separator + $2.toLowerCase());
268
+ const separator = '_';
269
+ const replacement = `$1${separator}$2`;
270
+
271
+ // Split lowercase sequences followed by uppercase character.
272
+ // `dataForUSACounties` → `data_For_USACounties`
273
+ // `myURLstring `my_URLstring`
274
+ let decamelized = text.replace(/([\p{Lowercase_Letter}\d])(\p{Uppercase_Letter})/gu, replacement);
275
+
276
+ // Lowercase all single uppercase characters. As we
277
+ // want to preserve uppercase sequences, we cannot
278
+ // simply lowercase the separated string at the end.
279
+ // `data_For_USACounties` `data_for_USACounties`
280
+ decamelized = decamelized.replace(
281
+ /((?<![\p{Uppercase_Letter}\d])[\p{Uppercase_Letter}\d](?![\p{Uppercase_Letter}\d]))/gu,
282
+ $0 => $0.toLowerCase(),
283
+ );
284
+
285
+ // Remaining uppercase sequences will be separated from lowercase sequences.
286
+ // `data_For_USACounties` → `data_for_USA_counties`
287
+ return decamelized.replace(
288
+ /(\p{Uppercase_Letter}+)(\p{Uppercase_Letter}\p{Lowercase_Letter}+)/gu,
289
+ (_, $1, $2) => $1 + separator + $2.toLowerCase(),
290
+ );
361
291
  };
292
+
362
293
  /**
363
294
  * Used to remove color codes
364
295
  * @param {*} input
365
296
  * @returns
366
297
  */
367
298
  function removeColorCodes(input) {
368
- return input.replace(/\x1b\[[0-9;]*m/g, '');
299
+ // eslint-disable-next-line no-control-regex
300
+ return input.replace(/\x1b\[[0-9;]*m/g, '');
369
301
  }
302
+
370
303
  const testRunnerHelper = {
371
- // for Jest
372
- getNameOfCurrentlyRunningTest: () => {
373
- if (global.testomatioTestTitle)
374
- return global.testomatioTestTitle;
375
- if (!process.env.JEST_WORKER_ID)
376
- return null;
377
- try {
378
- // TODO: expect?.getState()?.testPath + ' ' + expect?.getState()?.currentTestName
379
- // @ts-expect-error "expect" could only be defined inside Jest environement (forbidden to import it outside)
380
- return expect?.getState()?.currentTestName;
381
- }
382
- catch (e) {
383
- return null;
384
- }
385
- },
386
- };
387
- exports.testRunnerHelper = testRunnerHelper;
388
- function storeRunId(runId) {
389
- if (!runId || runId === 'undefined')
390
- return;
391
- const filePath = path_1.default.join(os_1.default.tmpdir(), `testomatio.latest.run`);
392
- fs_1.default.writeFileSync(filePath, runId);
393
- }
394
- function readLatestRunId() {
304
+ // for Jest
305
+ getNameOfCurrentlyRunningTest: () => {
306
+ if (global.testomatioTestTitle) return global.testomatioTestTitle;
307
+
308
+ if (!process.env.JEST_WORKER_ID) return null;
395
309
  try {
396
- const filePath = path_1.default.join(os_1.default.tmpdir(), `testomatio.latest.run`);
397
- const stats = fs_1.default.statSync(filePath);
398
- const diff = +new Date() - +stats.mtime;
399
- const diffHours = diff / 1000 / 60 / 60;
400
- if (diffHours > 1)
401
- return;
402
- return fs_1.default.readFileSync(filePath)?.toString()?.trim();
403
- }
404
- catch (e) {
405
- return null;
406
- }
407
- }
408
- function formatStep(step, shift = 0) {
409
- const prefix = ' '.repeat(shift);
410
- const lines = [];
411
- if (step.error) {
412
- lines.push(`${prefix}${picocolors_1.default.red(step.title)} ${picocolors_1.default.gray(`${step.duration}ms`)}`);
413
- }
414
- else {
415
- lines.push(`${prefix}${step.title} ${picocolors_1.default.gray(`${step.duration}ms`)}`);
310
+ // TODO: expect?.getState()?.testPath + ' ' + expect?.getState()?.currentTestName
311
+ // @ts-expect-error "expect" could only be defined inside Jest environement (forbidden to import it outside)
312
+ // eslint-disable-next-line no-undef
313
+ return expect?.getState()?.currentTestName;
314
+ } catch (e) {
315
+ return null;
416
316
  }
417
- for (const child of step.steps || []) {
418
- lines.push(...formatStep(child, shift + 2));
419
- }
420
- return lines;
421
- }
422
- function getPackageVersion() {
423
- const packageJsonPath = path_1.default.resolve(__dirname, '../../package.json');
424
- const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf8'));
425
- return packageJson.version;
426
- }
427
-
428
- module.exports.getPackageVersion = getPackageVersion;
429
-
430
- module.exports.formatStep = formatStep;
431
-
432
- module.exports.readLatestRunId = readLatestRunId;
433
-
434
- module.exports.removeColorCodes = removeColorCodes;
435
-
436
- module.exports.storeRunId = storeRunId;
437
-
438
- module.exports.getTestomatIdFromTestTitle = getTestomatIdFromTestTitle;
439
-
440
- module.exports.parseSuite = parseSuite;
441
-
442
- module.exports.validateSuiteId = validateSuiteId;
443
-
444
- module.exports.ansiRegExp = ansiRegExp;
445
-
446
- module.exports.isValidUrl = isValidUrl;
447
-
448
- module.exports.fetchFilesFromStackTrace = fetchFilesFromStackTrace;
449
-
450
- module.exports.fetchSourceCodeFromStackTrace = fetchSourceCodeFromStackTrace;
451
-
452
- module.exports.fetchIdFromCode = fetchIdFromCode;
317
+ },
318
+ };
453
319
 
454
- module.exports.fetchIdFromOutput = fetchIdFromOutput;
320
+ function storeRunId(runId) {
321
+ if (!runId || runId === 'undefined') return;
322
+ const filePath = path.join(os.tmpdir(), `testomatio.latest.run`);
323
+ fs.writeFileSync(filePath, runId);
324
+ }
455
325
 
456
- module.exports.fetchSourceCode = fetchSourceCode;
326
+ function readLatestRunId() {
327
+ try {
328
+ const filePath = path.join(os.tmpdir(), `testomatio.latest.run`);
329
+ const stats = fs.statSync(filePath);
330
+ const diff = +new Date() - +stats.mtime;
331
+ const diffHours = diff / 1000 / 60 / 60;
332
+ if (diffHours > 1) return;
457
333
 
458
- module.exports.isSameTest = isSameTest;
334
+ return fs.readFileSync(filePath)?.toString()?.trim();
335
+ } catch (e) {
336
+ return null;
337
+ }
338
+ }
459
339
 
460
- module.exports.getCurrentDateTime = getCurrentDateTime;
340
+ function formatStep(step, shift = 0) {
341
+ const prefix = ' '.repeat(shift);
461
342
 
462
- module.exports.specificTestInfo = specificTestInfo;
343
+ const lines = [];
463
344
 
464
- module.exports.fileSystem = fileSystem;
345
+ if (step.error) {
346
+ lines.push(`${prefix}${chalk.red(step.title)} ${chalk.gray(`${step.duration}ms`)}`);
347
+ } else {
348
+ lines.push(`${prefix}${step.title} ${chalk.gray(`${step.duration}ms`)}`);
349
+ }
465
350
 
466
- module.exports.foundedTestLog = foundedTestLog;
351
+ for (const child of step.steps || []) {
352
+ lines.push(...formatStep(child, shift + 2));
353
+ }
467
354
 
468
- module.exports.humanize = humanize;
355
+ return lines;
356
+ }
469
357
 
470
- module.exports.testRunnerHelper = testRunnerHelper;
358
+ module.exports = {
359
+ storeRunId,
360
+ readLatestRunId,
361
+ isSameTest,
362
+ fetchSourceCode,
363
+ fetchSourceCodeFromStackTrace,
364
+ fetchIdFromCode,
365
+ fetchIdFromOutput,
366
+ fetchFilesFromStackTrace,
367
+ fileSystem,
368
+ formatStep,
369
+ getCurrentDateTime,
370
+ specificTestInfo,
371
+ isValidUrl,
372
+ ansiRegExp,
373
+ getTestomatIdFromTestTitle,
374
+ parseSuite,
375
+ humanize,
376
+ removeColorCodes,
377
+ foundedTestLog,
378
+ testRunnerHelper,
379
+ };