Skip to content

Commit

Permalink
Merge pull request #73 from mopinsk/master
Browse files Browse the repository at this point in the history
  • Loading branch information
shairez authored Jun 3, 2023
2 parents d049be4 + d1ffbac commit 452868d
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ function createReplaySubject<T>(): ReplaySubject<T> {
return new ReplaySubject(1);
}

function addNextWithPerCall<T>(
function addNextWithPerCall(
objectToDecorate: any,
returnValueContainer: ReturnValueContainer,
onValuesPerCallConfigured: (
Expand Down
25 changes: 17 additions & 8 deletions packages/auto-spies-core/src/observables/observable-spy.types.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
import { Subject } from 'rxjs';
import { ValueConfigPerCall } from '../auto-spies-core.types';
import { Observable, Subject } from 'rxjs';
import { Func, ValueConfigPerCall } from '../auto-spies-core.types';

export type CreateObservableAutoSpy<
LibSpecificFunctionSpy,
LibSpecificFunctionSpyWithObservableMethods,
ObservableReturnType
Method extends Func
> = LibSpecificFunctionSpy &
LibSpecificFunctionSpyWithObservableMethods &
AddCalledWithToObservableFunctionSpy<ObservableReturnType>;
AddCalledWithToObservableFunctionSpy<Method>;

export type AddCalledWithToObservableFunctionSpy<ObservableReturnType> = {
calledWith(...args: any[]): AddObservableSpyMethods<ObservableReturnType>;
mustBeCalledWith(...args: any[]): AddObservableSpyMethods<ObservableReturnType>;
};
export type AddCalledWithToObservableFunctionSpy<Method extends Func> = Method &
(Method extends (...args: any[]) => infer ReturnType
? ReturnType extends Observable<infer ObservableReturnType>
? {
calledWith(
...args: Parameters<Method>
): AddObservableSpyMethods<ObservableReturnType>;
mustBeCalledWith(
...args: Parameters<Method>
): AddObservableSpyMethods<ObservableReturnType>;
}
: never
: never);

export interface AddObservableSpyMethods<T> {
nextWith(value?: T): void;
Expand Down
23 changes: 16 additions & 7 deletions packages/auto-spies-core/src/promises/promises-spy.types.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import { ValueConfigPerCall } from '../auto-spies-core.types';
import { Func, ValueConfigPerCall } from '../auto-spies-core.types';

export type CreatePromiseAutoSpy<
LibSpecificFunctionSpy,
LibSpecificFunctionSpyWithPromisesMethods,
PromiseReturnType
Method extends Func
> = LibSpecificFunctionSpy &
LibSpecificFunctionSpyWithPromisesMethods &
AddCalledWithToPromiseFunctionSpy<PromiseReturnType>;
AddCalledWithToPromiseFunctionSpy<Method>;

export type AddCalledWithToPromiseFunctionSpy<PromiseReturnType> = {
calledWith(...args: any[]): AddPromiseSpyMethods<PromiseReturnType>;
mustBeCalledWith(...args: any[]): AddPromiseSpyMethods<PromiseReturnType>;
};
export type AddCalledWithToPromiseFunctionSpy<Method extends Func> = Method &
(Method extends (...args: any[]) => infer ReturnType
? ReturnType extends Promise<infer PromiseReturnType>
? {
calledWith(
...args: Parameters<Method>
): AddPromiseSpyMethods<PromiseReturnType>;
mustBeCalledWith(
...args: Parameters<Method>
): AddPromiseSpyMethods<PromiseReturnType>;
}
: never
: never);

export interface AddPromiseSpyMethods<T> {
resolveWith(value?: T): void;
Expand Down
2 changes: 1 addition & 1 deletion packages/jasmine-auto-spies/src/create-function-spy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ type JasmineCalledWithObject = { returnValue: (...args: any[]) => void };

export function createFunctionSpy<FunctionType extends Func>(
name: string
): AddSpyMethodsByReturnTypes<FunctionType, jasmine.Spy> {
): AddSpyMethodsByReturnTypes<FunctionType> {
return createFunctionAutoSpy(
name,
addJasmineSyncMethodsToCalledWithObject,
Expand Down
37 changes: 15 additions & 22 deletions packages/jasmine-auto-spies/src/jasmine-auto-spies.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import {
CreatePromiseAutoSpy,
} from '@hirez_io/auto-spies-core';

export type Spy<ClassToSpyOn> = AddAutoSpies<ClassToSpyOn, jasmine.Spy> &
export type Spy<ClassToSpyOn> = AddJasmineAutoSpies<ClassToSpyOn> &
AddAccessorsSpies<ClassToSpyOn, jasmine.Spy>;

type AddAutoSpies<ClassToSpyOn, LibSpecificFunctionSpy> = {
type AddJasmineAutoSpies<ClassToSpyOn> = {
[Key in keyof ClassToSpyOn /*
if it's a method */]: ClassToSpyOn[Key] extends Func
? AddSpyMethodsByReturnTypes<ClassToSpyOn[Key], LibSpecificFunctionSpy>
? AddSpyMethodsByReturnTypes<ClassToSpyOn[Key]>
: // if it's a property of type Observable
ClassToSpyOn[Key] extends Observable<infer ObservableReturnType>
? ClassToSpyOn[Key] & AddObservableSpyMethods<ObservableReturnType>
Expand All @@ -25,30 +25,27 @@ type AddAutoSpies<ClassToSpyOn, LibSpecificFunctionSpy> = {
};

// Wrap the return type of the given function type with the appropriate spy methods
export type AddSpyMethodsByReturnTypes<
Method extends Func,
LibSpecificFunctionSpy
> = Method &
export type AddSpyMethodsByReturnTypes<Method extends Func> = Method &
(Method extends (...args: any[]) => infer ReturnType
? // returns a Promise
ReturnType extends Promise<infer PromiseReturnType>
? CreatePromiseAutoSpy<
LibSpecificFunctionSpy,
jasmine.Spy<Method>,
AddPromisesToJasmineFunctionSpy<PromiseReturnType>,
PromiseReturnType
Method
>
: // returns an Observable
ReturnType extends Observable<infer ObservableReturnType>
? CreateObservableAutoSpy<
LibSpecificFunctionSpy,
jasmine.Spy<Method>,
AddObservablesToJasmineFunctionSpy<ObservableReturnType>,
ObservableReturnType
Method
>
: // for any other type
CreateSyncAutoSpy<
Method,
LibSpecificFunctionSpy,
AddCalledWithToJasmineFunctionSpy
jasmine.Spy<Method>,
AddCalledWithToJasmineFunctionSpy<Method>
>
: never);

Expand All @@ -60,15 +57,11 @@ type AddObservablesToJasmineFunctionSpy<ObservableReturnType> = {
and: AddObservableSpyMethods<ObservableReturnType>;
};

export interface AddCalledWithToJasmineFunctionSpy {
calledWith(
...args: any[]
): {
returnValue: (value: any) => void;
export interface AddCalledWithToJasmineFunctionSpy<Method extends Func> {
calledWith(...args: Parameters<Method>): {
returnValue: (value: ReturnType<Method>) => void;
};
mustBeCalledWith(
...args: any[]
): {
returnValue: (value: any) => void;
mustBeCalledWith(...args: Parameters<Method>): {
returnValue: (value: ReturnType<Method>) => void;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,11 @@ describe('createSpyFromClass', () => {
WHEN called with the matching parameters`, () => {
Given(() => {
fakeArgs = [1, { a: 2 }];
fakeClassSpy.getSyncValue.calledWith(...fakeArgs).returnValue(null);
fakeClassSpy.getNullableSyncValue.calledWith(...fakeArgs).returnValue(null);
});

When(() => {
actualResult = fakeClassSpy.getSyncValue(...fakeArgs);
actualResult = fakeClassSpy.getNullableSyncValue(...fakeArgs);
});

Then('return null', () => {
Expand Down
13 changes: 9 additions & 4 deletions packages/jasmine-auto-spies/src/tests/fake-classes-to-test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Observable, of, Subject } from 'rxjs';

export class FakeClass {
Expand All @@ -10,23 +11,27 @@ export class FakeClass {
return this.observableProp;
}

public getSyncValue(): string {
public getSyncValue(..._args: any[]): string {
return '';
}

public getNullableSyncValue(..._args: any[]): string | null {
return '';
}

public getPromise(): Promise<any> {
public getPromise(..._args: any[]): Promise<any> {
return Promise.resolve();
}

public getObservable(): Observable<any> {
public getObservable(..._args: any[]): Observable<any> {
return of();
}

public getSubject(): Subject<any> {
return new Subject();
}

public arrowMethod: () => void = () => {};
public arrowMethod: () => string = () => '';
}

export class FakeChildClass extends FakeClass {
Expand Down
2 changes: 1 addition & 1 deletion packages/jest-auto-spies/src/create-function-spy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ type JestCalledWithObject = { mockReturnValue: (...args: any[]) => void };

export function createFunctionSpy<FunctionType extends Func>(
name: string
): AddSpyMethodsByReturnTypes<FunctionType, jasmine.Spy> {
): AddSpyMethodsByReturnTypes<FunctionType> {
return createFunctionAutoSpy(
name,
addJestSyncMethodsToCalledWithObject,
Expand Down
39 changes: 18 additions & 21 deletions packages/jest-auto-spies/src/jest-auto-spies.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import {
CreatePromiseAutoSpy,
} from '@hirez_io/auto-spies-core';

export type Spy<ClassToSpyOn> = AddAutoSpies<ClassToSpyOn, jest.Mock> &
export type Spy<ClassToSpyOn> = AddJestAutoSpies<ClassToSpyOn> &
AddAccessorsSpies<ClassToSpyOn, jest.Mock>;

type AddAutoSpies<ClassToSpyOn, LibSpecificFunctionSpy> = {
type AddJestAutoSpies<ClassToSpyOn> = {
[Key in keyof ClassToSpyOn /*
if it's a method */]: ClassToSpyOn[Key] extends Func
? AddSpyMethodsByReturnTypes<ClassToSpyOn[Key], LibSpecificFunctionSpy>
? AddSpyMethodsByReturnTypes<ClassToSpyOn[Key]>
: // if it's a property of type Observable
ClassToSpyOn[Key] extends Observable<infer ObservableReturnType>
? ClassToSpyOn[Key] & AddObservableSpyMethods<ObservableReturnType>
Expand All @@ -24,38 +24,35 @@ type AddAutoSpies<ClassToSpyOn, LibSpecificFunctionSpy> = {
};

// Wrap the return type of the given function type with the appropriate spy methods
export type AddSpyMethodsByReturnTypes<
Method extends Func,
LibSpecificFunctionSpy
> = Method &
export type AddSpyMethodsByReturnTypes<Method extends Func> = Method &
(Method extends (...args: any[]) => infer ReturnType
? // returns a Promise
ReturnType extends Promise<infer PromiseReturnType>
? CreatePromiseAutoSpy<
LibSpecificFunctionSpy,
jest.MockedFunction<Method>,
AddPromiseSpyMethods<PromiseReturnType>,
PromiseReturnType
Method
>
: // returns an Observable
ReturnType extends Observable<infer ObservableReturnType>
? CreateObservableAutoSpy<
LibSpecificFunctionSpy,
jest.MockedFunction<Method>,
AddObservableSpyMethods<ObservableReturnType>,
ObservableReturnType
Method
>
: // for any other type
CreateSyncAutoSpy<Method, LibSpecificFunctionSpy, AddCalledWithToJestFunctionSpy>
CreateSyncAutoSpy<
Method,
jest.MockedFunction<Method>,
AddCalledWithToJestFunctionSpy<Method>
>
: never);

export interface AddCalledWithToJestFunctionSpy {
calledWith(
...args: any[]
): {
mockReturnValue: (value: any) => void;
export interface AddCalledWithToJestFunctionSpy<Method extends Func> {
calledWith(...args: Parameters<Method>): {
mockReturnValue: (value: ReturnType<Method>) => void;
};
mustBeCalledWith(
...args: any[]
): {
mockReturnValue: (value: any) => void;
mustBeCalledWith(...args: Parameters<Method>): {
mockReturnValue: (value: ReturnType<Method>) => void;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,11 @@ describe('createSpyFromClass', () => {
WHEN called with the matching parameters`, () => {
Given(() => {
fakeArgs = [1, { a: 2 }];
fakeClassSpy.getSyncValue.calledWith(...fakeArgs).mockReturnValue(null);
fakeClassSpy.getNullableSyncValue.calledWith(...fakeArgs).mockReturnValue(null);
});

When(() => {
actualResult = fakeClassSpy.getSyncValue(...fakeArgs);
actualResult = fakeClassSpy.getNullableSyncValue(...fakeArgs);
});

Then('return null', () => {
Expand Down
13 changes: 9 additions & 4 deletions packages/jest-auto-spies/src/tests/fake-classes-to-test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-empty-function */
import { Observable, of, Subject } from 'rxjs';

Expand All @@ -10,23 +11,27 @@ export class FakeClass {
return this.observableProp;
}

public getSyncValue(): string {
public getSyncValue(..._args: any[]): string {
return '';
}

public getNullableSyncValue(..._args: any[]): string | null {
return '';
}

public getPromise(): Promise<any> {
public getPromise(..._args: any[]): Promise<any> {
return Promise.resolve();
}

public getObservable(): Observable<any> {
public getObservable(..._args: any[]): Observable<any> {
return of();
}

public getSubject(): Subject<any> {
return new Subject();
}

public arrowMethod: () => void = () => {};
public arrowMethod: () => string = () => '';
}

export class FakeChildClass extends FakeClass {
Expand Down

0 comments on commit 452868d

Please sign in to comment.