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))
- `[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]` Resolve mock files via Haste when using `require.resolve` ([#7687](https://github.com/facebook/jest/pull/7585))
### Chore & Maintenance

View File

@ -30,6 +30,6 @@ FAIL __tests__/index.js
12 | module.exports = () => 'test';
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)
`;

View File

@ -33,6 +33,6 @@ FAIL __tests__/test.js
| ^
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)
`;

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')
);
});
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": [
"native"
],
"defaultPlatform": "android"
"defaultPlatform": "android",
"hasteImplModulePath": "<rootDir>/hasteImpl.js"
},
"testEnvironment": "node",
"moduleNameMapper": {

View File

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

View File

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