New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[jest] add type inference #32579
[jest] add type inference #32579
Changes from 10 commits
f8c68f6
5b6edfa
3fdb22e
b337410
3236add
fd07752
68242a4
0ccaf36
d60a5cb
3b921ef
a0111a9
edd25d0
50942f2
1ba138a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TS ships with a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was added in 3.1 (microsoft/TypeScript@60b4fe9) Thanks for the info. I didn't even know about it since it's not in https://www.typescriptlang.org/docs/handbook/advanced-types.html
|
||
|
||
interface NodeRequire { | ||
/** | ||
* Returns the actual module instead of a mock, bypassing all checks on | ||
|
@@ -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. | ||
*/ | ||
|
@@ -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[]; | ||
/** | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you comment on the change here? Is this because
fn
is now correctly typed?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't know why I did that... I updated the PR.
fn
should be cast to a function because it is unknown