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

[jest] fix type inference for Mocked & mockResolvedValue/mockRejectedValue
This commit is contained in:
Mine Starks
2019-02-12 11:28:42 -08:00
committed by GitHub
3 changed files with 67 additions and 11 deletions
+4 -4
View File
@@ -11,10 +11,10 @@ export interface WhenMock<T = any, Y extends any[] = any> extends jest.Mock<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>;
mockResolvedValue(value: jest.ResolvedValue<T>): WhenMock<T, Y>;
mockResolvedValueOnce(value: jest.ResolvedValue<T>): WhenMock<T, Y>;
mockRejectedValue(value: jest.RejectedValue<T>): WhenMock<T, Y>;
mockRejectedValueOnce(value: jest.RejectedValue<T>): WhenMock<T, Y>;
}
export type When = <T, Y extends any[]>(fn: jest.Mock<T, Y>) => WhenMock<T, Y>;
+8 -7
View File
@@ -36,8 +36,6 @@ 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
@@ -237,6 +235,9 @@ declare namespace jest {
}
type EmptyFunction = () => void;
type ArgsType<T> = T extends (...args: infer A) => any ? A : never;
type RejectedValue<T> = T extends PromiseLike<any> ? any : never;
type ResolvedValue<T> = T extends PromiseLike<infer U> ? U | T : never;
// see https://github.com/Microsoft/TypeScript/issues/25215
type NonFunctionPropertyNames<T> = { [K in keyof T]: T[K] extends (...args: any[]) => any ? never : K }[keyof T] & string;
type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never }[keyof T] & string;
@@ -807,7 +808,7 @@ declare namespace jest {
* myApi.myApiMethod.mockImplementation(() => "test");
*/
type Mocked<T> = {
[P in keyof T]: T[P] & MockInstance<T[P], ArgsType<T[P]>>;
[P in keyof T]: T[P] extends (...args: any[]) => any ? MockInstance<ReturnType<T[P]>, ArgsType<T[P]>>: T[P];
} & T;
interface MockInstance<T, Y extends any[]> {
@@ -915,7 +916,7 @@ declare namespace jest {
/**
* Simple sugar function for: `jest.fn().mockImplementation(() => Promise.resolve(value));`
*/
mockResolvedValue(value: T | PromiseLike<T>): Mock<Promise<T>, Y>;
mockResolvedValue(value: ResolvedValue<T>): Mock<T, Y>;
/**
* Simple sugar function for: `jest.fn().mockImplementationOnce(() => Promise.resolve(value));`
*
@@ -935,7 +936,7 @@ declare namespace jest {
* });
*
*/
mockResolvedValueOnce(value: T | PromiseLike<T>): Mock<Promise<T>, Y>;
mockResolvedValueOnce(value: ResolvedValue<T>): Mock<T, Y>;
/**
* Simple sugar function for: `jest.fn().mockImplementation(() => Promise.reject(value));`
*
@@ -947,7 +948,7 @@ declare namespace jest {
* await asyncMock(); // throws "Async error"
* });
*/
mockRejectedValue(value: any): Mock<Promise<T>, Y>;
mockRejectedValue(value: RejectedValue<T>): Mock<T, Y>;
/**
* Simple sugar function for: `jest.fn().mockImplementationOnce(() => Promise.reject(value));`
@@ -965,7 +966,7 @@ declare namespace jest {
* });
*
*/
mockRejectedValueOnce(value: any): Mock<Promise<T>, Y>;
mockRejectedValueOnce(value: RejectedValue<T>): Mock<T, Y>;
}
/**
+55
View File
@@ -423,6 +423,61 @@ const spy6 = jest.spyOn(spiedTarget2, "value", "set");
// should compile
jest.fn().mockImplementation((test: number) => test);
jest.fn().mockResolvedValue(1);
interface Type1 { a: number; }
interface Type2 { b: number; }
class TestMocked {
field: string;
test1(x: Type1): Promise<Type1> {
return Promise.resolve(x);
}
test2(x: Promise<Type1>): Promise<Type1> {
return x;
}
test3(x: Promise<Type1>): Promise<Type2> {
return x.then(() => ({ b: 1 }));
}
test4(x: Type1): Type1 {
return x;
}
}
const mocked: jest.Mocked<TestMocked> = new TestMocked() as any;
mocked.test1.mockImplementation(() => Promise.resolve({ a: 1 }));
mocked.test1.mockReturnValue(Promise.resolve({ a: 1 }));
// $ExpectType Mock<Promise<Type1>, [Type1]>
mocked.test1.mockResolvedValue({ a: 1 });
mocked.test1.mockResolvedValueOnce({ a: 1 });
// $ExpectType Mock<Promise<Type1>, [Type1]>
mocked.test1.mockResolvedValue(Promise.resolve({ a: 1 }));
mocked.test1.mockResolvedValueOnce(Promise.resolve({ a: 1 }));
// $ExpectType Mock<Promise<Type1>, [Promise<Type1>]>
mocked.test2.mockResolvedValue({ a: 1 });
mocked.test2.mockResolvedValueOnce({ a: 1 });
// $ExpectType Mock<Promise<Type1>, [Promise<Type1>]>
mocked.test2.mockResolvedValue(Promise.resolve({ a: 1 }));
mocked.test2.mockResolvedValueOnce(Promise.resolve({ a: 1 }));
// $ExpectType Mock<Promise<Type2>, [Promise<Type1>]>
mocked.test3.mockResolvedValue({ b: 1 });
mocked.test3.mockResolvedValueOnce({ b: 1 });
// $ExpectType Mock<Promise<Type2>, [Promise<Type1>]>
mocked.test3.mockResolvedValue(Promise.resolve({ b: 1 }));
mocked.test3.mockResolvedValueOnce(Promise.resolve({ b: 1 }));
mocked.test3.mockRejectedValue(new Error());
mocked.test3.mockRejectedValueOnce(new Error());
// $ExpectError
mocked.test4.mockResolvedValue({ a: 1 });
// $ExpectError
mocked.test4.mockResolvedValueOnce({ a: 1 });
// $ExpectError
mocked.test4.mockResolvedValue(Promise.resolve({ a: 1 }));
// $ExpectError
mocked.test4.mockResolvedValueOnce(Promise.resolve({ a: 1 }));
// $ExpectError
mocked.test4.mockRejectedValue(new Error());
// $ExpectError
mocked.test4.mockRejectedValueOnce(new Error());
/* Snapshot serialization */