Skip to content

Commit

Permalink
feat: mock-service is typed and supports overrides
Browse files Browse the repository at this point in the history
closes #122
  • Loading branch information
satanTime committed May 18, 2020
1 parent af1c51f commit 42fc7dc
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 7 deletions.
43 changes: 38 additions & 5 deletions lib/mock-service/mock-service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// tslint:disable:max-classes-per-file

import { InjectionToken } from '@angular/core';

import { MockHelper } from '../mock-helper';

import { MockService } from './mock-service';

// tslint:disable:max-classes-per-file
class DeepParentClass {
public deepParentMethodName = 'deepParentMethod';

Expand Down Expand Up @@ -58,8 +59,6 @@ class GetterSetterMethodHuetod {
}
}

// tslint:enable:max-classes-per-file

describe('MockService', () => {
it('should convert boolean, number, string, null and undefined to undefined', () => {
expect(MockService(true)).toBeUndefined();
Expand Down Expand Up @@ -93,7 +92,7 @@ describe('MockService', () => {
});

it('should mock own methods of a class without a parent', () => {
const mockedService = MockService(DeepParentClass);
const mockedService = MockService(DeepParentClass) as any;
expect(mockedService).toEqual(jasmine.any(Object));

// all properties should be undefined, maybe defined as getters and setters.
Expand All @@ -106,7 +105,7 @@ describe('MockService', () => {
});

it('should mock own and parent methods of a class', () => {
const mockedService = MockService(ChildClass);
const mockedService = MockService(ChildClass) as any;
expect(mockedService).toEqual(jasmine.any(ChildClass));

// all properties should be undefined, maybe defined as getters and setters.
Expand Down Expand Up @@ -232,4 +231,38 @@ describe('MockService', () => {
const token1 = MockService(new InjectionToken('hello'));
expect(token1).toBeUndefined();
});

it('mocks a class to an instance with proper types', () => {
class Test {
public readonly nameRead = 'read';

private name = 'test';

public get nameGet(): string {
return this.name;
}

public set nameSet(name: string) {
this.name = name;
}

public echo(): string {
return this.name;
}
}

const test1 = MockService(Test).__override({
echo: jasmine.createSpy().and.returnValue('fake1'),
fake: jasmine.createSpy().and.returnValue('fake2'),
nameGet: 'fake3',
nameRead: 'fake4',
nameSet: 'fake5',
});
expect(test1).toEqual(jasmine.any(Test));
expect(test1.echo()).toBe('fake1');
expect((test1 as any).fake()).toBe('fake2');
expect(test1.nameGet).toBe('fake3');
expect(test1.nameRead).toBe('fake4');
expect(test1.nameSet).toBe('fake5');
});
});
21 changes: 19 additions & 2 deletions lib/mock-service/mock-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,13 +211,30 @@ export const mockServiceHelper: {
registerMockFunction(mockFunction: (mockName: string) => MockedFunction | undefined): void;
} = ((window as any) || (global as any)).ngMocksMockServiceHelper;

// tslint:disable:ban-types
export type MockedService<T> = T & {
__override(mocks: object): MockedService<T>;
};
// tslint:enable:ban-types

export function MockService(service?: boolean | number | string | null, mockNamePrefix?: string): undefined;
export function MockService<T extends {}>(service: T, mockNamePrefix?: string): any;
export function MockService<T>(service: new (...args: any[]) => T, mockNamePrefix?: string): MockedService<T>;
// tslint:disable-next-line:no-misused-new unified-signatures
export function MockService<T = any>(service: object, mockNamePrefix?: string): T;
export function MockService(service: any, mockNamePrefix?: string): any {
// mocking all methods / properties of a class / object.
let value: any;
if (isClass(service)) {
value = localHelper.createMockFromPrototype(service.prototype);
value.__override = (mocks: object): MockedService<typeof service> => {
for (const key of Object.getOwnPropertyNames(mocks)) {
const def = Object.getOwnPropertyDescriptor(mocks, key);
if (def) {
Object.defineProperty(value, key, def);
}
}
return value;
};
} else if (isFunc(service)) {
value = localHelper.mockFunction(`func:${mockNamePrefix ? mockNamePrefix : service.name || 'arrow-function'}`);
} else if (Array.isArray(service)) {
Expand All @@ -228,7 +245,7 @@ export function MockService(service: any, mockNamePrefix?: string): any {
? localHelper.createMockFromPrototype(service.constructor.prototype)
: {};
for (const property of Object.keys(service)) {
const mock = MockService(service[property], `${mockNamePrefix ? mockNamePrefix : 'instance'}.${property}`);
const mock: any = MockService(service[property], `${mockNamePrefix ? mockNamePrefix : 'instance'}.${property}`);
if (mock !== undefined) {
value[property] = mock;
}
Expand Down

0 comments on commit 42fc7dc

Please sign in to comment.