Skip to content

Commit

Permalink
fix(default-mock): supports an array with declarations #568
Browse files Browse the repository at this point in the history
  • Loading branch information
satanTime committed May 20, 2021
1 parent 24c4bfd commit 5d3b43e
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 36 deletions.
2 changes: 1 addition & 1 deletion examples/MockBuilder/test.ng-mocks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ describe('MockBuilder:ngMocks', () => {
expect(serviceMockInstance.getName).toBeDefined();
expect(serviceMockInstance.getName()).toBeUndefined();
expect(mocks.has(TOKEN_MOCK)).toBeDefined();
expect(mocks.get(TOKEN_MOCK)).toBeUndefined();
expect(mocks.get(TOKEN_MOCK)).toBeDefined();

// customize
const serviceCustomize = mocks.get(ServiceCustomize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default (ngModule: NgMeta, { mockDef, configDef }: BuilderData): void =>
}

const mock = ngMocksUniverse.builtProviders.get(def);
ngModule.providers.push(mock || { provide: def, useValue: undefined });
ngModule.providers.push(mock);
ngMocksUniverse.touches.add(def);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default (def: any, defValue: Map<any, any>): void => {
helperUseFactory(def, undefined, existing => createInstance(existing, instance, config, isPipeFunc)),
);
} else if (isNgDef(def, 'i')) {
ngMocksUniverse.builtProviders.set(def, mockProvider(def));
ngMocksUniverse.builtProviders.set(def, mockProvider(def, true));
}

if (!isNgDef(def) && defValue.has(def)) {
Expand All @@ -34,6 +34,6 @@ export default (def: any, defValue: Map<any, any>): void => {
helperUseFactory(def, undefined, () => instance),
);
} else if (!isNgDef(def)) {
ngMocksUniverse.builtProviders.set(def, mockProvider(def));
ngMocksUniverse.builtProviders.set(def, mockProvider(def, true));
}
};
17 changes: 10 additions & 7 deletions libs/ng-mocks/src/lib/mock-helper/mock-helper.default-mock.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { InjectionToken, Injector } from '@angular/core';

import { flatten } from '../common/core.helpers';
import { AnyType } from '../common/core.types';
import ngMocksUniverse from '../common/ng-mocks-universe';

