From 176e16f6412fac6cc2fdd1d71b18ae9ffd9b4245 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus <sbekkhus91@gmail.com> Date: Wed, 23 Dec 2020 16:20:17 +0100 Subject: [PATCH 1/2] feat(runtime): add jest.mockModule --- e2e/native-esm/__tests__/native-esm.test.js | 2 +- packages/jest-environment/src/index.ts | 4 +- packages/jest-runtime/src/index.ts | 83 +++++++++++++++++++-- 3 files changed, 80 insertions(+), 9 deletions(-) diff --git a/e2e/native-esm/__tests__/native-esm.test.js b/e2e/native-esm/__tests__/native-esm.test.js index 494d67e62146..0d2536a10fa0 100644 --- a/e2e/native-esm/__tests__/native-esm.test.js +++ b/e2e/native-esm/__tests__/native-esm.test.js @@ -184,7 +184,7 @@ test('require of ESM should throw correct error', () => { }); test('can mock module', async () => { - jestObject.unstable_mockModule('../mockedModule.mjs', () => ({foo: 'bar'}), { + jestObject.mockModule('../mockedModule.mjs', () => ({foo: 'bar'}), { virtual: true, }); diff --git a/packages/jest-environment/src/index.ts b/packages/jest-environment/src/index.ts index 7a6e1cc8f7ef..0f0bd6500075 100644 --- a/packages/jest-environment/src/index.ts +++ b/packages/jest-environment/src/index.ts @@ -173,9 +173,9 @@ export interface Jest { /** * Mocks a module with the provided module factory when it is being imported. */ - unstable_mockModule<T = unknown>( + mockModule<T = unknown>( moduleName: string, - moduleFactory: () => Promise<T> | T, + moduleFactory?: () => Promise<T> | T, options?: {virtual?: boolean}, ): Jest; /** diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 1dc2c9a56322..99e19a5d1604 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -716,6 +716,8 @@ export default class Runtime { async unstable_importModule( from: string, moduleName?: string, + // TODO: implement this + _isImportActual = false, ): Promise<void> { invariant( runtimeSupportsVmModules, @@ -793,6 +795,7 @@ export default class Runtime { this.setExport(key, value); }); }, + // should identifier be `node://${moduleName}`? {context, identifier: moduleName}, ); @@ -801,7 +804,69 @@ export default class Runtime { return evaluateSyntheticModule(module); } - throw new Error('Attempting to import a mock without a factory'); + const manualMockOrStub = this._resolver.getMockModule(from, moduleName); + + let modulePath = + this._resolver.getMockModule(from, moduleName) || + this._resolveModule(from, moduleName); + + 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: InitialModule = { + children: [], + exports: {}, + filename: modulePath, + id: modulePath, + loaded: false, + path: modulePath, + }; + + this._loadModule( + localModule, + from, + moduleName, + modulePath, + undefined, + this._moduleMockRegistry, + ); + + this._moduleMockRegistry.set(moduleID, localModule.exports); + } else { + // Look for a real module to generate an automock from + this._moduleMockRegistry.set( + moduleID, + this._generateMock(from, moduleName), + ); + } + + return this._moduleMockRegistry.get(moduleID); } private getExportsOfCjs(modulePath: string) { @@ -2041,16 +2106,22 @@ export default class Runtime { this.setMock(from, moduleName, mockFactory, options); return jestObject; }; - const mockModule: Jest['unstable_mockModule'] = ( + const mockModule: Jest['mockModule'] = ( moduleName, mockFactory, options, ) => { - if (typeof mockFactory !== 'function') { - throw new Error('`unstable_mockModule` must be passed a mock factory'); + if (mockFactory !== undefined) { + this.setModuleMock(from, moduleName, mockFactory, options); + return jestObject; } - this.setModuleMock(from, moduleName, mockFactory, options); + const moduleID = this._resolver.getModuleID( + this._virtualMocks, + from, + moduleName, + ); + this._explicitShouldMockModule.set(moduleID, true); return jestObject; }; const clearAllMocks = () => { @@ -2161,6 +2232,7 @@ export default class Runtime { isolateModules, mock, mocked, + mockModule, requireActual: this.requireActual.bind(this, from), requireMock: this.requireMock.bind(this, from), resetAllMocks, @@ -2197,7 +2269,6 @@ export default class Runtime { setTimeout, spyOn, unmock, - unstable_mockModule: mockModule, useFakeTimers, useRealTimers, }; From 3895c42fb392d887904247270aa86f6f88b09ec4 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus <sbekkhus91@gmail.com> Date: Wed, 23 Dec 2020 16:46:01 +0100 Subject: [PATCH 2/2] remove dead code --- packages/jest-runtime/src/index.ts | 65 +----------------------------- 1 file changed, 1 insertion(+), 64 deletions(-) diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 99e19a5d1604..dc0929c926d1 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -795,7 +795,6 @@ export default class Runtime { this.setExport(key, value); }); }, - // should identifier be `node://${moduleName}`? {context, identifier: moduleName}, ); @@ -804,69 +803,7 @@ export default class Runtime { return evaluateSyntheticModule(module); } - const manualMockOrStub = this._resolver.getMockModule(from, moduleName); - - let modulePath = - this._resolver.getMockModule(from, moduleName) || - this._resolveModule(from, moduleName); - - 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: InitialModule = { - children: [], - exports: {}, - filename: modulePath, - id: modulePath, - loaded: false, - path: modulePath, - }; - - this._loadModule( - localModule, - from, - moduleName, - modulePath, - undefined, - this._moduleMockRegistry, - ); - - this._moduleMockRegistry.set(moduleID, localModule.exports); - } else { - // Look for a real module to generate an automock from - this._moduleMockRegistry.set( - moduleID, - this._generateMock(from, moduleName), - ); - } - - return this._moduleMockRegistry.get(moduleID); + throw new Error('Attempting to import a mock without a factory'); } private getExportsOfCjs(modulePath: string) {