diff --git a/CHANGELOG.md b/CHANGELOG.md index 2822ebb21d9d..a0607a004208 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,14 @@ ## master -### features +### Features * `[jest-mock]` Add util methods to create async functions. ([#5318](https://github.com/facebook/jest/pull/5318)) ### Fixes +* `[jest-message-util]` Prevent an `ENOENT` crash when the test file contained a + malformed source-map. ([#5405](https://github.com/facebook/jest/pull/5405)). * `[jest]` Add `import-local` to `jest` package. ([#5353](https://github.com/facebook/jest/pull/5353)) * `[expect]` Support class instances in `.toHaveProperty()` matcher. diff --git a/integration-tests/__tests__/bad_source_map.test.js b/integration-tests/__tests__/bad_source_map.test.js new file mode 100644 index 000000000000..f2ac3a4050c0 --- /dev/null +++ b/integration-tests/__tests__/bad_source_map.test.js @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ +'use strict'; + +const runJest = require('../runJest'); + +test('suite with test cases that contain malformed sourcemaps', () => { + const result = runJest('bad-source-map'); + expect(result.stderr).not.toMatch('ENOENT'); +}); diff --git a/integration-tests/bad-source-map/__tests__/bad-source-map.js b/integration-tests/bad-source-map/__tests__/bad-source-map.js new file mode 100644 index 000000000000..db9e5136a166 --- /dev/null +++ b/integration-tests/bad-source-map/__tests__/bad-source-map.js @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ +'use strict'; + +it('should fail with a proper stacktrace', () => { + expect(true).toBe(false); +}); + +//# sourceMappingURL=bad-source-map.js.map diff --git a/integration-tests/bad-source-map/__tests__/bad-source-map.js.map b/integration-tests/bad-source-map/__tests__/bad-source-map.js.map new file mode 100644 index 000000000000..6d7809e16409 --- /dev/null +++ b/integration-tests/bad-source-map/__tests__/bad-source-map.js.map @@ -0,0 +1 @@ +{"version":3,"file":"bad-source-map.js","sources":["dummy:///./index.js"],"sourcesContent":[""],"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACzEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACRA;;;;;;;;;;;;;;;;A","sourceRoot":""} diff --git a/integration-tests/bad-source-map/package.json b/integration-tests/bad-source-map/package.json new file mode 100644 index 000000000000..148788b25446 --- /dev/null +++ b/integration-tests/bad-source-map/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "testEnvironment": "node" + } +} diff --git a/packages/jest-message-util/src/index.js b/packages/jest-message-util/src/index.js index ec9461dff078..0f93bd54408d 100644 --- a/packages/jest-message-util/src/index.js +++ b/packages/jest-message-util/src/index.js @@ -70,6 +70,22 @@ const trim = string => (string || '').replace(/^\s+/, '').replace(/\s+$/, ''); const trimPaths = string => string.match(STACK_PATH_REGEXP) ? trim(string) : string; +const getRenderedCallsite = (fileContent: string, line: number) => { + let renderedCallsite = codeFrameColumns( + fileContent, + {start: {line}}, + {highlightCode: true}, + ); + + renderedCallsite = renderedCallsite + .split('\n') + .map(line => MESSAGE_INDENT + line) + .join('\n'); + + renderedCallsite = `\n${renderedCallsite}\n`; + return renderedCallsite; +}; + // ExecError is an error thrown outside of the test suite (not inside an `it` or // `before/after each` hooks). If it's thrown, none of the tests in the file // are executed. @@ -228,20 +244,15 @@ export const formatStackTrace = ( const filename = topFrame.file; if (path.isAbsolute(filename)) { - renderedCallsite = codeFrameColumns( - fs.readFileSync(filename, 'utf8'), - { - start: {line: topFrame.line}, - }, - {highlightCode: true}, - ); - - renderedCallsite = renderedCallsite - .split('\n') - .map(line => MESSAGE_INDENT + line) - .join('\n'); - - renderedCallsite = `\n${renderedCallsite}\n`; + let fileContent; + try { + // TODO: check & read HasteFS instead of reading the filesystem: + // see: https://github.com/facebook/jest/pull/5405#discussion_r164281696 + fileContent = fs.readFileSync(filename, 'utf8'); + renderedCallsite = getRenderedCallsite(fileContent, topFrame.line); + } catch (e) { + // the file does not exist or is inaccessible, we ignore + } } }