diff --git a/CHANGELOG.md b/CHANGELOG.md index 6373e35b745b..b5cfce30413a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Features +- `[@jest/environment, jest-runtime]` Allow passing a generic type argument to `jest.createMockFromModule()` method ([#13202](https://github.com/facebook/jest/pull/13202)) + ### Fixes ### Chore & Maintenance diff --git a/docs/JestObjectAPI.md b/docs/JestObjectAPI.md index add6b8c49a6c..b80a1759e1b1 100644 --- a/docs/JestObjectAPI.md +++ b/docs/JestObjectAPI.md @@ -5,6 +5,16 @@ title: The Jest Object The `jest` object is automatically in scope within every test file. The methods in the `jest` object help create mocks and let you control Jest's overall behavior. It can also be imported explicitly by via `import {jest} from '@jest/globals'`. +:::info + +The TypeScript examples from this page will only work as documented if you import global APIs from `'@jest/globals'`: + +```ts +import {expect, jest, test} from '@jest/globals'; +``` + +::: + ## Methods import TOCInline from '@theme/TOCInline'; @@ -96,18 +106,12 @@ _Note: this method was previously called `autoMockOn`. When using `babel-jest`, ### `jest.createMockFromModule(moduleName)` -##### renamed in Jest **26.0.0+** - -Also under the alias: `.genMockFromModule(moduleName)` - Given the name of a module, use the automatic mocking system to generate a mocked version of the module for you. -This is useful when you want to create a [manual mock](ManualMocks.md) that extends the automatic mock's behavior. +This is useful when you want to create a [manual mock](ManualMocks.md) that extends the automatic mock's behavior: -Example: - -```js title="utils.js" -export default { +```js tab={"span":2} title="utils.js" +module.exports = { authorize: () => { return 'token'; }, @@ -116,12 +120,34 @@ export default { ``` ```js title="__tests__/createMockFromModule.test.js" -const utils = jest.createMockFromModule('../utils').default; +const utils = jest.createMockFromModule('../utils'); + utils.isAuthorized = jest.fn(secret => secret === 'not wizard'); test('implementation created by jest.createMockFromModule', () => { - expect(utils.authorize.mock).toBeTruthy(); - expect(utils.isAuthorized('not wizard')).toEqual(true); + expect(jest.isMockFunction(utils.authorize)).toBe(true); + expect(utils.isAuthorized('not wizard')).toBe(true); +}); +``` + +```ts tab={"span":2} title="utils.ts" +export const utils = { + authorize: () => { + return 'token'; + }, + isAuthorized: (secret: string) => secret === 'wizard', +}; +``` + +```ts title="__tests__/createMockFromModule.test.ts" +const {utils} = + jest.createMockFromModule('../utils'); + +utils.isAuthorized = jest.fn((secret: string) => secret === 'not wizard'); + +test('implementation created by jest.createMockFromModule', () => { + expect(jest.isMockFunction(utils.authorize)).toBe(true); + expect(utils.isAuthorized('not wizard')).toBe(true); }); ``` @@ -180,7 +206,7 @@ module.exports = { ``` ```js title="__tests__/example.test.js" -const example = jest.createMockFromModule('./example'); +const example = jest.createMockFromModule('../example'); test('should run example code', () => { // creates a new mocked function with no formal arguments. diff --git a/packages/jest-environment/src/index.ts b/packages/jest-environment/src/index.ts index 4d4df64eaad7..e5a4c3037e65 100644 --- a/packages/jest-environment/src/index.ts +++ b/packages/jest-environment/src/index.ts @@ -8,7 +8,7 @@ import type {Context} from 'vm'; import type {LegacyFakeTimers, ModernFakeTimers} from '@jest/fake-timers'; import type {Circus, Config, Global} from '@jest/types'; -import type {ModuleMocker} from 'jest-mock'; +import type {Mocked, ModuleMocker} from 'jest-mock'; export type EnvironmentContext = { console: Console; @@ -92,7 +92,7 @@ export interface Jest { * This is useful when you want to create a manual mock that extends the * automatic mock's behavior. */ - createMockFromModule(moduleName: string): unknown; + createMockFromModule(moduleName: string): Mocked; /** * Indicates that the module system should never return a mocked version of * the specified module and its dependencies. @@ -129,6 +129,7 @@ export interface Jest { * Creates a mock function. Optionally takes a mock implementation. */ fn: ModuleMocker['fn']; + // TODO remove `genMockFromModule()` in Jest 30 /** * Given the name of a module, use the automatic mocking system to generate a * mocked version of the module for you. @@ -138,7 +139,7 @@ export interface Jest { * * @deprecated Use `jest.createMockFromModule()` instead */ - genMockFromModule(moduleName: string): unknown; + genMockFromModule(moduleName: string): Mocked; /** * When mocking time, `Date.now()` will also be mocked. If you for some reason * need access to the real current time, you can invoke this function. diff --git a/packages/jest-runtime/src/index.ts b/packages/jest-runtime/src/index.ts index 639ccc9371c3..4e9358d24f8a 100644 --- a/packages/jest-runtime/src/index.ts +++ b/packages/jest-runtime/src/index.ts @@ -50,7 +50,7 @@ import { import type {Config, Global} from '@jest/types'; import HasteMap, {IModuleMap} from 'jest-haste-map'; import {formatStackTrace, separateMessageFromStack} from 'jest-message-util'; -import type {MockFunctionMetadata, ModuleMocker} from 'jest-mock'; +import type {MockMetadata, ModuleMocker} from 'jest-mock'; import {escapePathForRegex} from 'jest-regex-util'; import Resolver, {ResolveModuleConfig} from 'jest-resolve'; import {EXTENSION as SnapshotExtension} from 'jest-snapshot'; @@ -168,7 +168,7 @@ export default class Runtime { private _isCurrentlyExecutingManualMock: string | null; private _mainModule: Module | null; private readonly _mockFactories: Map unknown>; - private readonly _mockMetaDataCache: Map; + private readonly _mockMetaDataCache: Map>; private _mockRegistry: Map; private _isolatedMockRegistry: Map | null; private _moduleMockRegistry: Map; @@ -1710,7 +1710,7 @@ export default class Runtime { return Module; } - private _generateMock(from: string, moduleName: string) { + private _generateMock(from: string, moduleName: string) { const modulePath = this._resolver.resolveStubModuleName(from, moduleName) || this._resolveCjsModule(from, moduleName); @@ -1747,7 +1747,7 @@ export default class Runtime { } this._mockMetaDataCache.set(modulePath, mockMetadata); } - return this._moduleMocker.generateFromMetadata( + return this._moduleMocker.generateFromMetadata( // added above if missing this._mockMetaDataCache.get(modulePath)!, ); diff --git a/packages/jest-types/__typetests__/jest.test.ts b/packages/jest-types/__typetests__/jest.test.ts index 997aad9cac69..188fe697072c 100644 --- a/packages/jest-types/__typetests__/jest.test.ts +++ b/packages/jest-types/__typetests__/jest.test.ts @@ -62,7 +62,15 @@ expectError(jest.autoMockOff(true)); expectType(jest.autoMockOn()); expectError(jest.autoMockOn(false)); +const someModule = { + methodA: () => {}, + propertyB: 'B', +}; + expectType(jest.createMockFromModule('moduleName')); +expectType>( + jest.createMockFromModule('moduleName'), +); expectError(jest.createMockFromModule()); expectType(jest.deepUnmock('moduleName'));