From 911b74e4d8af4846ccf964793b9042bd7401f600 Mon Sep 17 00:00:00 2001 From: Vincent Date: Tue, 6 Oct 2020 11:53:40 +0200 Subject: [PATCH] Fix type definitions for promises (#10600) When calling `mockResolvedValue` (-`Once`), the argument should be the expected return value unwrapped from its Promise. Likewise, when mocking a rejected value, the passed argument needs not necessarily be of the same type as the expected successful return value. --- CHANGELOG.md | 2 ++ packages/jest-mock/src/index.ts | 22 +++++++++++---------- test-types/top-level-jest-namespace.test.ts | 21 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f29887d759a1..786ec76af00a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Fixes +- `[jest-mock]` Fix typings for `mockResolvedValue`, `mockResolvedValueOnce`, `mockRejectedValue` and `mockRejectedValueOnce` + ### Chore & Maintenance ### Performance diff --git a/packages/jest-mock/src/index.ts b/packages/jest-mock/src/index.ts index 8031900b0453..073c9d6b8a6d 100644 --- a/packages/jest-mock/src/index.ts +++ b/packages/jest-mock/src/index.ts @@ -63,13 +63,15 @@ namespace JestMock { mockReturnThis(): this; mockReturnValue(value: T): this; mockReturnValueOnce(value: T): this; - mockResolvedValue(value: T): this; - mockResolvedValueOnce(value: T): this; - mockRejectedValue(value: T): this; - mockRejectedValueOnce(value: T): this; + mockResolvedValue(value: Unpromisify): this; + mockResolvedValueOnce(value: Unpromisify): this; + mockRejectedValue(value: unknown): this; + mockRejectedValueOnce(value: unknown): this; } } +type Unpromisify = T extends Promise ? R : never; + /** * Possible types of a MockFunctionResult. * 'return': The call completed by returning normally. @@ -661,20 +663,20 @@ class ModuleMockerClass { // next function call will return this value or default return value f.mockImplementationOnce(() => value); - f.mockResolvedValueOnce = (value: T) => - f.mockImplementationOnce(() => Promise.resolve(value)); + f.mockResolvedValueOnce = (value: Unpromisify) => + f.mockImplementationOnce(() => Promise.resolve(value as T)); - f.mockRejectedValueOnce = (value: T) => + f.mockRejectedValueOnce = (value: unknown) => f.mockImplementationOnce(() => Promise.reject(value)); f.mockReturnValue = (value: T) => // next function call will return specified return value or this one f.mockImplementation(() => value); - f.mockResolvedValue = (value: T) => - f.mockImplementation(() => Promise.resolve(value)); + f.mockResolvedValue = (value: Unpromisify) => + f.mockImplementation(() => Promise.resolve(value as T)); - f.mockRejectedValue = (value: T) => + f.mockRejectedValue = (value: unknown) => f.mockImplementation(() => Promise.reject(value)); f.mockImplementationOnce = ( diff --git a/test-types/top-level-jest-namespace.test.ts b/test-types/top-level-jest-namespace.test.ts index 41be5aee551c..fe03300cdea5 100644 --- a/test-types/top-level-jest-namespace.test.ts +++ b/test-types/top-level-jest-namespace.test.ts @@ -10,6 +10,7 @@ import {expectError, expectType} from 'mlh-tsd'; //eslint-disable-next-line import/no-extraneous-dependencies import {jest} from '@jest/globals'; +import type {Mock} from 'jest-mock'; expectType(jest.addMatchers({})); expectType(jest.autoMockOff()); @@ -37,6 +38,26 @@ expectType(jest.resetModuleRegistry()); expectType(jest.resetModules()); expectType(jest.isolateModules(() => {})); expectType(jest.retryTimes(3)); +expectType, []>>( + jest + .fn(() => Promise.resolve('string value')) + .mockResolvedValueOnce('A string, not a Promise'), +); +expectType, []>>( + jest + .fn(() => Promise.resolve('string value')) + .mockResolvedValue('A string, not a Promise'), +); +expectType, []>>( + jest + .fn(() => Promise.resolve('string value')) + .mockRejectedValueOnce(new Error('An error, not a string')), +); +expectType, []>>( + jest + .fn(() => Promise.resolve('string value')) + .mockRejectedValue(new Error('An error, not a string')), +); expectType(jest.runAllImmediates()); expectType(jest.runAllTicks());