From 2f4340cb1da435a9b147e238f7034f99653b8070 Mon Sep 17 00:00:00 2001 From: Tom Mrazauskas Date: Sat, 13 Aug 2022 00:48:22 +0300 Subject: [PATCH] feat(@jest/globals): add `jest.Mocked`, `jest.MockedClass`, `jest.MockedFunction` and `jest.MockedObject` utility types (#12727) --- CHANGELOG.md | 1 + docs/MockFunctionAPI.md | 25 ++++++++++++++ packages/jest-globals/package.json | 3 +- packages/jest-globals/src/index.ts | 34 +++++++++++++++++-- packages/jest-globals/tsconfig.json | 1 + .../jest-types/__typetests__/jest.test.ts | 34 +++++++++++++++++-- yarn.lock | 1 + 7 files changed, 94 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02d6f94c4885..c59948435fde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - `[jest-config]` [**BREAKING**] Make `snapshotFormat` default to `escapeString: false` and `printBasicPrototype: false` ([#13036](https://github.com/facebook/jest/pull/13036)) - `[jest-environment-jsdom]` [**BREAKING**] Upgrade to `jsdom@20` ([#13037](https://github.com/facebook/jest/pull/13037), [#13058](https://github.com/facebook/jest/pull/13058)) +- `[@jest/globals]` Add `jest.Mocked`, `jest.MockedClass`, `jest.MockedFunction` and `jest.MockedObject` utility types ([#12727](https://github.com/facebook/jest/pull/12727)) - `[jest-mock]` [**BREAKING**] Refactor `Mocked*` utility types. `MaybeMockedDeep` and `MaybeMocked` became `Mocked` and `MockedShallow` respectively; only deep mocked variants of `MockedClass`, `MockedFunction` and `MockedObject` are exported ([#13123](https://github.com/facebook/jest/pull/13123), [#13124](https://github.com/facebook/jest/pull/13124)) - `[jest-worker]` Adds `workerIdleMemoryLimit` option which is used as a check for worker memory leaks >= Node 16.11.0 and recycles child workers as required. ([#13056](https://github.com/facebook/jest/pull/13056), [#13105](https://github.com/facebook/jest/pull/13105), [#13106](https://github.com/facebook/jest/pull/13106), [#13107](https://github.com/facebook/jest/pull/13107)) - `[pretty-format]` [**BREAKING**] Remove `ConvertAnsi` plugin in favour of `jest-serializer-ansi-escapes` ([#13040](https://github.com/facebook/jest/pull/13040)) diff --git a/docs/MockFunctionAPI.md b/docs/MockFunctionAPI.md index db8f2d5ea4b3..0b2fea48b464 100644 --- a/docs/MockFunctionAPI.md +++ b/docs/MockFunctionAPI.md @@ -520,3 +520,28 @@ test('calculate calls add', () => { expect(mockAdd).toBeCalledWith(1, 2); }); ``` + +### `jest.Mocked` + +The `jest.Mocked` utility type returns the `Source` type wrapped with type definitions of Jest mock function. + +```ts +import fetch from 'node-fetch'; +import {expect, jest, test} from '@jest/globals'; + +jest.mock('node-fetch'); + +let mockedFetch: jest.Mocked; + +test('makes correct call', () => { + mockedFetch = getMockedFetch(); + // ... +}); + +test('returns correct data', () => { + mockedFetch = getMockedFetch(); + // ... +}); +``` + +Types of classes, functions or objects can be passed as type argument to `jest.Mocked`. If you prefer to constrain the input type, use: `jest.MockedClass`, `jest.MockedFunction` or `jest.MockedObject`. diff --git a/packages/jest-globals/package.json b/packages/jest-globals/package.json index 57bb567f65b2..a55ddbf2044b 100644 --- a/packages/jest-globals/package.json +++ b/packages/jest-globals/package.json @@ -22,7 +22,8 @@ "dependencies": { "@jest/environment": "workspace:^", "@jest/expect": "workspace:^", - "@jest/types": "workspace:^" + "@jest/types": "workspace:^", + "jest-mock": "workspace:^" }, "publishConfig": { "access": "public" diff --git a/packages/jest-globals/src/index.ts b/packages/jest-globals/src/index.ts index 90f50d9665ec..a06db18df650 100644 --- a/packages/jest-globals/src/index.ts +++ b/packages/jest-globals/src/index.ts @@ -8,8 +8,14 @@ import type {Jest} from '@jest/environment'; import type {JestExpect} from '@jest/expect'; import type {Global} from '@jest/types'; - -export declare const jest: Jest; +import type { + ClassLike, + FunctionLike, + Mocked as JestMocked, + MockedClass as JestMockedClass, + MockedFunction as JestMockedFunction, + MockedObject as JestMockedObject, +} from 'jest-mock'; export declare const expect: JestExpect; @@ -26,6 +32,30 @@ export declare const beforeEach: Global.GlobalAdditions['beforeEach']; export declare const afterEach: Global.GlobalAdditions['afterEach']; export declare const afterAll: Global.GlobalAdditions['afterAll']; +declare const jest: Jest; + +// eslint-disable-next-line @typescript-eslint/no-namespace +declare namespace jest { + /** + * Wraps a class, function or object type with Jest mock type definitions. + */ + export type Mocked = JestMocked; + /** + * Wraps a class type with Jest mock type definitions. + */ + export type MockedClass = JestMockedClass; + /** + * Wraps a function type with Jest mock type definitions. + */ + export type MockedFunction = JestMockedFunction; + /** + * Wraps an object type with Jest mock type definitions. + */ + export type MockedObject = JestMockedObject; +} + +export {jest}; + throw new Error( 'Do not import `@jest/globals` outside of the Jest test environment', ); diff --git a/packages/jest-globals/tsconfig.json b/packages/jest-globals/tsconfig.json index 16a7adbc92db..90f222531f6b 100644 --- a/packages/jest-globals/tsconfig.json +++ b/packages/jest-globals/tsconfig.json @@ -11,6 +11,7 @@ "references": [ {"path": "../jest-environment"}, {"path": "../jest-expect"}, + {"path": "../jest-mock"}, {"path": "../jest-types"} ] } diff --git a/packages/jest-types/__typetests__/jest.test.ts b/packages/jest-types/__typetests__/jest.test.ts index 58f6a1020ffa..f5f12ba68f05 100644 --- a/packages/jest-types/__typetests__/jest.test.ts +++ b/packages/jest-types/__typetests__/jest.test.ts @@ -7,7 +7,15 @@ import {expectAssignable, expectError, expectType} from 'tsd-lite'; import {jest} from '@jest/globals'; -import type {Mock, ModuleMocker, SpyInstance} from 'jest-mock'; +import type { + Mock, + Mocked, + MockedClass, + MockedFunction, + MockedObject, + ModuleMocker, + SpyInstance, +} from 'jest-mock'; expectType( jest @@ -210,7 +218,7 @@ expectType(jest.fn); expectType(jest.spyOn); -// deep mocked() +// Mocked* class SomeClass { constructor(one: string, two?: boolean) {} @@ -223,6 +231,10 @@ class SomeClass { } } +function someFunction(a: string, b?: number): boolean { + return true; +} + const someObject = { SomeClass, @@ -248,6 +260,24 @@ const someObject = { someClassInstance: new SomeClass('value'), }; +expectType>( + someObject as jest.Mocked, +); + +expectType>( + SomeClass as jest.MockedClass, +); + +expectType>( + someFunction as jest.MockedFunction, +); + +expectType>( + someObject as jest.MockedObject, +); + +// deep mocked() + const mockObjectA = jest.mocked(someObject, true); expectError(jest.mocked('abc', true)); diff --git a/yarn.lock b/yarn.lock index 2e4f5b0d44aa..851b6ea55d14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2717,6 +2717,7 @@ __metadata: "@jest/environment": "workspace:^" "@jest/expect": "workspace:^" "@jest/types": "workspace:^" + jest-mock: "workspace:^" languageName: unknown linkType: soft