Skip to content

Commit

Permalink
馃 Merge PR #62781 [jest] add jest.Spied* utility types by @mrazauskas
Browse files Browse the repository at this point in the history
* [jest] add `jest.Spied*` utility types

* add me to code owners list
  • Loading branch information
mrazauskas committed Nov 4, 2022
1 parent 0922549 commit 2084c7d
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 8 deletions.
46 changes: 38 additions & 8 deletions types/jest/index.d.ts
Expand Up @@ -26,6 +26,7 @@
// Pawel Fajfer <https://github.com/pawfa>
// Alexandre Germain <https://github.com/gerkindev>
// Adam Jones <https://github.com/domdomegg>
// Tom Mrazauskas <https://github.com/mrazauskas>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Minimum TypeScript Version: 4.3

Expand Down Expand Up @@ -389,18 +390,18 @@ declare namespace jest {
: Value extends Func
? SpyInstance<ReturnType<Value>, ArgsType<Value>>
: never;
function spyOn<T extends {}, M extends FunctionPropertyNames<Required<T>>>(
object: T,
method: M,
): FunctionProperties<Required<T>>[M] extends Func
? SpyInstance<ReturnType<FunctionProperties<Required<T>>[M]>, ArgsType<FunctionProperties<Required<T>>[M]>>
: never;
function spyOn<T extends {}, M extends ConstructorPropertyNames<Required<T>>>(
object: T,
method: M,
): Required<T>[M] extends new (...args: any[]) => any
? SpyInstance<InstanceType<Required<T>[M]>, ConstructorArgsType<Required<T>[M]>>
: never;
function spyOn<T extends {}, M extends FunctionPropertyNames<Required<T>>>(
object: T,
method: M,
): FunctionProperties<Required<T>>[M] extends Func
? SpyInstance<ReturnType<FunctionProperties<Required<T>>[M]>, ArgsType<FunctionProperties<Required<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 @@ -1166,9 +1167,38 @@ declare namespace jest {
interface SpyInstance<T = any, Y extends any[] = any> extends MockInstance<T, Y> {}

/**
* Represents a function that has been spied on.
* Constructs the type of a spied class.
*/
type SpiedFunction<T extends (...args: any[]) => any> = SpyInstance<ReturnType<T>, ArgsType<T>>;
type SpiedClass<T extends abstract new (...args: any) => any> = SpyInstance<
InstanceType<T>,
ConstructorParameters<T>
>;

/**
* Constructs the type of a spied function.
*/
type SpiedFunction<T extends (...args: any) => any> = SpyInstance<ReturnType<T>, ArgsType<T>>;

/**
* Constructs the type of a spied getter.
*/
type SpiedGetter<T> = SpyInstance<T, []>;

/**
* Constructs the type of a spied setter.
*/
type SpiedSetter<T> = SpyInstance<void, [T]>;

/**
* Constructs the type of a spied class or function.
*/
type Spied<T extends (abstract new (...args: any) => any) | ((...args: any) => any)> = T extends abstract new (
...args: any
) => any
? SpiedClass<T>
: T extends (...args: any) => any
? SpiedFunction<T>
: never;

/**
* Wrap a function with mock definitions
Expand Down
15 changes: 15 additions & 0 deletions types/jest/jest-tests.ts
Expand Up @@ -674,6 +674,21 @@ jest.spyOn(spyWithIndexSignatureImpl, 'prop');
// $ExpectType SpyInstance<{ some: string; }, []>
jest.spyOn(spyWithIndexSignatureImpl, 'prop', 'get');

let typedSpy: jest.Spied<typeof spiedTarget.returnsVoid>;
typedSpy = jest.spyOn(spiedTarget, 'returnsVoid');

let typedSpy1: jest.SpiedClass<typeof globalThis.Date>;
typedSpy1 = jest.spyOn(globalThis, 'Date');

let typedSpy2: jest.SpiedFunction<typeof spiedTarget.setValue>;
typedSpy2 = jest.spyOn(spiedTarget, 'setValue');

let typedSpy3: jest.SpiedGetter<typeof spiedTarget2.value>;
typedSpy3 = jest.spyOn(spiedTarget2, 'value', 'get');

let typedSpy4: jest.SpiedSetter<typeof spiedTarget2.value>;
typedSpy4 = jest.spyOn(spiedTarget2, 'value', 'set');

// $ExpectType MockedObjectDeep<{}>
jest.mocked({});
// $ExpectType MockedObjectDeep<{}>
Expand Down

0 comments on commit 2084c7d

Please sign in to comment.