From bd9a02580daa64dbba4b2573466262922d6687d7 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 13 Sep 2022 09:07:24 +0300 Subject: [PATCH 1/2] feat(@jest/environment): `jest.mock` type arg --- docs/JestObjectAPI.md | 38 ++++++++++++++++++- packages/jest-environment/src/index.ts | 10 ++--- .../jest-types/__typetests__/jest.test.ts | 29 ++++++++++++++ 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/docs/JestObjectAPI.md b/docs/JestObjectAPI.md index 5f63b7efcb77..eb3fbe689c00 100644 --- a/docs/JestObjectAPI.md +++ b/docs/JestObjectAPI.md @@ -254,7 +254,7 @@ banana(); // will return 'undefined' because the function is auto-mocked. The second argument can be used to specify an explicit module factory that is being run instead of using Jest's automocking feature: -```js +```js tab jest.mock('../moduleName', () => { return jest.fn(() => 42); }); @@ -264,6 +264,17 @@ const moduleName = require('../moduleName'); moduleName(); // Will return '42'; ``` +```ts tab +// The optional type argument provides typings for the module factory +jest.mock('../moduleName', () => { + return jest.fn(() => 42); +}); + +// This runs the function specified as second argument to `jest.mock`. +const moduleName = require('../moduleName'); +moduleName(); // Will return '42'; +``` + When using the `factory` parameter for an ES6 module with a default export, the `__esModule: true` property needs to be specified. This property is normally generated by Babel / TypeScript, but here it needs to be set manually. When importing a default export, it's an instruction to import the property named `default` from the export object: ```js @@ -330,7 +341,7 @@ When using `babel-jest`, calls to `mock` will automatically be hoisted to the to One example when this is useful is when you want to mock a module differently within the same file: -```js +```js tab beforeEach(() => { jest.resetModules(); }); @@ -352,6 +363,29 @@ test('moduleName 2', () => { }); ``` +```ts tab +beforeEach(() => { + jest.resetModules(); +}); + +test('moduleName 1', () => { + // The optional type argument provides typings for the module factory + jest.doMock('../moduleName', () => { + return jest.fn(() => 1); + }); + const moduleName = require('../moduleName'); + expect(moduleName()).toEqual(1); +}); + +test('moduleName 2', () => { + jest.doMock('../moduleName', () => { + return jest.fn(() => 2); + }); + const moduleName = require('../moduleName'); + expect(moduleName()).toEqual(2); +}); +``` + Using `jest.doMock()` with ES6 imports requires additional steps. Follow these if you don't want to use `require` in your tests: - We have to specify the `__esModule: true` property (see the [`jest.mock()`](#jestmockmodulename-factory-options) API for more information). diff --git a/packages/jest-environment/src/index.ts b/packages/jest-environment/src/index.ts index a683bba060cf..b2b737a3f369 100644 --- a/packages/jest-environment/src/index.ts +++ b/packages/jest-environment/src/index.ts @@ -110,9 +110,9 @@ export interface Jest { * to the top of the code block. Use this method if you want to explicitly * avoid this behavior. */ - doMock( + doMock( moduleName: string, - moduleFactory?: () => unknown, + moduleFactory?: () => T, options?: {virtual?: boolean}, ): Jest; /** @@ -170,9 +170,9 @@ export interface Jest { /** * Mocks a module with an auto-mocked version when it is being required. */ - mock( + mock( moduleName: string, - moduleFactory?: () => unknown, + moduleFactory?: () => T, options?: {virtual?: boolean}, ): Jest; /** @@ -180,7 +180,7 @@ export interface Jest { */ unstable_mockModule( moduleName: string, - moduleFactory: () => Promise | T, + moduleFactory: () => T | Promise, options?: {virtual?: boolean}, ): Jest; /** diff --git a/packages/jest-types/__typetests__/jest.test.ts b/packages/jest-types/__typetests__/jest.test.ts index 53627054f652..5fcce5512a71 100644 --- a/packages/jest-types/__typetests__/jest.test.ts +++ b/packages/jest-types/__typetests__/jest.test.ts @@ -78,9 +78,13 @@ expectError(jest.deepUnmock()); expectType(jest.doMock('moduleName')); expectType(jest.doMock('moduleName', jest.fn())); +expectType( + jest.doMock<{some: 'test'}>('moduleName', () => ({some: 'test'})), +); expectType(jest.doMock('moduleName', jest.fn(), {})); expectType(jest.doMock('moduleName', jest.fn(), {virtual: true})); expectError(jest.doMock()); +expectError(jest.doMock<{some: 'test'}>('moduleName', () => false)); expectType(jest.dontMock('moduleName')); expectError(jest.dontMock()); @@ -96,14 +100,30 @@ expectError(jest.isolateModules()); expectType(jest.mock('moduleName')); expectType(jest.mock('moduleName', jest.fn())); +expectType( + jest.mock<{some: 'test'}>('moduleName', () => ({some: 'test'})), +); expectType(jest.mock('moduleName', jest.fn(), {})); expectType(jest.mock('moduleName', jest.fn(), {virtual: true})); expectError(jest.mock()); +expectError(jest.mock<{some: 'test'}>('moduleName', () => false)); expectType(jest.unstable_mockModule('moduleName', jest.fn())); +expectType( + jest.unstable_mockModule<{some: 'test'}>('moduleName', () => ({ + some: 'test', + })), +); expectType( jest.unstable_mockModule('moduleName', () => Promise.resolve(jest.fn())), ); +expectType( + jest.unstable_mockModule<{some: 'test'}>('moduleName', () => + Promise.resolve({ + some: 'test', + }), + ), +); expectType(jest.unstable_mockModule('moduleName', jest.fn(), {})); expectType( jest.unstable_mockModule('moduleName', () => Promise.resolve(jest.fn()), {}), @@ -116,6 +136,15 @@ expectType( virtual: true, }), ); +expectError(jest.unstable_mockModule('moduleName')); +expectError( + jest.unstable_mockModule<{some: 'test'}>('moduleName', () => false), +); +expectError( + jest.unstable_mockModule<{some: 'test'}>('moduleName', () => + Promise.resolve(false), + ), +); expectType(jest.requireActual('./pathToModule')); expectError(jest.requireActual()); From 5d235715b46c28aeec260e8a8fff21bd6bd6145e Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Tue, 13 Sep 2022 09:12:35 +0300 Subject: [PATCH 2/2] add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd028883f897..3d168abe9ae9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- `[feat(@jest/environment]` Allow `jest.mock` and `jest.doMock` to take a type argument ([#13254](https://github.com/facebook/jest/pull/13254)) - `[@jest/fake-timers]` Add `jest.now()` to return the current fake clock time ([#13244](https://github.com/facebook/jest/pull/13244), [13246](https://github.com/facebook/jest/pull/13246)) ### Fixes