From 6265b89dc4bb799df1bacddc2a98e3fe3803453c Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Sun, 17 Sep 2017 17:10:29 -0700 Subject: [PATCH 01/10] Support jest-preset.js files within Node modules. Use resolver extensions options. --- docs/Configuration.md | 10 ++++- .../src/__tests__/normalize.test.js | 42 +++++++++++++++++++ packages/jest-config/src/normalize.js | 7 ++-- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 85e4e7ee0ae4..24a8a5960335 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -470,7 +470,15 @@ Specifies notification mode. Requires `notify: true`. Default: `undefined` A preset that is used as a base for Jest's configuration. A preset should point -to an npm module that exports a `jest-preset.json` module on its top level. +to an npm module that exports a `jest-preset.json` or `jest-preset.js` module at its top level. + +Presets may also be relative filesystem paths. + +```json +{ + "preset": "./node_modules/foo-bar/jest-preset.js" +} +``` ### `projects` [array] diff --git a/packages/jest-config/src/__tests__/normalize.test.js b/packages/jest-config/src/__tests__/normalize.test.js index 718e24404c32..8ed53a004684 100644 --- a/packages/jest-config/src/__tests__/normalize.test.js +++ b/packages/jest-config/src/__tests__/normalize.test.js @@ -897,6 +897,24 @@ describe('preset', () => { }), {virtual: true}, ); + jest.mock( + '/node_modules/with-json-ext/jest-preset.json', + () => ({ + moduleNameMapper: { + json: true, + }, + }), + {virtual: true}, + ); + jest.mock( + '/node_modules/with-js-ext/jest-preset.js', + () => ({ + moduleNameMapper: { + js: true, + }, + }), + {virtual: true}, + ); }); afterEach(() => { @@ -943,6 +961,30 @@ describe('preset', () => { }).not.toThrow(); }); + test('supports .json preset files', () => { + const {options} = normalize( + { + preset: 'with-json-ext', + rootDir: '/root/path/foo', + }, + {}, + ); + + expect(options.moduleNameMapper).toEqual([['json', true]]); + }); + + test('supports .js preset files', () => { + const {options} = normalize( + { + preset: 'with-js-ext', + rootDir: '/root/path/foo', + }, + {}, + ); + + expect(options.moduleNameMapper).toEqual([['js', true]]); + }); + test('merges with options', () => { const {options} = normalize( { diff --git a/packages/jest-config/src/normalize.js b/packages/jest-config/src/normalize.js index ad848a7a2b0a..0e33928bad5a 100644 --- a/packages/jest-config/src/normalize.js +++ b/packages/jest-config/src/normalize.js @@ -36,8 +36,8 @@ import DEPRECATED_CONFIG from './deprecated'; import setFromArgv from './set_from_argv'; import VALID_CONFIG from './valid_config'; const ERROR = `${BULLET}Validation Error`; -const JSON_EXTENSION = '.json'; -const PRESET_NAME = 'jest-preset' + JSON_EXTENSION; +const PRESET_EXTENSIONS = ['.json', '.js']; +const PRESET_NAME = 'jest-preset'; const createConfigError = message => new ValidationError(ERROR, message, DOCUMENTATION_NOTE); @@ -64,11 +64,12 @@ const setupPreset = ( let preset; const presetPath = replaceRootDirInPath(options.rootDir, optionsPreset); const presetModule = Resolver.findNodeModule( - presetPath.endsWith(JSON_EXTENSION) + presetPath.charAt(0) === '.' ? presetPath : path.join(presetPath, PRESET_NAME), { basedir: options.rootDir, + extensions: PRESET_EXTENSIONS, }, ); From 161dc5ec7bcd10d0d4b1524dab6868a60551af75 Mon Sep 17 00:00:00 2001 From: Robin Drexler Date: Wed, 16 May 2018 09:26:38 +0200 Subject: [PATCH 02/10] Fix normalize tests --- .../src/__tests__/normalize.test.js | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/packages/jest-config/src/__tests__/normalize.test.js b/packages/jest-config/src/__tests__/normalize.test.js index 8ed53a004684..49ecf85bba01 100644 --- a/packages/jest-config/src/__tests__/normalize.test.js +++ b/packages/jest-config/src/__tests__/normalize.test.js @@ -882,7 +882,7 @@ describe('preset', () => { beforeEach(() => { const Resolver = require('jest-resolve'); Resolver.findNodeModule = jest.fn(name => { - if (name === 'react-native/jest-preset.json') { + if (name === 'react-native/jest-preset') { return '/node_modules/react-native/jest-preset.json'; } return '/node_modules/' + name; @@ -961,28 +961,19 @@ describe('preset', () => { }).not.toThrow(); }); - test('supports .json preset files', () => { - const {options} = normalize( - { - preset: 'with-json-ext', - rootDir: '/root/path/foo', - }, - {}, - ); - - expect(options.moduleNameMapper).toEqual([['json', true]]); - }); + test('searches for .json and .js preset files', () => { + const Resolver = require('jest-resolve'); - test('supports .js preset files', () => { - const {options} = normalize( + normalize( { - preset: 'with-js-ext', + preset: 'react-native', rootDir: '/root/path/foo', }, {}, ); - expect(options.moduleNameMapper).toEqual([['js', true]]); + const options = Resolver.findNodeModule.mock.calls[0][1]; + expect(options.extensions).toEqual(['.json', '.js']); }); test('merges with options', () => { @@ -1074,7 +1065,7 @@ describe('preset without setupFiles', () => { beforeAll(() => { jest.doMock( - '/node_modules/react-foo/jest-preset.json', + '/node_modules/react-foo/jest-preset', () => { return { moduleNameMapper: {b: 'b'}, @@ -1086,7 +1077,7 @@ describe('preset without setupFiles', () => { }); afterAll(() => { - jest.dontMock('/node_modules/react-foo/jest-preset.json'); + jest.dontMock('/node_modules/react-foo/jest-preset'); }); it('should normalize setupFiles correctly', () => { From fb627322939fb67105ad881100d3ccf5b6f813b0 Mon Sep 17 00:00:00 2001 From: Robin Drexler Date: Wed, 16 May 2018 09:49:17 +0200 Subject: [PATCH 03/10] Delete preset from require cache to allow multiple projects --- packages/jest-config/src/normalize.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/jest-config/src/normalize.js b/packages/jest-config/src/normalize.js index 0e33928bad5a..1d579761488b 100644 --- a/packages/jest-config/src/normalize.js +++ b/packages/jest-config/src/normalize.js @@ -76,6 +76,13 @@ const setupPreset = ( try { // $FlowFixMe preset = (require(presetModule): InitialOptions); + + // Force re-evaluation to support multiple projects + try { + if (presetModule) { + delete require.cache[require.resolve(presetModule)]; + } + } catch (e) {} } catch (error) { if (error instanceof SyntaxError) { throw createConfigError( From ac8f57fe976668a370c2c64f3d7b2657fabcaff0 Mon Sep 17 00:00:00 2001 From: Robin Drexler Date: Wed, 16 May 2018 09:51:07 +0200 Subject: [PATCH 04/10] Prettify Configuration.md --- docs/Configuration.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 24a8a5960335..edde687c7143 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -470,7 +470,8 @@ Specifies notification mode. Requires `notify: true`. Default: `undefined` A preset that is used as a base for Jest's configuration. A preset should point -to an npm module that exports a `jest-preset.json` or `jest-preset.js` module at its top level. +to an npm module that exports a `jest-preset.json` or `jest-preset.js` module at +its top level. Presets may also be relative filesystem paths. From 42ec8005a3eb777fa8958a8d420ccb77c757aa70 Mon Sep 17 00:00:00 2001 From: Robin Drexler Date: Wed, 16 May 2018 20:59:00 +0200 Subject: [PATCH 05/10] Add integration test for js and json presets --- .gitignore | 2 ++ integration-tests/__tests__/presets.test.js | 21 +++++++++++++++++++ .../presets/js/__tests__/index.js | 11 ++++++++++ .../jest-preset-js/jest-preset.js | 5 +++++ .../js/node_modules/jest-preset-js/mapper.js | 1 + integration-tests/presets/js/package.json | 5 +++++ .../presets/json/__tests__/index.js | 11 ++++++++++ .../jest-preset-json/jest-preset.json | 5 +++++ .../node_modules/jest-preset-json/mapper.js | 1 + integration-tests/presets/json/package.json | 5 +++++ 10 files changed, 67 insertions(+) create mode 100644 integration-tests/__tests__/presets.test.js create mode 100644 integration-tests/presets/js/__tests__/index.js create mode 100644 integration-tests/presets/js/node_modules/jest-preset-js/jest-preset.js create mode 100644 integration-tests/presets/js/node_modules/jest-preset-js/mapper.js create mode 100644 integration-tests/presets/js/package.json create mode 100644 integration-tests/presets/json/__tests__/index.js create mode 100644 integration-tests/presets/json/node_modules/jest-preset-json/jest-preset.json create mode 100644 integration-tests/presets/json/node_modules/jest-preset-json/mapper.js create mode 100644 integration-tests/presets/json/package.json diff --git a/.gitignore b/.gitignore index 80a6548be223..31a19105ed56 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ /examples/*/node_modules/ /integration-tests/*/node_modules +!/integration-tests/presets/json/node_modules +!/integration-tests/presets/js/node_modules /integration-tests/transform/*/coverage /integration-tests/transform/*/node_modules diff --git a/integration-tests/__tests__/presets.test.js b/integration-tests/__tests__/presets.test.js new file mode 100644 index 000000000000..0166d03dd26a --- /dev/null +++ b/integration-tests/__tests__/presets.test.js @@ -0,0 +1,21 @@ +/** + * 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('supports json preset', () => { + const result = runJest('presets/json'); + expect(result.status).toBe(0); +}); + +test('supports js preset', () => { + const result = runJest('presets/js'); + expect(result.status).toBe(0); +}); diff --git a/integration-tests/presets/js/__tests__/index.js b/integration-tests/presets/js/__tests__/index.js new file mode 100644 index 000000000000..37ddfff8736c --- /dev/null +++ b/integration-tests/presets/js/__tests__/index.js @@ -0,0 +1,11 @@ +/** + * 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. + */ +'use strict'; + +test('load file mapped by js preset', () => { + expect(require('./test.foo')).toEqual(42); +}); diff --git a/integration-tests/presets/js/node_modules/jest-preset-js/jest-preset.js b/integration-tests/presets/js/node_modules/jest-preset-js/jest-preset.js new file mode 100644 index 000000000000..f5585495bcfb --- /dev/null +++ b/integration-tests/presets/js/node_modules/jest-preset-js/jest-preset.js @@ -0,0 +1,5 @@ +module.exports = { + moduleNameMapper: { + '^.+\\.foo$': 'jest-preset-js/mapper.js', + }, +}; diff --git a/integration-tests/presets/js/node_modules/jest-preset-js/mapper.js b/integration-tests/presets/js/node_modules/jest-preset-js/mapper.js new file mode 100644 index 000000000000..888cae37af95 --- /dev/null +++ b/integration-tests/presets/js/node_modules/jest-preset-js/mapper.js @@ -0,0 +1 @@ +module.exports = 42; diff --git a/integration-tests/presets/js/package.json b/integration-tests/presets/js/package.json new file mode 100644 index 000000000000..7390cf69ce25 --- /dev/null +++ b/integration-tests/presets/js/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "preset": "jest-preset-js" + } +} \ No newline at end of file diff --git a/integration-tests/presets/json/__tests__/index.js b/integration-tests/presets/json/__tests__/index.js new file mode 100644 index 000000000000..dc10bd7b2712 --- /dev/null +++ b/integration-tests/presets/json/__tests__/index.js @@ -0,0 +1,11 @@ +/** + * 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. + */ +'use strict'; + +test('load file mapped by json preset', () => { + expect(require('./test.foo')).toEqual(42); +}); diff --git a/integration-tests/presets/json/node_modules/jest-preset-json/jest-preset.json b/integration-tests/presets/json/node_modules/jest-preset-json/jest-preset.json new file mode 100644 index 000000000000..39517294ea27 --- /dev/null +++ b/integration-tests/presets/json/node_modules/jest-preset-json/jest-preset.json @@ -0,0 +1,5 @@ +{ + "moduleNameMapper": { + "^.+\\.foo$": "jest-preset-json/mapper.js" + } +} diff --git a/integration-tests/presets/json/node_modules/jest-preset-json/mapper.js b/integration-tests/presets/json/node_modules/jest-preset-json/mapper.js new file mode 100644 index 000000000000..888cae37af95 --- /dev/null +++ b/integration-tests/presets/json/node_modules/jest-preset-json/mapper.js @@ -0,0 +1 @@ +module.exports = 42; diff --git a/integration-tests/presets/json/package.json b/integration-tests/presets/json/package.json new file mode 100644 index 000000000000..fc14967979ae --- /dev/null +++ b/integration-tests/presets/json/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "preset": "jest-preset-json" + } +} \ No newline at end of file From bd119032610162e82f3a44bd6f065dacc3535b76 Mon Sep 17 00:00:00 2001 From: Robin Drexler Date: Wed, 16 May 2018 21:01:37 +0200 Subject: [PATCH 06/10] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfa3700e6255..f3bf0343b4f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Features +* `[jest-config]` Support jest-preset.js files within Node modules + ([#6185](https://github.com/facebook/jest/pull/6185)) * `[jest-cli]` Add `--detectOpenHandles` flag which enables Jest to potentially track down handles keeping it open after tests are complete. ([#6130](https://github.com/facebook/jest/pull/6130)) From f27a49db3db5005c7f3ae2cec1d3f38f0bff7442 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 18 May 2018 13:55:58 +0100 Subject: [PATCH 07/10] Update package.json --- integration-tests/presets/json/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/presets/json/package.json b/integration-tests/presets/json/package.json index fc14967979ae..60d71a4edcd0 100644 --- a/integration-tests/presets/json/package.json +++ b/integration-tests/presets/json/package.json @@ -2,4 +2,4 @@ "jest": { "preset": "jest-preset-json" } -} \ No newline at end of file +} From c24ac990b01fe41715211bf3ec54e102b886ada1 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 18 May 2018 13:56:09 +0100 Subject: [PATCH 08/10] Update package.json --- integration-tests/presets/js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/presets/js/package.json b/integration-tests/presets/js/package.json index 7390cf69ce25..54ea256f7f39 100644 --- a/integration-tests/presets/js/package.json +++ b/integration-tests/presets/js/package.json @@ -2,4 +2,4 @@ "jest": { "preset": "jest-preset-js" } -} \ No newline at end of file +} From 7296a552b03a5e413569396f1f4728de36c4a272 Mon Sep 17 00:00:00 2001 From: Robin Drexler Date: Fri, 18 May 2018 21:13:17 +0200 Subject: [PATCH 09/10] Delete require cache before requiring preset --- packages/jest-config/src/normalize.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/jest-config/src/normalize.js b/packages/jest-config/src/normalize.js index 1d579761488b..408f7aeda3f0 100644 --- a/packages/jest-config/src/normalize.js +++ b/packages/jest-config/src/normalize.js @@ -74,15 +74,15 @@ const setupPreset = ( ); try { - // $FlowFixMe - preset = (require(presetModule): InitialOptions); - // Force re-evaluation to support multiple projects try { if (presetModule) { delete require.cache[require.resolve(presetModule)]; } } catch (e) {} + + // $FlowFixMe + preset = (require(presetModule): InitialOptions); } catch (error) { if (error instanceof SyntaxError) { throw createConfigError( From 6786998ea62043a0acdcc09e75177392cc6fcfac Mon Sep 17 00:00:00 2001 From: Robin Drexler Date: Tue, 22 May 2018 08:50:10 +0200 Subject: [PATCH 10/10] refactor normalize to use startsWith instead of charAt --- packages/jest-config/src/normalize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-config/src/normalize.js b/packages/jest-config/src/normalize.js index 408f7aeda3f0..9efc83d073c3 100644 --- a/packages/jest-config/src/normalize.js +++ b/packages/jest-config/src/normalize.js @@ -64,7 +64,7 @@ const setupPreset = ( let preset; const presetPath = replaceRootDirInPath(options.rootDir, optionsPreset); const presetModule = Resolver.findNodeModule( - presetPath.charAt(0) === '.' + presetPath.startsWith('.') ? presetPath : path.join(presetPath, PRESET_NAME), {