Ensure mocks get resolved too (#7687)

This commit is contained in:
Miguel Jiménez Esún 2019-01-24 16:04:40 +00:00 committed by GitHub
parent 1d1c3f9f1d
commit 28971c5f79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 108 additions and 18 deletions

View File

@ -124,6 +124,7 @@
- `[babel-plugin-jest-hoist]` Ignore TS type annotations when looking for out-of-scope references ([#7641](https://github.com/facebook/jest/pull/7641)) - `[babel-plugin-jest-hoist]` Ignore TS type annotations when looking for out-of-scope references ([#7641](https://github.com/facebook/jest/pull/7641))
- `[jest-config]` Add name to project if one does not exist to pick correct resolver ([#5862](https://github.com/facebook/jest/pull/5862)) - `[jest-config]` Add name to project if one does not exist to pick correct resolver ([#5862](https://github.com/facebook/jest/pull/5862))
- `[jest-runtime]` Pass `watchPathIgnorePatterns` to Haste instance ([#7585](https://github.com/facebook/jest/pull/7585)) - `[jest-runtime]` Pass `watchPathIgnorePatterns` to Haste instance ([#7585](https://github.com/facebook/jest/pull/7585))
- `[jest-runtime]` Resolve mock files via Haste when using `require.resolve` ([#7687](https://github.com/facebook/jest/pull/7585))
### Chore & Maintenance ### Chore & Maintenance

View File

@ -30,6 +30,6 @@ FAIL __tests__/index.js
12 | module.exports = () => 'test'; 12 | module.exports = () => 'test';
13 | 13 |
at createNoMappedModuleFoundError (../../packages/jest-resolve/build/index.js:433:17) at createNoMappedModuleFoundError (../../packages/jest-resolve/build/index.js:435:17)
at Object.require (index.js:10:1) at Object.require (index.js:10:1)
`; `;

View File

@ -33,6 +33,6 @@ FAIL __tests__/test.js
| ^ | ^
4 | 4 |
at Resolver.resolveModule (../../packages/jest-resolve/build/index.js:200:17) at Resolver.resolveModule (../../packages/jest-resolve/build/index.js:202:17)
at Object.require (index.js:3:18) at Object.require (index.js:3:18)
`; `;

10
e2e/resolve/Test5.js Normal file
View File

@ -0,0 +1,10 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*
* @providesModule Test5
*/
module.exports = {key: 'real'};

View File

@ -0,0 +1,8 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*/
module.exports = {key: 'mock'};

View File

@ -0,0 +1,8 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*/
module.exports = {key: 'mock'};

View File

@ -67,3 +67,34 @@ test('should preserve identity for symlinks', () => {
require('jest-resolve') require('jest-resolve')
); );
}); });
test('should require resolve haste files correctly', () => {
// We unmock Test5 (they should already be, but to be sure).
jest.unmock('Test5');
// Test5 is a standard module, that has a mock (but it is unmocked here).
expect(require.resolve('Test5')).toBe(require.resolve('../Test5'));
expect(require('Test5').key).toBe('real');
// Test6 only exits as a mock; so even when unmocked, we resolve to the mock.
expect(require.resolve('Test6')).toBe(require.resolve('../__mocks__/Test6'));
expect(require('Test6').key).toBe('mock');
});
test('should require resolve haste mocks correctly', () => {
// Now we mock Test5 and Test6.
jest.mock('Test5');
jest.mock('Test6');
// The resolution still points to the real one, but requires the mock.
expect(require.resolve('Test5')).toBe(require.resolve('../Test5'));
expect(require('Test5').key).toBe('mock');
// And Test6 points to the mock, because Test6 does not exist as a module.
expect(require.resolve('Test6')).toBe(require.resolve('../__mocks__/Test6'));
expect(require('Test6').key).toBe('mock');
});

20
e2e/resolve/hasteImpl.js Normal file
View File

@ -0,0 +1,20 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. 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.
*
* @noflow
*/
const path = require('path');
module.exports = {
getHasteName(filePath) {
const name = path.parse(filePath).name;
const isMock = filePath.indexOf('__mocks__') !== -1;
// Mocks are automatically parsed by Jest already.
return name.startsWith('Test') && !isMock ? name : null;
},
};

View File

@ -5,7 +5,8 @@
"platforms": [ "platforms": [
"native" "native"
], ],
"defaultPlatform": "android" "defaultPlatform": "android",
"hasteImplModulePath": "<rootDir>/hasteImpl.js"
}, },
"testEnvironment": "node", "testEnvironment": "node",
"moduleNameMapper": { "moduleNameMapper": {

View File

@ -122,6 +122,8 @@ class Resolver {
const key = dirname + path.delimiter + moduleName; const key = dirname + path.delimiter + moduleName;
const defaultPlatform = this._options.defaultPlatform; const defaultPlatform = this._options.defaultPlatform;
const extensions = this._options.extensions.slice(); const extensions = this._options.extensions.slice();
let module;
if (this._supportsNativePlatform) { if (this._supportsNativePlatform) {
extensions.unshift( extensions.unshift(
...this._options.extensions.map(ext => '.' + NATIVE_PLATFORM + ext), ...this._options.extensions.map(ext => '.' + NATIVE_PLATFORM + ext),
@ -133,24 +135,24 @@ class Resolver {
); );
} }
// 0. If we have already resolved this module for this directory name, // 1. If we have already resolved this module for this directory name,
// return a value from the cache. // return a value from the cache.
if (this._moduleNameCache[key]) { if (this._moduleNameCache[key]) {
return this._moduleNameCache[key]; return this._moduleNameCache[key];
} }
// 1. Check if the module is a haste module. // 2. Check if the module is a haste module.
let module = this.getModule(moduleName); module = this.getModule(moduleName);
if (module) { if (module) {
return (this._moduleNameCache[key] = module); return (this._moduleNameCache[key] = module);
} }
// 2. Check if the module is a node module and resolve it based on // 3. Check if the module is a node module and resolve it based on
// the node module resolution algorithm. // the node module resolution algorithm. If skipNodeResolution is given we
// If skipNodeResolution is given we ignore all modules that look like // ignore all modules that look like node modules (ie. are not relative
// node modules (ie. are not relative requires). This enables us to speed // requires). This enables us to speed up resolution when we build a
// up resolution when we build a dependency graph because we don't have // dependency graph because we don't have to look at modules that may not
// to look at modules that may not exist and aren't mocked. // exist and aren't mocked.
const skipResolution = const skipResolution =
options && options.skipNodeResolution && !moduleName.includes(path.sep); options && options.skipNodeResolution && !moduleName.includes(path.sep);
@ -173,7 +175,7 @@ class Resolver {
} }
} }
// 3. Resolve "haste packages" which are `package.json` files outside of // 4. Resolve "haste packages" which are `package.json` files outside of
// `node_modules` folders anywhere in the file system. // `node_modules` folders anywhere in the file system.
const parts = moduleName.split('/'); const parts = moduleName.split('/');
const hastePackage = this.getPackage(parts.shift()); const hastePackage = this.getPackage(parts.shift());
@ -206,9 +208,9 @@ class Resolver {
); );
if (module) return module; if (module) return module;
// (4.) Throw an error if the module could not be found. `resolve.sync` // 5. Throw an error if the module could not be found. `resolve.sync` only
// only produces an error based on the dirname but we have the actual // produces an error based on the dirname but we have the actual current
// current module name available. // module name available.
const relativePath = path.relative(dirname, from); const relativePath = path.relative(dirname, from);
const err = new Error( const err = new Error(
`Cannot find module '${moduleName}' from '${relativePath || '.'}'`, `Cannot find module '${moduleName}' from '${relativePath || '.'}'`,

View File

@ -589,8 +589,17 @@ class Runtime {
)}'] from ${from}`, )}'] from ${from}`,
); );
} }
try {
return this._resolveModule(from, moduleName); return this._resolveModule(from, moduleName);
} catch (err) {
const module = this._resolver.getMockModule(from, moduleName);
if (module) {
return module;
} else {
throw err;
}
}
} }
_requireResolvePaths(from: Path, moduleName?: string) { _requireResolvePaths(from: Path, moduleName?: string) {