Skip to content

Commit

Permalink
Fix for mocks not working with module name mapper (#7787)
Browse files Browse the repository at this point in the history
  • Loading branch information
grosto authored and SimenB committed Feb 3, 2019
1 parent 006b0b9 commit ab64cc8
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 31 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

### Fixes

- `[jest-runtime]` Fix for mocks not working with module name mapper ([#7787](https://github.com/facebook/jest/pull/7787))
- `[jest-cli]` Break dependency cycle when using Jest programmatically ([#7707](https://github.com/facebook/jest/pull/7707))
- `[jest-config]` Extract setupFilesAfterEnv from preset ([#7724](https://github.com/facebook/jest/pull/7724))
- `[jest-cli]` Do not execute any `globalSetup` or `globalTeardown` if there are no tests to execute ([#7745](https://github.com/facebook/jest/pull/7745))
Expand Down
8 changes: 7 additions & 1 deletion e2e/__tests__/moduleNameMapper.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @flow
*/

import runJest from '../runJest';
import runJest, {json as runWithJson} from '../runJest';
import {extractSummary} from '../Utils';
import {wrap} from 'jest-snapshot-serializer-raw';

Expand All @@ -28,3 +28,9 @@ test('moduleNameMapper correct configuration', () => {
expect(status).toBe(0);
expect(wrap(rest)).toMatchSnapshot();
});

test('moduleNameMapper with mocking', () => {
const {json} = runWithJson('module-name-mapper-mock');
expect(json.numTotalTests).toBe(2);
expect(json.success).toBe(true);
});
14 changes: 14 additions & 0 deletions e2e/module-name-mapper-mock/__tests__/storage/track/Track.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* 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.
*/

const {Track} = require('../../../src/storage/track/Track');
jest.mock('@@storage/track/Track');

test('relative import', () => {
const track = new Track();
expect(track.someRandomFunction).not.toBeCalled();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* 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.
*/

const {Track} = require('@@storage/track/Track');
jest.mock('@@storage/track/Track');

test('through moduleNameMapper', () => {
const track = new Track();
expect(track.someRandomFunction).not.toBeCalled();
});
8 changes: 8 additions & 0 deletions e2e/module-name-mapper-mock/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"jest": {
"moduleNameMapper": {
"^@@storage/(.*)$": "<rootDir>/src/storage/$1"
},
"testEnvironment": "node"
}
}
12 changes: 12 additions & 0 deletions e2e/module-name-mapper-mock/src/storage/track/Track.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* 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.Track = class Track {
someRandomFunction() {
return 42;
}
};
4 changes: 2 additions & 2 deletions packages/jest-resolve/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ class Resolver {
if (mock) {
return mock;
} else {
const moduleName = this._resolveStubModuleName(from, name);
const moduleName = this.resolveStubModuleName(from, name);
if (moduleName) {
return this.getModule(moduleName) || moduleName;
}
Expand Down Expand Up @@ -341,7 +341,7 @@ class Resolver {
);
}

_resolveStubModuleName(from: Path, moduleName: string): ?Path {
resolveStubModuleName(from: Path, moduleName: string): ?Path {
const dirname = path.dirname(from);
const paths = this._options.modulePaths;
const extensions = this._options.extensions.slice();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@

let createRuntime;

const moduleNameMapper = {
'module/name/(.*)': '<rootDir>/mapped_module_$1.js',
};

describe('Runtime', () => {
beforeEach(() => {
createRuntime = require('createRuntime');
Expand All @@ -35,6 +39,16 @@ describe('Runtime', () => {
expect(mock.fn()).toBe(undefined);
expect(module.getModuleStateValue()).toBe(origModuleStateValue);
}));

it('resolves mapped modules correctly', () =>
createRuntime(__filename, {moduleNameMapper}).then(runtime => {
const root = runtime.requireModule(runtime.__mockRootPath);
const mockModule = root.jest.genMockFromModule(
'module/name/genMockFromModule',
);

expect(mockModule.test.mock).toBeTruthy();
}));
});

it('creates mock objects in the right environment', () =>
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
*/

module.exports = {
test: () => '42',
};
63 changes: 35 additions & 28 deletions packages/jest-runtime/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,37 +389,43 @@ class Runtime {
return (mockRegistry[moduleID] = this._mockFactories[moduleID]());
}

let manualMock = this._resolver.getMockModule(from, moduleName);
const manualMockOrStub = this._resolver.getMockModule(from, moduleName);
let modulePath;
if (manualMock) {
modulePath = this._resolveModule(from, manualMock);
if (manualMockOrStub) {
modulePath = this._resolveModule(from, manualMockOrStub);
} else {
modulePath = this._resolveModule(from, moduleName);
}
// If the actual module file has a __mocks__ dir sitting immediately next
// to it, look to see if there is a manual mock for this file.
//
// subDir1/my_module.js
// subDir1/__mocks__/my_module.js
// subDir2/my_module.js
// subDir2/__mocks__/my_module.js
//
// Where some other module does a relative require into each of the
// respective subDir{1,2} directories and expects a manual mock
// corresponding to that particular my_module.js file.
const moduleDir = path.dirname(modulePath);
const moduleFileName = path.basename(modulePath);
const potentialManualMock = path.join(
moduleDir,
'__mocks__',
moduleFileName,
);
if (fs.existsSync(potentialManualMock)) {
manualMock = true;
modulePath = potentialManualMock;
}

if (manualMock) {
let isManualMock =
manualMockOrStub &&
!this._resolver.resolveStubModuleName(from, moduleName);
if (!isManualMock) {
// If the actual module file has a __mocks__ dir sitting immediately next
// to it, look to see if there is a manual mock for this file.
//
// subDir1/my_module.js
// subDir1/__mocks__/my_module.js
// subDir2/my_module.js
// subDir2/__mocks__/my_module.js
//
// Where some other module does a relative require into each of the
// respective subDir{1,2} directories and expects a manual mock
// corresponding to that particular my_module.js file.

const moduleDir = path.dirname(modulePath);
const moduleFileName = path.basename(modulePath);
const potentialManualMock = path.join(
moduleDir,
'__mocks__',
moduleFileName,
);
if (fs.existsSync(potentialManualMock)) {
isManualMock = true;
modulePath = potentialManualMock;
}
}
if (isManualMock) {
const localModule: Module = {
children: [],
exports: {},
Expand Down Expand Up @@ -730,8 +736,9 @@ class Runtime {
}

_generateMock(from: Path, moduleName: string) {
const modulePath = this._resolveModule(from, moduleName);

const modulePath =
this._resolver.resolveStubModuleName(from, moduleName) ||
this._resolveModule(from, moduleName);
if (!(modulePath in this._mockMetaDataCache)) {
// This allows us to handle circular dependencies while generating an
// automock
Expand Down

0 comments on commit ab64cc8

Please sign in to comment.