Merge pull request #32579 from antoinebrault/jest-type-inference

[jest] add type inference
This commit is contained in:
Armando Aguirre
2019-02-04 17:07:44 -08:00
committed by GitHub
16 changed files with 136 additions and 72 deletions
+1 -1
View File
@@ -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" />
+1 -1
View File
@@ -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'/>
+1 -1
View File
@@ -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" />
+1 -1
View File
@@ -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" />
+1 -1
View File
@@ -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" />
+4 -4
View File
@@ -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());
});
@@ -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)';
+1 -1
View File
@@ -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";
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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" />
+1 -1
View File
@@ -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" />
+12 -17
View File
@@ -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;
+10 -6
View File
@@ -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:', () => {
+29 -24
View File
@@ -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;
@@ -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
@@ -114,11 +117,11 @@ 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.
*/
@@ -126,7 +129,7 @@ declare namespace jest {
/**
* 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.
*/
@@ -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).
@@ -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
@@ -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.
*
@@ -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.
@@ -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:
*
@@ -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.
*
@@ -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
@@ -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));`
*
@@ -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));`
*
@@ -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));`
@@ -953,7 +958,7 @@ declare namespace jest {
* });
*
*/
mockRejectedValueOnce(value: any): Mock<T>;
mockRejectedValueOnce(value: any): Mock<Promise<T>, Y>;
}
/**
@@ -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[];
/**
+70 -11
View File
@@ -259,12 +259,43 @@ jest.requireMock("./thisAlwaysReturnsTheMock");
/* Mocks and spies */
const mock1: jest.Mock = jest.fn();
const mock2: jest.Mock<undefined> = jest.fn<undefined>(() => undefined);
const mock3: jest.Mock<string> = jest.fn(() => "abc");
const mock4: jest.Mock<"abc"> = jest.fn((): "abc" => "abc");
const mock5: jest.Mock<string> = jest.fn((...args: string[]) => args.join(""));
const mock6: jest.Mock = jest.fn((arg: {}) => arg);
// $ExpectType Mock<any, any>
const mock1: jest.Mock<number> = jest.fn();
// $ExpectType Mock<undefined, []>
const mock2 = jest.fn(() => undefined);
// $ExpectType Mock<string, []>
const mock3 = jest.fn(() => "abc");
// $ExpectType Mock<"abc", []>
const mock4 = jest.fn((): "abc" => "abc");
// $ExpectType Mock<string, string[]>
const mock5 = jest.fn((...args: string[]) => args.join(""));
// $ExpectType Mock<{}, [{}]>
const mock6 = jest.fn((arg: {}) => arg);
// $ExpectType Mock<number, [number]>
const mock7 = jest.fn((arg: number) => arg);
// $ExpectType Mock<number, [number]>
const mock8: jest.Mock = jest.fn((arg: number) => arg);
// $ExpectType Mock<Promise<boolean>, [number, string, {}, [], boolean]>
const mock9 = jest.fn((a: number, _b: string, _c: {}, _iReallyDontCare: [], _makeItStop: boolean) => Promise.resolve(_makeItStop));
// $ExpectType Mock<never, [never]>
const mock10 = jest.fn((arg: never) => { throw new Error(arg); });
// $ExpectType Mock<unknown, [unknown]>
const mock11 = jest.fn((arg: unknown) => arg);
// $ExpectType number
mock1('test');
// $ExpectError
mock7('abc');
// $ExpectError
mock7.mockImplementation((arg: string) => 1);
// compiles because mock8 is declared as jest.Mock<{}, any>
mock8('abc');
mock8.mockImplementation((arg: string) => 1);
// mockImplementation not required to declare all arguments
mock9.mockImplementation((a: number) => Promise.resolve(a === 0));
const genMockModule1: {} = jest.genMockFromModule("moduleName");
const genMockModule2: { a: "b" } = jest.genMockFromModule<{ a: "b" }>("moduleName");
@@ -278,8 +309,8 @@ if (jest.isMockFunction(maybeMock)) {
}
const mockName: string = jest.fn().getMockName();
const mockContextVoid: jest.MockContext<void> = jest.fn<void>().mock;
const mockContextString: jest.MockContext<string> = jest.fn(() => "").mock;
const mockContextVoid = jest.fn().mock;
const mockContextString = jest.fn(() => "").mock;
jest.fn().mockClear();
@@ -289,14 +320,28 @@ jest.fn().mockRestore();
const spiedTarget = {
returnsVoid(): void { },
setValue(value: string): void {
this.value = value;
},
returnsString(): string {
return "";
}
};
class SpiedTargetClass {
private _value = 3;
get value() {
return this._value;
}
set value(value) {
this._value = value;
}
}
const spiedTarget2 = new SpiedTargetClass();
const spy1 = jest.spyOn(spiedTarget, "returnsVoid");
const spy2 = jest.spyOn(spiedTarget, "returnsVoid", "get");
const spy3 = jest.spyOn(spiedTarget, "returnsString", "set");
const spy3 = jest.spyOn(spiedTarget, "returnsString");
const spy1Name: string = spy1.getMockName();
const spy2Calls: any[][] = spy2.mock.calls;
@@ -304,9 +349,10 @@ const spy2Calls: any[][] = spy2.mock.calls;
spy2.mockClear();
spy2.mockReset();
const spy3Mock: jest.Mock<() => string> = spy3
const spy3Mock = spy3
.mockImplementation(() => "")
.mockImplementation()
// $ExpectError
.mockImplementation((arg: {}) => arg)
.mockImplementation((...args: string[]) => args.join(""))
.mockImplementationOnce(() => "")
@@ -320,10 +366,23 @@ const spy3Mock: jest.Mock<() => string> = spy3
.mockRejectedValueOnce("value");
let spy4: jest.SpyInstance;
// $ExpectType SpyInstance<string, []>
spy4 = jest.spyOn(spiedTarget, "returnsString");
// compiles because spy4 is declared as jest.SpyInstance<any, any>
spy4.mockImplementation(() => 1);
spy4.mockRestore();
// $ExpectType SpyInstance<number, []>
const spy5 = jest.spyOn(spiedTarget2, "value", "get");
// $ExpectError
spy5.mockReturnValue('5');
// $ExpectType SpyInstance<void, [number]>
const spy6 = jest.spyOn(spiedTarget2, "value", "set");
// should compile
jest.fn().mockImplementation((test: number) => test);
/* Snapshot serialization */
const snapshotSerializerPlugin: jest.SnapshotSerializerPlugin = {
+1
View File
@@ -13,6 +13,7 @@
"typeRoots": [
"../"
],
"target": "es5",
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
+1 -1
View File
@@ -2,7 +2,7 @@
// Project: https://github.com/storybooks/storybook/tree/master/addons/storyshots
// Definitions by: Bradley Ayers <https://github.com/bradleyayers>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
// TypeScript Version: 3.0
import * as React from 'react';
import { StoryObject } from '@storybook/react';