From b032746161e307000afb8bafc368ae0d655c9c81 Mon Sep 17 00:00:00 2001 From: satanTime Date: Thu, 17 Feb 2022 21:48:24 +0100 Subject: [PATCH] fix(mock-render): apply overrides to components with no selectors #1876 --- .../lib/common/ng-mocks-global-overrides.ts | 5 +- .../lib/mock-render/func.reflect-template.ts | 30 +++++++--- tests/issue-1876/test.spec.ts | 59 +++++++++++++++++++ 3 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 tests/issue-1876/test.spec.ts diff --git a/libs/ng-mocks/src/lib/common/ng-mocks-global-overrides.ts b/libs/ng-mocks/src/lib/common/ng-mocks-global-overrides.ts index fdf14a90a8..9b6080d8b7 100644 --- a/libs/ng-mocks/src/lib/common/ng-mocks-global-overrides.ts +++ b/libs/ng-mocks/src/lib/common/ng-mocks-global-overrides.ts @@ -36,7 +36,10 @@ const applyOverride = (def: any, override: any) => { const applyOverrides = (overrides: Map, [MetadataOverride, MetadataOverride]>): void => { for (const [def, [override, original]] of mapEntries(overrides)) { - (TestBed as any).ngMocksOverrides.set(def, original); + (TestBed as any).ngMocksOverrides.set(def, { + ...original, + override, + }); applyOverride(def, override); } }; diff --git a/libs/ng-mocks/src/lib/mock-render/func.reflect-template.ts b/libs/ng-mocks/src/lib/mock-render/func.reflect-template.ts index d29de32aeb..b25fcc3f3e 100644 --- a/libs/ng-mocks/src/lib/mock-render/func.reflect-template.ts +++ b/libs/ng-mocks/src/lib/mock-render/func.reflect-template.ts @@ -9,14 +9,11 @@ import { isNgDef } from '../common/func.is-ng-def'; const registerTemplateMiddleware = (template: AnyType, meta: Directive): void => { const child = extendClass(template); - let providers = meta.providers || []; - providers = [ - ...providers, - { - provide: template, - useExisting: child, - }, - ]; + const alias = { + provide: template, + useExisting: child, + }; + const providers = [...(meta.providers || []), alias]; meta.providers = providers; if (isNgDef(template, 'c')) { @@ -27,6 +24,23 @@ const registerTemplateMiddleware = (template: AnyType, meta: Directive): vo TestBed.configureTestingModule({ declarations: [child], }); + + // https://github.com/ike18t/ng-mocks/issues/1876 + // We need to apply overrides to our cloned declaration. + try { + const ngMocksOverrides: Map = (TestBed as any).ngMocksOverrides; + const { override } = ngMocksOverrides.get(template); + const { set } = override; + ngMocksOverrides.set(child, { set: meta }); + TestBed.overrideComponent(child, { + set: { + ...set, + providers: [...set.providers, alias], + }, + }); + } catch { + // nothing to do + } }; export default (template: AnyType): Directive => { diff --git a/tests/issue-1876/test.spec.ts b/tests/issue-1876/test.spec.ts new file mode 100644 index 0000000000..3bd2691e67 --- /dev/null +++ b/tests/issue-1876/test.spec.ts @@ -0,0 +1,59 @@ +import { + Component, + Directive, + Injectable, + Input, +} from '@angular/core'; +import { MockBuilder, MockRender, ngMocks } from 'ng-mocks'; + +@Injectable() +export class HelloService { + public description = 'real service'; +} + +@Component({ + providers: [HelloService], + template: ``, +}) +export class HelloComponent { + public serviceDescription = ''; + + public constructor(private readonly helloService: HelloService) { + this.serviceDescription = this.helloService.description; + } +} + +@Directive({ + providers: [HelloService], + selector: 'hello', +}) +export class HelloDirective { + @Input() public name = ''; + public serviceDescription = ''; + + public constructor(private readonly helloService: HelloService) { + this.serviceDescription = this.helloService.description; + } +} + +// Components without selectors should still inherit mocked providers. +// https://github.com/ike18t/ng-mocks/issues/1876 +describe('issue-1876', () => { + beforeEach(() => + MockBuilder([HelloComponent, HelloDirective]).mock(HelloService, { + description: 'fake service', + }), + ); + + it('uses fake service in components', () => { + MockRender(HelloComponent); + const instance = ngMocks.findInstance(HelloComponent); + expect(instance.serviceDescription).toContain('fake service'); + }); + + it('uses fake service in directives', () => { + MockRender(HelloDirective); + const instance = ngMocks.findInstance(HelloDirective); + expect(instance.serviceDescription).toContain('fake service'); + }); +});