Skip to content

Commit

Permalink
Merge pull request #32579 from antoinebrault/jest-type-inference
Browse files Browse the repository at this point in the history
[jest] add type inference
  • Loading branch information
armanio123 committed Feb 5, 2019
2 parents 1657e86 + 1ba138a commit 9bb7883
Show file tree
Hide file tree
Showing 16 changed files with 136 additions and 72 deletions.
2 changes: 1 addition & 1 deletion types/expect-puppeteer/index.d.ts
Expand Up @@ -3,7 +3,7 @@
// Definitions by: Josh Goldberg <https://github.com/JoshuaKGoldberg>
// Tanguy Krotoff <https://github.com/tkrotoff>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0

/// <reference types="jest" />

Expand Down
2 changes: 1 addition & 1 deletion types/frisby/index.d.ts
Expand Up @@ -3,7 +3,7 @@
// Definitions by: Christopher E. Woodland <https://github.com/cwoodland>
// Johnny Li <https://github.com/johnny4753>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0

/// <reference types='jest'/>

Expand Down
2 changes: 1 addition & 1 deletion types/jest-axe/index.d.ts
Expand Up @@ -2,7 +2,7 @@
// Project: https://github.com/nickcolley/jest-axe
// Definitions by: Josh Goldberg <https://github.com/JoshuaKGoldberg>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.4
// TypeScript Version: 3.0

/// <reference types="jest" />

Expand Down
2 changes: 1 addition & 1 deletion types/jest-image-snapshot/index.d.ts
Expand Up @@ -2,7 +2,7 @@
// Project: https://github.com/americanexpress/jest-image-snapshot#readme
// Definitions by: Janeene Beeforth <https://github.com/dawnmist>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
// TypeScript Version: 3.0

/// <reference types="jest" />

Expand Down
2 changes: 1 addition & 1 deletion types/jest-in-case/index.d.ts
Expand Up @@ -2,7 +2,7 @@
// Project: https://github.com/thinkmill/jest-in-case#readme
// Definitions by: Geovani de Souza <https://github.com/geovanisouza92>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
// TypeScript Version: 3.0

/// <reference types="jest" />
/// <reference types="node" />
Expand Down
8 changes: 4 additions & 4 deletions types/jest-in-case/jest-in-case-tests.ts
Expand Up @@ -11,8 +11,8 @@ function subtract(minuend: number, subtrahend: number) {
}

beforeEach(() => {
jest.spyOn(global, 'describe').mockImplementation((title, fn) => fn());
jest.spyOn(global, 'test').mockImplementation((name, fn) => fn());
jest.spyOn(global, 'describe').mockImplementation((title, fn) => (fn as () => void)());
jest.spyOn(global, 'test').mockImplementation((name, fn) => (fn as () => void)());
global.test.skip = jest.fn((name, fn) => fn());
global.test.only = jest.fn((name, fn) => fn());
});
Expand Down Expand Up @@ -54,8 +54,8 @@ test('array', () => {
});

