1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, '__esModule', {
|
4 | value: true
|
5 | });
|
6 | exports.separateMessageFromStack =
|
7 | exports.formatResultsErrors =
|
8 | exports.formatStackTrace =
|
9 | exports.getTopFrame =
|
10 | exports.getStackTraceLines =
|
11 | exports.formatExecError =
|
12 | void 0;
|
13 |
|
14 | var path = _interopRequireWildcard(require('path'));
|
15 |
|
16 | var _codeFrame = require('@babel/code-frame');
|
17 |
|
18 | var _chalk = _interopRequireDefault(require('chalk'));
|
19 |
|
20 | var fs = _interopRequireWildcard(require('graceful-fs'));
|
21 |
|
22 | var _micromatch = _interopRequireDefault(require('micromatch'));
|
23 |
|
24 | var _slash = _interopRequireDefault(require('slash'));
|
25 |
|
26 | var _stackUtils = _interopRequireDefault(require('stack-utils'));
|
27 |
|
28 | var _prettyFormat = require('pretty-format');
|
29 |
|
30 | function _interopRequireDefault(obj) {
|
31 | return obj && obj.__esModule ? obj : {default: obj};
|
32 | }
|
33 |
|
34 | function _getRequireWildcardCache(nodeInterop) {
|
35 | if (typeof WeakMap !== 'function') return null;
|
36 | var cacheBabelInterop = new WeakMap();
|
37 | var cacheNodeInterop = new WeakMap();
|
38 | return (_getRequireWildcardCache = function (nodeInterop) {
|
39 | return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
40 | })(nodeInterop);
|
41 | }
|
42 |
|
43 | function _interopRequireWildcard(obj, nodeInterop) {
|
44 | if (!nodeInterop && obj && obj.__esModule) {
|
45 | return obj;
|
46 | }
|
47 | if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
48 | return {default: obj};
|
49 | }
|
50 | var cache = _getRequireWildcardCache(nodeInterop);
|
51 | if (cache && cache.has(obj)) {
|
52 | return cache.get(obj);
|
53 | }
|
54 | var newObj = {};
|
55 | var hasPropertyDescriptor =
|
56 | Object.defineProperty && Object.getOwnPropertyDescriptor;
|
57 | for (var key in obj) {
|
58 | if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
|
59 | var desc = hasPropertyDescriptor
|
60 | ? Object.getOwnPropertyDescriptor(obj, key)
|
61 | : null;
|
62 | if (desc && (desc.get || desc.set)) {
|
63 | Object.defineProperty(newObj, key, desc);
|
64 | } else {
|
65 | newObj[key] = obj[key];
|
66 | }
|
67 | }
|
68 | }
|
69 | newObj.default = obj;
|
70 | if (cache) {
|
71 | cache.set(obj, newObj);
|
72 | }
|
73 | return newObj;
|
74 | }
|
75 |
|
76 | var global = (function () {
|
77 | if (typeof globalThis !== 'undefined') {
|
78 | return globalThis;
|
79 | } else if (typeof global !== 'undefined') {
|
80 | return global;
|
81 | } else if (typeof self !== 'undefined') {
|
82 | return self;
|
83 | } else if (typeof window !== 'undefined') {
|
84 | return window;
|
85 | } else {
|
86 | return Function('return this')();
|
87 | }
|
88 | })();
|
89 |
|
90 | var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
|
91 |
|
92 | var global = (function () {
|
93 | if (typeof globalThis !== 'undefined') {
|
94 | return globalThis;
|
95 | } else if (typeof global !== 'undefined') {
|
96 | return global;
|
97 | } else if (typeof self !== 'undefined') {
|
98 | return self;
|
99 | } else if (typeof window !== 'undefined') {
|
100 | return window;
|
101 | } else {
|
102 | return Function('return this')();
|
103 | }
|
104 | })();
|
105 |
|
106 | var Symbol = global['jest-symbol-do-not-touch'] || global.Symbol;
|
107 |
|
108 | var global = (function () {
|
109 | if (typeof globalThis !== 'undefined') {
|
110 | return globalThis;
|
111 | } else if (typeof global !== 'undefined') {
|
112 | return global;
|
113 | } else if (typeof self !== 'undefined') {
|
114 | return self;
|
115 | } else if (typeof window !== 'undefined') {
|
116 | return window;
|
117 | } else {
|
118 | return Function('return this')();
|
119 | }
|
120 | })();
|
121 |
|
122 | var jestReadFile =
|
123 | global[Symbol.for('jest-native-read-file')] || fs.readFileSync;
|
124 |
|
125 | const stackUtils = new _stackUtils.default({
|
126 | cwd: 'something which does not exist'
|
127 | });
|
128 | let nodeInternals = [];
|
129 |
|
130 | try {
|
131 | nodeInternals = _stackUtils.default.nodeInternals();
|
132 | } catch {
|
133 |
|
134 |
|
135 | }
|
136 |
|
137 | const PATH_NODE_MODULES = `${path.sep}node_modules${path.sep}`;
|
138 | const PATH_JEST_PACKAGES = `${path.sep}jest${path.sep}packages${path.sep}`;
|
139 |
|
140 | const JASMINE_IGNORE =
|
141 | /^\s+at(?:(?:.jasmine\-)|\s+jasmine\.buildExpectationResult)/;
|
142 | const JEST_INTERNALS_IGNORE =
|
143 | /^\s+at.*?jest(-.*?)?(\/|\\)(build|node_modules|packages)(\/|\\)/;
|
144 | const ANONYMOUS_FN_IGNORE = /^\s+at <anonymous>.*$/;
|
145 | const ANONYMOUS_PROMISE_IGNORE = /^\s+at (new )?Promise \(<anonymous>\).*$/;
|
146 | const ANONYMOUS_GENERATOR_IGNORE = /^\s+at Generator.next \(<anonymous>\).*$/;
|
147 | const NATIVE_NEXT_IGNORE = /^\s+at next \(native\).*$/;
|
148 | const TITLE_INDENT = ' ';
|
149 | const MESSAGE_INDENT = ' ';
|
150 | const STACK_INDENT = ' ';
|
151 | const ANCESTRY_SEPARATOR = ' \u203A ';
|
152 |
|
153 | const TITLE_BULLET = _chalk.default.bold('\u25cf ');
|
154 |
|
155 | const STACK_TRACE_COLOR = _chalk.default.dim;
|
156 | const STACK_PATH_REGEXP = /\s*at.*\(?(\:\d*\:\d*|native)\)?/;
|
157 | const EXEC_ERROR_MESSAGE = 'Test suite failed to run';
|
158 | const NOT_EMPTY_LINE_REGEXP = /^(?!$)/gm;
|
159 |
|
160 | const indentAllLines = (lines, indent) =>
|
161 | lines.replace(NOT_EMPTY_LINE_REGEXP, indent);
|
162 |
|
163 | const trim = string => (string || '').trim();
|
164 |
|
165 |
|
166 |
|
167 |
|
168 | const trimPaths = string =>
|
169 | string.match(STACK_PATH_REGEXP) ? trim(string) : string;
|
170 |
|
171 | const getRenderedCallsite = (fileContent, line, column) => {
|
172 | let renderedCallsite = (0, _codeFrame.codeFrameColumns)(
|
173 | fileContent,
|
174 | {
|
175 | start: {
|
176 | column,
|
177 | line
|
178 | }
|
179 | },
|
180 | {
|
181 | highlightCode: true
|
182 | }
|
183 | );
|
184 | renderedCallsite = indentAllLines(renderedCallsite, MESSAGE_INDENT);
|
185 | renderedCallsite = `\n${renderedCallsite}\n`;
|
186 | return renderedCallsite;
|
187 | };
|
188 |
|
189 | const blankStringRegexp = /^\s*$/;
|
190 |
|
191 | function checkForCommonEnvironmentErrors(error) {
|
192 | if (
|
193 | error.includes('ReferenceError: document is not defined') ||
|
194 | error.includes('ReferenceError: window is not defined') ||
|
195 | error.includes('ReferenceError: navigator is not defined')
|
196 | ) {
|
197 | return warnAboutWrongTestEnvironment(error, 'jsdom');
|
198 | } else if (error.includes('.unref is not a function')) {
|
199 | return warnAboutWrongTestEnvironment(error, 'node');
|
200 | }
|
201 |
|
202 | return error;
|
203 | }
|
204 |
|
205 | function warnAboutWrongTestEnvironment(error, env) {
|
206 | return (
|
207 | _chalk.default.bold.red(
|
208 | `The error below may be caused by using the wrong test environment, see ${_chalk.default.dim.underline(
|
209 | 'https://jestjs.io/docs/configuration#testenvironment-string'
|
210 | )}.\nConsider using the "${env}" test environment.\n\n`
|
211 | ) + error
|
212 | );
|
213 | }
|
214 |
|
215 |
|
216 |
|
217 | const formatExecError = (error, config, options, testPath, reuseMessage) => {
|
218 | if (!error || typeof error === 'number') {
|
219 | error = new Error(`Expected an Error, but "${String(error)}" was thrown`);
|
220 | error.stack = '';
|
221 | }
|
222 |
|
223 | let message, stack;
|
224 |
|
225 | if (typeof error === 'string' || !error) {
|
226 | error || (error = 'EMPTY ERROR');
|
227 | message = '';
|
228 | stack = error;
|
229 | } else {
|
230 | message = error.message;
|
231 | stack =
|
232 | typeof error.stack === 'string'
|
233 | ? error.stack
|
234 | : `thrown: ${(0, _prettyFormat.format)(error, {
|
235 | maxDepth: 3
|
236 | })}`;
|
237 | }
|
238 |
|
239 | const separated = separateMessageFromStack(stack || '');
|
240 | stack = separated.stack;
|
241 |
|
242 | if (separated.message.includes(trim(message))) {
|
243 |
|
244 | message = separated.message;
|
245 | }
|
246 |
|
247 | message = checkForCommonEnvironmentErrors(message);
|
248 | message = indentAllLines(message, MESSAGE_INDENT);
|
249 | stack =
|
250 | stack && !options.noStackTrace
|
251 | ? '\n' + formatStackTrace(stack, config, options, testPath)
|
252 | : '';
|
253 |
|
254 | if (
|
255 | typeof stack !== 'string' ||
|
256 | (blankStringRegexp.test(message) && blankStringRegexp.test(stack))
|
257 | ) {
|
258 |
|
259 | message = `thrown: ${(0, _prettyFormat.format)(error, {
|
260 | maxDepth: 3
|
261 | })}`;
|
262 | }
|
263 |
|
264 | let messageToUse;
|
265 |
|
266 | if (reuseMessage) {
|
267 | messageToUse = ` ${message.trim()}`;
|
268 | } else {
|
269 | messageToUse = `${EXEC_ERROR_MESSAGE}\n\n${message}`;
|
270 | }
|
271 |
|
272 | return TITLE_INDENT + TITLE_BULLET + messageToUse + stack + '\n';
|
273 | };
|
274 |
|
275 | exports.formatExecError = formatExecError;
|
276 |
|
277 | const removeInternalStackEntries = (lines, options) => {
|
278 | let pathCounter = 0;
|
279 | return lines.filter(line => {
|
280 | if (ANONYMOUS_FN_IGNORE.test(line)) {
|
281 | return false;
|
282 | }
|
283 |
|
284 | if (ANONYMOUS_PROMISE_IGNORE.test(line)) {
|
285 | return false;
|
286 | }
|
287 |
|
288 | if (ANONYMOUS_GENERATOR_IGNORE.test(line)) {
|
289 | return false;
|
290 | }
|
291 |
|
292 | if (NATIVE_NEXT_IGNORE.test(line)) {
|
293 | return false;
|
294 | }
|
295 |
|
296 | if (nodeInternals.some(internal => internal.test(line))) {
|
297 | return false;
|
298 | }
|
299 |
|
300 | if (!STACK_PATH_REGEXP.test(line)) {
|
301 | return true;
|
302 | }
|
303 |
|
304 | if (JASMINE_IGNORE.test(line)) {
|
305 | return false;
|
306 | }
|
307 |
|
308 | if (++pathCounter === 1) {
|
309 | return true;
|
310 | }
|
311 |
|
312 | if (options.noStackTrace) {
|
313 | return false;
|
314 | }
|
315 |
|
316 | if (JEST_INTERNALS_IGNORE.test(line)) {
|
317 | return false;
|
318 | }
|
319 |
|
320 | return true;
|
321 | });
|
322 | };
|
323 |
|
324 | const formatPaths = (config, relativeTestPath, line) => {
|
325 |
|
326 | const match = line.match(/(^\s*at .*?\(?)([^()]+)(:[0-9]+:[0-9]+\)?.*$)/);
|
327 |
|
328 | if (!match) {
|
329 | return line;
|
330 | }
|
331 |
|
332 | let filePath = (0, _slash.default)(path.relative(config.rootDir, match[2]));
|
333 |
|
334 | if (
|
335 | (config.testMatch &&
|
336 | config.testMatch.length &&
|
337 | (0, _micromatch.default)([filePath], config.testMatch).length > 0) ||
|
338 | filePath === relativeTestPath
|
339 | ) {
|
340 | filePath = _chalk.default.reset.cyan(filePath);
|
341 | }
|
342 |
|
343 | return STACK_TRACE_COLOR(match[1]) + filePath + STACK_TRACE_COLOR(match[3]);
|
344 | };
|
345 |
|
346 | const getStackTraceLines = (
|
347 | stack,
|
348 | options = {
|
349 | noCodeFrame: false,
|
350 | noStackTrace: false
|
351 | }
|
352 | ) => removeInternalStackEntries(stack.split(/\n/), options);
|
353 |
|
354 | exports.getStackTraceLines = getStackTraceLines;
|
355 |
|
356 | const getTopFrame = lines => {
|
357 | for (const line of lines) {
|
358 | if (line.includes(PATH_NODE_MODULES) || line.includes(PATH_JEST_PACKAGES)) {
|
359 | continue;
|
360 | }
|
361 |
|
362 | const parsedFrame = stackUtils.parseLine(line.trim());
|
363 |
|
364 | if (parsedFrame && parsedFrame.file) {
|
365 | return parsedFrame;
|
366 | }
|
367 | }
|
368 |
|
369 | return null;
|
370 | };
|
371 |
|
372 | exports.getTopFrame = getTopFrame;
|
373 |
|
374 | const formatStackTrace = (stack, config, options, testPath) => {
|
375 | const lines = getStackTraceLines(stack, options);
|
376 | let renderedCallsite = '';
|
377 | const relativeTestPath = testPath
|
378 | ? (0, _slash.default)(path.relative(config.rootDir, testPath))
|
379 | : null;
|
380 |
|
381 | if (!options.noStackTrace && !options.noCodeFrame) {
|
382 | const topFrame = getTopFrame(lines);
|
383 |
|
384 | if (topFrame) {
|
385 | const {column, file: filename, line} = topFrame;
|
386 |
|
387 | if (line && filename && path.isAbsolute(filename)) {
|
388 | let fileContent;
|
389 |
|
390 | try {
|
391 |
|
392 |
|
393 | fileContent = jestReadFile(filename, 'utf8');
|
394 | renderedCallsite = getRenderedCallsite(fileContent, line, column);
|
395 | } catch {
|
396 |
|
397 | }
|
398 | }
|
399 | }
|
400 | }
|
401 |
|
402 | const stacktrace = lines
|
403 | .filter(Boolean)
|
404 | .map(
|
405 | line =>
|
406 | STACK_INDENT + formatPaths(config, relativeTestPath, trimPaths(line))
|
407 | )
|
408 | .join('\n');
|
409 | return renderedCallsite
|
410 | ? `${renderedCallsite}\n${stacktrace}`
|
411 | : `\n${stacktrace}`;
|
412 | };
|
413 |
|
414 | exports.formatStackTrace = formatStackTrace;
|
415 |
|
416 | const formatResultsErrors = (testResults, config, options, testPath) => {
|
417 | const failedResults = testResults.reduce((errors, result) => {
|
418 | result.failureMessages.forEach(item => {
|
419 | errors.push({
|
420 | content: checkForCommonEnvironmentErrors(item),
|
421 | result
|
422 | });
|
423 | });
|
424 | return errors;
|
425 | }, []);
|
426 |
|
427 | if (!failedResults.length) {
|
428 | return null;
|
429 | }
|
430 |
|
431 | return failedResults
|
432 | .map(({result, content}) => {
|
433 | let {message, stack} = separateMessageFromStack(content);
|
434 | stack = options.noStackTrace
|
435 | ? ''
|
436 | : STACK_TRACE_COLOR(
|
437 | formatStackTrace(stack, config, options, testPath)
|
438 | ) + '\n';
|
439 | message = indentAllLines(message, MESSAGE_INDENT);
|
440 | const title =
|
441 | _chalk.default.bold.red(
|
442 | TITLE_INDENT +
|
443 | TITLE_BULLET +
|
444 | result.ancestorTitles.join(ANCESTRY_SEPARATOR) +
|
445 | (result.ancestorTitles.length ? ANCESTRY_SEPARATOR : '') +
|
446 | result.title
|
447 | ) + '\n';
|
448 | return title + '\n' + message + '\n' + stack;
|
449 | })
|
450 | .join('\n');
|
451 | };
|
452 |
|
453 | exports.formatResultsErrors = formatResultsErrors;
|
454 | const errorRegexp = /^Error:?\s*$/;
|
455 |
|
456 | const removeBlankErrorLine = str =>
|
457 | str
|
458 | .split('\n')
|
459 | .filter(line => !errorRegexp.test(line))
|
460 | .join('\n')
|
461 | .trimRight();
|
462 |
|
463 |
|
464 |
|
465 | const separateMessageFromStack = content => {
|
466 | if (!content) {
|
467 | return {
|
468 | message: '',
|
469 | stack: ''
|
470 | };
|
471 | }
|
472 |
|
473 |
|
474 |
|
475 |
|
476 | const messageMatch = content.match(
|
477 | /^(?:Error: )?([\s\S]*?(?=\n\s*at\s.*:\d*:\d*)|\s*.*)([\s\S]*)$/
|
478 | );
|
479 |
|
480 | if (!messageMatch) {
|
481 |
|
482 | throw new Error('If you hit this error, the regex above is buggy.');
|
483 | }
|
484 |
|
485 | const message = removeBlankErrorLine(messageMatch[1]);
|
486 | const stack = removeBlankErrorLine(messageMatch[2]);
|
487 | return {
|
488 | message,
|
489 | stack
|
490 | };
|
491 | };
|
492 |
|
493 | exports.separateMessageFromStack = separateMessageFromStack;
|