Skip to content

Commit

Permalink
fix: generic type constraint for ngMocks.stub tedious to write
Browse files Browse the repository at this point in the history
closes #166
  • Loading branch information
satanTime committed Sep 30, 2020
1 parent d108927 commit 39d9be7
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 47 deletions.
21 changes: 1 addition & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,7 @@ const spySet: Function = ngMocks.stub(instance, propertyName, 'set');

// or add / override properties and methods.
ngMocks.stub(instance, {
newPropert: true,
existingProperty: true,
existingMethod: jasmine.createSpy(),
});
```
Expand Down Expand Up @@ -1030,25 +1030,6 @@ describe('MockService', () => {
// spyOn(mock, 'nameMethod').mockReturnValue('mock');
expect(mock.nameMethod('mock')).toEqual('mock');
expect(ngMocks.stub(mock, 'nameMethod')).toHaveBeenCalledWith('mock');

// Creating a mock on the method that doesn't exist.
ngMocks.stub(mock, 'fakeMethod');
spyOn(mock as any, 'fakeMethod').and.returnValue('mock');
// for jest
// spyOn(mock as any, 'fakeMethod').mockReturnValue('mock');
expect((mock as any).fakeMethod('mock')).toEqual('mock');
expect(ngMocks.stub(mock, 'fakeMethod')).toHaveBeenCalledWith('mock');

// Creating a mock on the property that doesn't exist.
ngMocks.stub(mock, 'fakeProp', 'get');
ngMocks.stub(mock, 'fakeProp', 'set');
spyOnProperty(mock as any, 'fakeProp', 'get').and.returnValue('mockProp');
// for jest
// spyOnProperty(mock as any, 'fakeProp', 'get').mockReturnValue('mockProp');
spyOnProperty(mock as any, 'fakeProp', 'set');
expect((mock as any).fakeProp).toEqual('mockProp');
(mock as any).fakeProp = 'mockPropSet';
expect(ngMocks.stub(mock as any, 'fakeProp', 'set')).toHaveBeenCalledWith('mockPropSet');
});
});
```
Expand Down
15 changes: 10 additions & 5 deletions lib/mock-helper/mock-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,13 @@ export const MockHelper: {

findAll: (el: MockedDebugElement, sel: any) => ngMocks.findAll(el, sel),

mockService: <T = MockedFunction>(instance: any, override: string | object, style?: 'get' | 'set'): T =>
typeof override === 'object' ? ngMocks.stub(instance, override) : ngMocks.stub(instance, override, style),
mockService: <T = MockedFunction>(instance: any, override: any, style?: 'get' | 'set'): T => {
if (typeof override !== 'object') {
return ngMocks.stub(instance, override, style);
}

return ngMocks.stub(instance, override);
},
};

const defaultNotFoundValue = {}; // simulating Symbol
Expand Down Expand Up @@ -122,8 +127,8 @@ export const ngMocks: {

reset(): void;

stub<T = MockedFunction>(instance: any, name: string, style?: 'get' | 'set'): T;
stub<I extends object, O extends object>(instance: I, overrides: O): I & O;
stub<T = MockedFunction, I = any>(instance: I, name: keyof I, style?: 'get' | 'set'): T;
stub<I extends object, O extends Partial<I>>(instance: I, overrides: O): I & O;
} = {
find: (...args: any[]) => {
const el: MockedDebugElement = args[0];
Expand Down Expand Up @@ -304,7 +309,7 @@ export const ngMocks: {
throw new Error(`Cannot find ${sel} input via ngMocks.output`);
},

stub: <T = MockedFunction>(instance: any, override: string | object, style?: 'get' | 'set'): T => {
stub: <T = MockedFunction>(instance: any, override: any, style?: 'get' | 'set'): T => {
if (typeof override === 'string') {
return mockServiceHelper.mock(instance, override, style);
}
Expand Down
24 changes: 2 additions & 22 deletions lib/mock-service/mock-service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,25 +217,6 @@ describe('MockService', () => {
// spyOn(mock, 'nameMethod').mockReturnValue('mock');
expect(mock.nameMethod('mock')).toEqual('mock');
expect(ngMocks.stub(mock, 'nameMethod')).toHaveBeenCalledWith('mock');

// Creating a mock on the method that doesn't exist.
ngMocks.stub(mock, 'fakeMethod');
spyOn(mock as any, 'fakeMethod').and.returnValue('mock');
// for jest
// spyOn(mock as any, 'fakeMethod').mockReturnValue('mock');
expect((mock as any).fakeMethod('mock')).toEqual('mock');
expect(ngMocks.stub(mock, 'fakeMethod')).toHaveBeenCalledWith('mock');

// Creating a mock on the property that doesn't exist.
ngMocks.stub(mock, 'fakeProp', 'get');
ngMocks.stub(mock, 'fakeProp', 'set');
spyOnProperty(mock as any, 'fakeProp', 'get').and.returnValue('mockProp');
// for jest
// spyOnProperty(mock as any, 'fakeProp', 'get').mockReturnValue('mockProp');
spyOnProperty(mock as any, 'fakeProp', 'set');
expect((mock as any).fakeProp).toEqual('mockProp');
(mock as any).fakeProp = 'mockPropSet';
expect(ngMocks.stub(mock as any, 'fakeProp', 'set')).toHaveBeenCalledWith('mockPropSet');
});

it('mocks injection tokens as undefined', () => {
Expand Down Expand Up @@ -264,15 +245,14 @@ describe('MockService', () => {

const test = ngMocks.stub(MockService(Test), {
echo: jasmine.createSpy().and.returnValue('fake1'),
fake: jasmine.createSpy().and.returnValue('fake2'),
nameGet: 'fake3',
nameRead: 'fake4',
nameSet: 'fake5',
});
ngMocks.stub(test, 'nameRead', 'get');
spyOnProperty(test, 'nameRead', 'get').and.returnValue('fake4');

expect(test).toEqual(jasmine.any(Test));
expect(test.echo()).toBe('fake1');
expect((test as any).fake()).toBe('fake2');
expect(test.nameGet).toBe('fake3');
expect(test.nameRead).toBe('fake4');
expect(test.nameSet).toBe('fake5');
Expand Down
40 changes: 40 additions & 0 deletions tests/issue-166/test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// tslint:enable:no-any no-unsafe-any

import { MockService, ngMocks } from 'ng-mocks';
import { Observable, Subject } from 'rxjs';

// fix to support both jasmine and jest in the test
declare let jest: { fn(): () => any };
declare let jasmine: { createSpy(): () => any };

class MyService {
public readonly onErrorSet$: Observable<string>;
public readonly onSuccessSet$: Observable<string>;
public readonly onWarningSet$: Observable<string>;

protected value = 'MyService';

public stringMethod(): string {
return this.value;
}

public voidMethod(sum: string): void {
this.value = `${this.value}${sum}`;
}
}

describe('issue-166', () => {
it('accepts spies', () => {
const spy = typeof jest !== 'undefined' ? jest.fn() : jasmine.createSpy();
const stub = ngMocks.stub(MockService(MyService), {
fakeMethod: () => 123,
onErrorSet$: new Subject<string>(),
onWarningSet$: new Subject<string>(),
stringMethod: spy,
voidMethod: spy,
});
ngMocks.stub(stub, 'onSuccessSet$', 'get');

expect(stub).toBeDefined();
});
});

0 comments on commit 39d9be7

Please sign in to comment.