export default <T>(
def: AnyType<T> | InjectionToken<T> | string,
def: AnyType<T> | InjectionToken<T> | string | Array<AnyType<T> | InjectionToken<T> | string>,
callback?: (instance: undefined | T, injector: Injector) => void | Partial<T>,
): void => {
const map = ngMocksUniverse.getOverrides();
if (callback) {
const set: Set<any> = map.has(def) ? map.get(def) : new Set();
set.add(callback);
map.set(def, set);
} else {
map.delete(def);
for (const item of flatten(def)) {
if (callback) {
const set: Set<any> = map.has(item) ? map.get(item) : new Set();
set.add(callback);
map.set(item, set);
} else {
map.delete(item);
}
}
};
8 changes: 8 additions & 0 deletions libs/ng-mocks/src/lib/mock-helper/mock-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ export const ngMocks: {
*/
defaultMock<T>(def: AnyType<T>, handler?: (value: T, injector: Injector) => void | Partial<T>): void;

/**
* @see https://ng-mocks.sudo.eu/api/ngMocks/defaultMock
*/
defaultMock<T = any>(
defs: Array<AnyType<any> | InjectionToken<any>>,
handler?: (value: undefined | T, injector: Injector) => undefined | Partial<T>,
): void;

/**
* @see https://ng-mocks.sudo.eu/api/ngMocks/event
*/
Expand Down
18 changes: 16 additions & 2 deletions libs/ng-mocks/src/lib/mock-module/mock-module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,22 @@ describe('mockProvider', () => {
});

it('should return undefined on any token', () => {
expect(mockProvider(CUSTOM_TOKEN)).toBeUndefined();
expect(mockProvider(HTTP_INTERCEPTORS)).toBeUndefined();
const p1: any = mockProvider(CUSTOM_TOKEN, true);
expect(p1).toEqual({
deps: [Injector],
provide: CUSTOM_TOKEN,
useFactory: jasmine.anything(),
});
expect(p1.useFactory()).toEqual(undefined);

const p2: any = mockProvider(HTTP_INTERCEPTORS, true);
expect(p2).toEqual({
deps: [Injector],
provide: HTTP_INTERCEPTORS,
useFactory: jasmine.anything(),
});
expect(p2.useFactory()).toEqual(undefined);

expect(mockProvider(APP_INITIALIZER)).toBeUndefined();
});

Expand Down
14 changes: 7 additions & 7 deletions libs/ng-mocks/src/lib/mock-render/mock-render-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { DebugElement, Directive, InjectionToken } from '@angular/core';
import { getTestBed, TestBed } from '@angular/core/testing';

import coreDefineProperty from '../common/core.define-property';
import { Type } from '../common/core.types';
import { AnyType, Type } from '../common/core.types';
import funcImportExists from '../common/func.import-exists';
import { isNgDef } from '../common/func.is-ng-def';
import ngMocksUniverse from '../common/ng-mocks-universe';
Expand All @@ -16,7 +16,7 @@ import funcReflectTemplate from './func.reflect-template';
import { DefaultRenderComponent, IMockRenderOptions, MockedComponentFixture } from './types';

interface MockRenderFactory<C = any, F = DefaultRenderComponent<C>> {
declaration: Type<never>;
declaration: AnyType<never>;
params: F;
(): MockedComponentFixture<C, F>;
}
Expand Down Expand Up @@ -123,7 +123,7 @@ function MockRenderFactory<MComponent>(
* @see https://ng-mocks.sudo.eu/api/MockRender#factory
*/
function MockRenderFactory<MComponent>(
template: Type<MComponent>,
template: AnyType<MComponent>,
params: undefined | null,
detectChangesOrOptions?: boolean | IMockRenderOptions,
): MockRenderFactory<MComponent, MComponent>;
Expand All @@ -132,7 +132,7 @@ function MockRenderFactory<MComponent>(
* @see https://ng-mocks.sudo.eu/api/MockRender#factory
*/
function MockRenderFactory<MComponent, TComponent extends object>(
template: Type<MComponent>,
template: AnyType<MComponent>,
params: TComponent,
detectChangesOrOptions?: boolean | IMockRenderOptions,
): MockRenderFactory<MComponent, TComponent>;
Expand All @@ -141,7 +141,7 @@ function MockRenderFactory<MComponent, TComponent extends object>(
* @see https://ng-mocks.sudo.eu/api/MockRender#factory
*/
function MockRenderFactory<MComponent, TComponent extends object = Record<keyof any, any>>(
template: Type<MComponent>,
template: AnyType<MComponent>,
params: TComponent,
detectChangesOrOptions?: boolean | IMockRenderOptions,
): MockRenderFactory<MComponent, TComponent>;
Expand All @@ -151,7 +151,7 @@ function MockRenderFactory<MComponent, TComponent extends object = Record<keyof
*
* @see https://ng-mocks.sudo.eu/api/MockRender#factory
*/
function MockRenderFactory<MComponent>(template: Type<MComponent>): MockRenderFactory<MComponent, MComponent>;
function MockRenderFactory<MComponent>(template: AnyType<MComponent>): MockRenderFactory<MComponent, MComponent>;

/**
* An empty string does not have point.
Expand Down Expand Up @@ -195,7 +195,7 @@ function MockRenderFactory<MComponent, TComponent extends Record<keyof any, any>
): MockRenderFactory<MComponent, TComponent>;

function MockRenderFactory<MComponent, TComponent extends Record<keyof any, any>>(
template: string | Type<MComponent> | InjectionToken<MComponent>,
template: string | AnyType<MComponent> | InjectionToken<MComponent>,
params?: TComponent,
flags: boolean | IMockRenderOptions = true,
): any {
Expand Down
12 changes: 6 additions & 6 deletions libs/ng-mocks/src/lib/mock-render/mock-render.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { InjectionToken } from '@angular/core';
import { ComponentFixture } from '@angular/core/testing';

import { Type } from '../common/core.types';
import { AnyType } from '../common/core.types';

import { MockRenderFactory } from './mock-render-factory';
import { IMockRenderOptions, MockedComponentFixture } from './types';
Expand All @@ -19,7 +19,7 @@ function MockRender<MComponent>(
* @see https://ng-mocks.sudo.eu/api/MockRender
*/
function MockRender<MComponent>(
template: Type<MComponent>,
template: AnyType<MComponent>,
params: undefined | null,
detectChangesOrOptions?: boolean | IMockRenderOptions,
): MockedComponentFixture<MComponent, MComponent>;
Expand All @@ -28,7 +28,7 @@ function MockRender<MComponent>(
* @see https://ng-mocks.sudo.eu/api/MockRender
*/
function MockRender<MComponent, TComponent extends object>(
template: Type<MComponent>,
template: AnyType<MComponent>,
params: TComponent,
detectChangesOrOptions?: boolean | IMockRenderOptions,
): MockedComponentFixture<MComponent, TComponent>;
Expand All @@ -37,7 +37,7 @@ function MockRender<MComponent, TComponent extends object>(
* @see https://ng-mocks.sudo.eu/api/MockRender
*/
function MockRender<MComponent, TComponent extends object = Record<keyof any, any>>(
template: Type<MComponent>,
template: AnyType<MComponent>,
params: TComponent,
detectChangesOrOptions?: boolean | IMockRenderOptions,
): MockedComponentFixture<MComponent, TComponent>;
Expand All @@ -47,7 +47,7 @@ function MockRender<MComponent, TComponent extends object = Record<keyof any, an
*
* @see https://ng-mocks.sudo.eu/api/MockRender
*/
function MockRender<MComponent>(template: Type<MComponent>): MockedComponentFixture<MComponent, MComponent>;
function MockRender<MComponent>(template: AnyType<MComponent>): MockedComponentFixture<MComponent, MComponent>;

/**
* An empty string does not have point.
Expand Down Expand Up @@ -91,7 +91,7 @@ function MockRender<MComponent, TComponent extends Record<keyof any, any> = Reco
): MockedComponentFixture<MComponent, TComponent>;

function MockRender<MComponent, TComponent extends Record<keyof any, any>>(
template: string | Type<MComponent> | InjectionToken<MComponent>,
template: string | AnyType<MComponent> | InjectionToken<MComponent>,
params?: TComponent,
flags: boolean | IMockRenderOptions = true,
): any {
Expand Down
6 changes: 0 additions & 6 deletions libs/ng-mocks/src/lib/mock-service/helper.resolve-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,6 @@ const createPredefinedMockProvider = (provider: any, provide: any): any => {
if (mockDef === provide) {
return provider;
}
if (mockDef === undefined) {
return {
provide,
useValue: undefined,
};
}

return mockDef;
}
Expand Down
8 changes: 4 additions & 4 deletions libs/ng-mocks/src/lib/mock-service/mock-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ const createMockProvider = (provider: any, provide: any, cacheProviders?: Map<an
// The main problem is that providing undefined to HTTP_INTERCEPTORS and others breaks their code.
// If a testing module / component requires omitted tokens then they should be provided manually
// during creation of TestBed module.
const handleProvider = (provider: any, provide: any) => {
const handleProvider = (provider: any, provide: any, useFactory: boolean) => {
if (provide === provider) {
return undefined;
return useFactory ? helperUseFactory(provider, () => undefined) : undefined;
}
if (provider.multi) {
ngMocksUniverse.config.get('ngMocksMulti')?.add(provide);
Expand Down Expand Up @@ -115,7 +115,7 @@ const isNeverMockFunction = (provide: any): boolean =>
const isNeverMockToken = (provide: any): boolean =>
isNgInjectionToken(provide) && neverMockToken.indexOf(provide.toString()) !== -1;

export default function (provider: any): Provider | undefined {
export default function (provider: any, useFactory = false): Provider | undefined {
const provide = funcGetProvider(provider);

if (isNeverMockFunction(provide)) {
Expand All @@ -134,5 +134,5 @@ export default function (provider: any): Provider | undefined {
return cacheProviders.get(provide);
}

return createMockProvider(provider, provide, cacheProviders) || handleProvider(provider, provide);
return createMockProvider(provider, provide, cacheProviders) || handleProvider(provider, provide, useFactory);
}
82 changes: 82 additions & 0 deletions tests/issue-568/test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Injectable, InjectionToken } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import {
MockBuilder,
MockProvider,
MockRender,
ngMocks,
} from 'ng-mocks';

@Injectable()
class Service1 {
public readonly name = 'service1';
}

@Injectable()
abstract class Service2 {
public readonly name = 'service2';
}

const TOKEN = new InjectionToken<{ name: string }>('TOKEN');

ngMocks.defaultMock([Service1, Service2, TOKEN], () => ({
name: 'mock',
}));

describe('issue-568', () => {
describe('MockBuilder', () => {
ngMocks.faster();

beforeAll(() =>
MockBuilder().mock(Service1).mock(Service2).mock(TOKEN),
);

it('mocks service1', () => {
expect(
MockRender(Service1).point.componentInstance.name,
).toEqual('mock');
});

it('mocks service2', () => {
expect(
MockRender(Service2).point.componentInstance.name,
).toEqual('mock');
});

it('mocks token', () => {
expect(MockRender(TOKEN).point.componentInstance.name).toEqual(
'mock',
);
});
});

describe('TestBed', () => {
beforeEach(() =>
TestBed.configureTestingModule({
providers: [
MockProvider(Service1),
MockProvider(Service2),
MockProvider(TOKEN),
],
}).compileComponents(),
);

it('mocks service1', () => {
expect(
MockRender(Service1).point.componentInstance.name,
).toEqual('mock');
});

it('mocks service2', () => {
expect(
MockRender(Service2).point.componentInstance.name,
).toEqual('mock');
});

it('mocks token', () => {
expect(MockRender(TOKEN).point.componentInstance.name).toEqual(
'mock',
);
});
});
});

0 comments on commit 5d3b43e

Please sign in to comment.