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