test('object', () => {
jest.spyOn(global, 'describe').mockImplementation((title, fn) => fn());
jest.spyOn(global, 'test').mockImplementation((name, fn) => fn());
jest.spyOn(global, 'describe').mockImplementation((title, fn) => (fn as () => void)());
jest.spyOn(global, 'test').mockImplementation((name, fn) => (fn as () => void)());

const title = 'add(augend, addend)';

Expand Down
2 changes: 1 addition & 1 deletion types/jest-json-schema/index.d.ts
Expand Up @@ -2,7 +2,7 @@
// Project: https://github.com/americanexpress/jest-json-schema#readme
// Definitions by: Igor Korolev <https://github.com/deadNightTiger>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
// TypeScript Version: 3.0

/// <reference types="jest" />
import * as ajv from "ajv";
Expand Down
2 changes: 1 addition & 1 deletion types/jest-matchers/index.d.ts
Expand Up @@ -2,7 +2,7 @@
// Project: https://github.com/facebook/jest#readme
// Definitions by: Joscha Feth <https://github.com/joscha>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
// TypeScript Version: 3.0

/// <reference types="jest" />
export = expect;
2 changes: 1 addition & 1 deletion types/jest-plugin-context/index.d.ts
Expand Up @@ -2,7 +2,7 @@
// Project: https://github.com/negativetwelve/jest-plugins/tree/master/packages/jest-plugin-context
// Definitions by: Jonas Heinrich <https://github.com/jonasheinrich>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
// TypeScript Version: 3.0

/// <reference types="jest" />

Expand Down
2 changes: 1 addition & 1 deletion types/jest-specific-snapshot/index.d.ts
Expand Up @@ -2,7 +2,7 @@
// Project: https://github.com/igor-dv/jest-specific-snapshot#readme
// Definitions by: Janeene Beeforth <https://github.com/dawnmist>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0

/// <reference types="jest" />

Expand Down
29 changes: 12 additions & 17 deletions types/jest-when/index.d.ts
Expand Up @@ -2,26 +2,21 @@
// Project: https://github.com/timkindberg/jest-when#readme
// Definitions by: Alden Taylor <https://github.com/aldentaylor>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
// TypeScript Version: 3.0

/// <reference types="jest" />

export interface When {
<T>(fn: jest.Mocked<T> | jest.Mock<T>): When;

// due to no-unnecessary-generics lint rule, the generics have been replaced with 'any'
// calledWith<T>(...matchers: any[]): PartialMockInstance<T>;
// expectCalledWith<T>(...matchers: any[]): PartialMockInstance<T>;
calledWith(...matchers: any[]): When;

expectCalledWith(...matchers: any[]): When;

mockReturnValue: (value: any) => jest.MockInstance<any>['mockReturnValue'] & When;
mockReturnValueOnce: (value: any) => jest.MockInstance<any>['mockReturnValue'] & When;
mockResolvedValue: (value: any) => jest.MockInstance<any>['mockReturnValue'] & When;
mockResolvedValueOnce: (value: any) => jest.MockInstance<any>['mockReturnValue'] & When;
mockRejectedValue: (value: any) => jest.MockInstance<any>['mockReturnValue'] & When;
mockRejectedValueOnce: (value: any) => jest.MockInstance<any>['mockReturnValue'] & When;
export interface WhenMock<T = any, Y extends any[] = any> extends jest.Mock<T, Y> {
calledWith(...matchers: Y): WhenMock<T, Y>;
expectCalledWith(...matchers: Y): WhenMock<T, Y>;
mockReturnValue(value: T): WhenMock<T, Y>;
mockReturnValueOnce(value: T): WhenMock<T, Y>;
mockResolvedValue(value: T | PromiseLike<T>): WhenMock<Promise<T>, Y>;
mockResolvedValueOnce(value: T | PromiseLike<T>): WhenMock<Promise<T>, Y>;
mockRejectedValue(value: T | PromiseLike<T>): WhenMock<Promise<T>, Y>;
mockRejectedValueOnce(value: T | PromiseLike<T>): WhenMock<Promise<T>, Y>;
}

export type When = <T, Y extends any[]>(fn: jest.Mock<T, Y>) => WhenMock<T, Y>;

export const when: When;
16 changes: 10 additions & 6 deletions types/jest-when/jest-when-tests.ts
Expand Up @@ -31,16 +31,20 @@ describe('mock-when test', () => {

it('Supports compound declarations:', () => {
const fn = jest.fn();
when(fn).calledWith(1).mockReturnValue('no');
when(fn).calledWith(1).mockReturnValueOnce('no').mockReturnValue('yes');
when(fn).calledWith(2).mockReturnValue('way?');
when(fn).calledWith(3).mockReturnValue('yes');
when(fn).calledWith(4).mockReturnValue('way!');
when(fn).calledWith(3).mockResolvedValueOnce('no');
when(fn).calledWith(3).mockResolvedValue('yes');
when(fn).calledWith(4).mockRejectedValueOnce('no');
when(fn).calledWith(4).mockRejectedValue('yes');

expect(fn(1)).toEqual('no');
expect(fn(1)).toEqual('yes');
expect(fn(2)).toEqual('way?');
expect(fn(3)).toEqual('yes');
expect(fn(4)).toEqual('way!');
expect(fn(5)).toEqual(undefined);
expect(fn(3)).resolves.toEqual('no');
expect(fn(3)).resolves.toEqual('yes');
expect(fn(4)).rejects.toEqual('no');
expect(fn(4)).rejects.toEqual('yes');
});

it('Supports chained calls:', () => {
Expand Down
53 changes: 29 additions & 24 deletions types/jest/index.d.ts
Expand Up @@ -17,8 +17,9 @@
// Martin Hochel <https://github.com/hotell>
// Sebastian Sebald <https://github.com/sebald>
// Andy <https://github.com/andys8>
// Antoine Brault <https://github.com/antoinebrault>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
// TypeScript Version: 3.0

declare var beforeAll: jest.Lifecycle;
declare var beforeEach: jest.Lifecycle;
Expand All @@ -35,6 +36,8 @@ declare var xtest: jest.It;

declare const expect: jest.Expect;

type ArgsType<T> = T extends (...args: infer A) => any ? A : never;

interface NodeRequire {
/**
* Returns the actual module instead of a mock, bypassing all checks on
Expand Down Expand Up @@ -114,19 +117,19 @@ declare namespace jest {
/**
* Creates a mock function. Optionally takes a mock implementation.
*/
function fn<T extends {}>(implementation: (...args: any[]) => T): Mock<T>;
function fn(): Mock;
/**
* Creates a mock function. Optionally takes a mock implementation.
*/
function fn<T>(implementation?: (...args: any[]) => any): Mock<T>;
function fn<T, Y extends any[]>(implementation: (...args: Y) => T): Mock<T, Y>;
/**
* Use the automatic mocking system to generate a mocked version of the given module.
*/
function genMockFromModule<T>(moduleName: string): T;
/**
* Returns whether the given function is a mock function.
*/
function isMockFunction(fn: any): fn is Mock<any>;
function isMockFunction(fn: any): fn is Mock;
/**
* Mocks a module with an auto-mocked version when it is being required.
*/
Expand Down Expand Up @@ -212,7 +215,9 @@ declare namespace jest {
* spy.mockRestore();
* });
*/
function spyOn<T extends {}, M extends keyof T>(object: T, method: M, accessType?: 'get' | 'set'): SpyInstance<T[M]>;
function spyOn<T extends {}, M extends keyof T>(object: T, method: M, accessType: 'get'): SpyInstance<T[M], []>;
function spyOn<T extends {}, M extends keyof T>(object: T, method: M, accessType: 'set'): SpyInstance<void, [T[M]]>;
function spyOn<T extends {}, M extends keyof T>(object: T, method: M): T[M] extends (...args: any[]) => any ? SpyInstance<ReturnType<T[M]>, ArgsType<T[M]>> : never;
/**
* Indicates that the module system should never return a mocked version of
* the specified module from require() (e.g. that it should always return the real module).
Expand Down Expand Up @@ -776,12 +781,12 @@ declare namespace jest {
new (...args: any[]): any;
}

interface Mock<T = {}> extends Function, MockInstance<T> {
new (...args: any[]): T;
(...args: any[]): any;
interface Mock<T = any, Y extends any[] = any> extends Function, MockInstance<T, Y> {
new (...args: Y): T;
(...args: Y): T;
}

interface SpyInstance<T = {}> extends MockInstance<T> {}
interface SpyInstance<T = any, Y extends any[] = any> extends MockInstance<T, Y> {}

/**
* Wrap module with mock definitions
Expand All @@ -795,14 +800,14 @@ declare namespace jest {
* myApi.myApiMethod.mockImplementation(() => "test");
*/
type Mocked<T> = {
[P in keyof T]: T[P] & MockInstance<T[P]>;
[P in keyof T]: T[P] & MockInstance<T[P], ArgsType<T[P]>>;
} & T;

interface MockInstance<T> {
interface MockInstance<T, Y extends any[]> {
/** Returns the mock name string set by calling `mockFn.mockName(value)`. */
getMockName(): string;
/** Provides access to the mock's metadata */
mock: MockContext<T>;
mock: MockContext<T, Y>;
/**
* Resets all information stored in the mockFn.mock.calls and mockFn.mock.instances arrays.
*
Expand Down Expand Up @@ -842,7 +847,7 @@ declare namespace jest {
*
* Note: `jest.fn(implementation)` is a shorthand for `jest.fn().mockImplementation(implementation)`.
*/
mockImplementation(fn?: (...args: any[]) => any): Mock<T>;
mockImplementation(fn?: (...args: Y) => T): Mock<T, Y>;
/**
* Accepts a function that will be used as an implementation of the mock for one call to the mocked function.
* Can be chained so that multiple function calls produce different results.
Expand All @@ -858,9 +863,9 @@ declare namespace jest {
*
* myMockFn((err, val) => console.log(val)); // false
*/
mockImplementationOnce(fn: (...args: any[]) => any): Mock<T>;
mockImplementationOnce(fn: (...args: Y) => T): Mock<T, Y>;
/** Sets the name of the mock`. */
mockName(name: string): Mock<T>;
mockName(name: string): Mock<T, Y>;
/**
* Just a simple sugar function for:
*
Expand All @@ -870,7 +875,7 @@ declare namespace jest {
* return this;
* });
*/
mockReturnThis(): Mock<T>;
mockReturnThis(): Mock<T, Y>;
/**
* Accepts a value that will be returned whenever the mock function is called.
*
Expand All @@ -882,7 +887,7 @@ declare namespace jest {
* mock.mockReturnValue(43);
* mock(); // 43
*/
mockReturnValue(value: any): Mock<T>;
mockReturnValue(value: T): Mock<T, Y>;
/**
* Accepts a value that will be returned for one call to the mock function. Can be chained so that
* successive calls to the mock function return different values. When there are no more
Expand All @@ -899,11 +904,11 @@ declare namespace jest {
* console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
*
*/
mockReturnValueOnce(value: any): Mock<T>;
mockReturnValueOnce(value: T): Mock<T, Y>;
/**
* Simple sugar function for: `jest.fn().mockImplementation(() => Promise.resolve(value));`
*/
mockResolvedValue(value: any): Mock<T>;
mockResolvedValue(value: T | PromiseLike<T>): Mock<Promise<T>, Y>;
/**
* Simple sugar function for: `jest.fn().mockImplementationOnce(() => Promise.resolve(value));`
*
Expand All @@ -923,7 +928,7 @@ declare namespace jest {
* });
*
*/
mockResolvedValueOnce(value: any): Mock<T>;
mockResolvedValueOnce(value: T | PromiseLike<T>): Mock<Promise<T>, Y>;
/**
* Simple sugar function for: `jest.fn().mockImplementation(() => Promise.reject(value));`
*
Expand All @@ -935,7 +940,7 @@ declare namespace jest {
* await asyncMock(); // throws "Async error"
* });
*/
mockRejectedValue(value: any): Mock<T>;
mockRejectedValue(value: any): Mock<Promise<T>, Y>;

/**
* Simple sugar function for: `jest.fn().mockImplementationOnce(() => Promise.reject(value));`
Expand All @@ -953,7 +958,7 @@ declare namespace jest {
* });
*
*/
mockRejectedValueOnce(value: any): Mock<T>;
mockRejectedValueOnce(value: any): Mock<Promise<T>, Y>;
}

/**
Expand All @@ -971,8 +976,8 @@ declare namespace jest {
value: any;
}

interface MockContext<T> {
calls: any[][];
interface MockContext<T, Y extends any[]> {
calls: Y[];
instances: T[];
invocationCallOrder: number[];
/**
Expand Down

0 comments on commit 9bb7883

Please sign in to comment.