diff --git a/README.md b/README.md index 41bb22c2..62177236 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ const createComponent = createComponentFactory({ entryComponents: [], componentProviders: [], // Override the component's providers componentViewProviders: [], // Override the component's view providers + overrideModules: [], // Override modules mocks: [], // Providers that will automatically be mocked componentMocks: [], // Component providers that will automatically be mocked componentViewProvidersMocks: [], // Component view providers that will be automatically mocked diff --git a/docs/docs/testing-components.md b/docs/docs/testing-components.md index 30baf4a3..d19bf349 100644 --- a/docs/docs/testing-components.md +++ b/docs/docs/testing-components.md @@ -39,6 +39,7 @@ const createComponent = createComponentFactory({ entryComponents: [], componentProviders: [], // Override the component's providers componentViewProviders: [], // Override the component's view providers + overrideModules: [], // Override modules mocks: [], // Providers that will automatically be mocked componentMocks: [], // Component providers that will automatically be mocked componentViewProvidersMocks: [], // Component view providers that will be automatically mocked @@ -192,3 +193,21 @@ spectator.get(FooService, true) In the same way you can also override the component view providers by using the `componentViewProviders` and `componentViewProvidersMocks`. The same rules also apply to directives using the `directiveProviders` and `directiveMocks` parameters. + +## Override Modules + +Use `overrideModules` option to override modules. + +For Example: + +```ts +createComponentFactory({ + component: SomeComponent, + overrideModules: [ + [SomeModule, {set: {declarations: [SomeOtherComponent]}], + [SomeOtherModule, {set: {declarations: [SomeOtherComponent]}] + ] +}) +``` + +cf. https://angular.io/api/core/testing/TestBed#overrideModule diff --git a/projects/spectator/jest/test/override-module.spec.ts b/projects/spectator/jest/test/override-module.spec.ts new file mode 100644 index 00000000..e1a3eab2 --- /dev/null +++ b/projects/spectator/jest/test/override-module.spec.ts @@ -0,0 +1,72 @@ +import { Component, Directive, HostBinding, NgModule } from '@angular/core'; +import { Spectator, SpectatorDirective, SpectatorHost } from '@ngneat/spectator'; +import { createComponentFactory, createDirectiveFactory, createHostFactory } from '@ngneat/spectator/jest'; + +import { AveragePipe } from '../../test/pipe/average.pipe'; + +@Component({ selector: 'test-comp', template: '
{{ prop | avg }}
' }) +class TestComponent { + public prop = [1, 2, 3]; +} + +@Directive({ selector: '[someDirective]' }) +class SomeDirective { + @HostBinding('class') public someClass = 'someClass'; +} + +@NgModule() +class SomeModule {} + +describe('Override Module With Component Factory', () => { + let spectator: Spectator; + const createComponent = createComponentFactory({ + component: TestComponent, + imports: [SomeModule], + overrideModules: [[SomeModule, { set: { declarations: [AveragePipe], exports: [AveragePipe] } }]] + }); + + beforeEach(() => { + spectator = createComponent(); + }); + + it('should be declared with override modules', () => { + expect(spectator.component).toBeTruthy(); + expect(spectator.query('div')?.textContent).toEqual('2'); + }); +}); + +describe('Override Module With Directive Factory', () => { + let spectator: SpectatorDirective; + const createDirective = createDirectiveFactory({ + directive: SomeDirective, + host: TestComponent, + imports: [SomeModule], + overrideModules: [[SomeModule, { set: { declarations: [AveragePipe], exports: [AveragePipe] } }]] + }); + + beforeEach(() => { + spectator = createDirective(`
{{ prop | avg }}
`); + }); + + it('should be declared with override modules', () => { + expect(spectator.query('div')?.classList).toContain('someClass'); + expect(spectator.query('div')?.textContent).toEqual('2'); + }); +}); + +describe('Override Module With Host Factory', () => { + let spectator: SpectatorHost; + const createHost = createHostFactory({ + component: TestComponent, + imports: [SomeModule], + overrideModules: [[SomeModule, { set: { declarations: [AveragePipe], exports: [AveragePipe] } }]] + }); + + beforeEach(() => { + spectator = createHost(``); + }); + + it('should be declared with override modules', () => { + expect(spectator.query('div')?.textContent).toEqual('2'); + }); +}); diff --git a/projects/spectator/src/lib/base/options.ts b/projects/spectator/src/lib/base/options.ts index ae91e5cf..57546434 100644 --- a/projects/spectator/src/lib/base/options.ts +++ b/projects/spectator/src/lib/base/options.ts @@ -1,4 +1,5 @@ -import { Provider, SchemaMetadata, Type } from '@angular/core'; +import { NgModule, Provider, SchemaMetadata, Type } from '@angular/core'; +import { MetadataOverride } from '@angular/core/testing'; import { merge } from '../internals/merge'; import { mockProvider, MockProvider } from '../mock'; @@ -16,6 +17,7 @@ export interface BaseSpectatorOptions { declarations?: any[]; imports?: any[]; schemas?: (SchemaMetadata | any[])[]; + overrideModules?: [Type, MetadataOverride][]; } /** @@ -33,7 +35,8 @@ const defaultOptions: OptionalsRequired = { providers: [], declarations: [], imports: [], - schemas: [] + schemas: [], + overrideModules: [] }; /** diff --git a/projects/spectator/src/lib/spectator-directive/create-factory.ts b/projects/spectator/src/lib/spectator-directive/create-factory.ts index ccae2100..1515807f 100644 --- a/projects/spectator/src/lib/spectator-directive/create-factory.ts +++ b/projects/spectator/src/lib/spectator-directive/create-factory.ts @@ -13,6 +13,7 @@ import { nodeByDirective } from '../internals/node-by-directive'; import { initialSpectatorDirectiveModule } from './initial-module'; import { getSpectatorDirectiveDefaultOptions, SpectatorDirectiveOptions } from './options'; import { SpectatorDirective } from './spectator-directive'; +import { overrideModules } from '../spectator/create-factory'; /** * @publicApi @@ -64,6 +65,7 @@ export function createDirectiveFactory( beforeEach(async(() => { jasmine.addMatchers(customMatchers as any); TestBed.configureTestingModule(moduleMetadata); + overrideModules(options); })); return (template?: string, overrides?: SpectatorDirectiveOverrides) => { diff --git a/projects/spectator/src/lib/spectator-host/create-factory.ts b/projects/spectator/src/lib/spectator-host/create-factory.ts index a8fe55d1..c884ad44 100644 --- a/projects/spectator/src/lib/spectator-host/create-factory.ts +++ b/projects/spectator/src/lib/spectator-host/create-factory.ts @@ -5,7 +5,7 @@ import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/t import { setProps } from '../internals/query'; import * as customMatchers from '../matchers'; -import { SpectatorOverrides, overrideComponentIfProviderOverridesSpecified } from '../spectator/create-factory'; +import { overrideComponentIfProviderOverridesSpecified, overrideModules, SpectatorOverrides } from '../spectator/create-factory'; import { isType } from '../types'; import { nodeByDirective } from '../internals/node-by-directive'; @@ -67,6 +67,8 @@ export function createHostFactory(typeOrOptions: Type | jasmine.addMatchers(customMatchers as any); TestBed.configureTestingModule(moduleMetadata); + overrideModules(options); + overrideComponentIfProviderOverridesSpecified(options); })); diff --git a/projects/spectator/src/lib/spectator-http/create-factory.ts b/projects/spectator/src/lib/spectator-http/create-factory.ts index 21012b7b..feabdc2c 100644 --- a/projects/spectator/src/lib/spectator-http/create-factory.ts +++ b/projects/spectator/src/lib/spectator-http/create-factory.ts @@ -9,6 +9,7 @@ import { isType } from '../types'; import { initialHttpModule } from './initial-module'; import { getDefaultHttpOptions, isDeprecated, SpectatorHttpOptions } from './options'; import { SpectatorHttp } from './spectator-http'; +import { overrideModules } from '../spectator/create-factory'; /** * @publicApi @@ -31,6 +32,7 @@ export function createHttpFactory(typeOrOptions: Type | SpectatorHttpOptio beforeEach(() => { TestBed.configureTestingModule(moduleMetadata); + overrideModules(options); }); afterEach(() => { diff --git a/projects/spectator/src/lib/spectator-pipe/create-factory.ts b/projects/spectator/src/lib/spectator-pipe/create-factory.ts index db901710..8697d0bd 100644 --- a/projects/spectator/src/lib/spectator-pipe/create-factory.ts +++ b/projects/spectator/src/lib/spectator-pipe/create-factory.ts @@ -11,6 +11,7 @@ import { HostComponent } from '../spectator-host/host-component'; import { initialSpectatorPipeModule } from './initial-module'; import { getSpectatorPipeDefaultOptions, SpectatorPipeOptions } from './options'; import { SpectatorPipe } from './spectator-pipe'; +import { overrideModules } from '../spectator/create-factory'; /** * @publicApi @@ -41,6 +42,7 @@ export function createPipeFactory(typeOrOptions: Type

| beforeEach(async(() => { jasmine.addMatchers(customMatchers as any); TestBed.configureTestingModule(moduleMetadata); + overrideModules(options); })); return (templateOrOverrides?: string | SpectatorPipeOverrides, overrides?: SpectatorPipeOverrides) => { diff --git a/projects/spectator/src/lib/spectator-routing/create-factory.ts b/projects/spectator/src/lib/spectator-routing/create-factory.ts index 2069da15..e751a1d4 100644 --- a/projects/spectator/src/lib/spectator-routing/create-factory.ts +++ b/projects/spectator/src/lib/spectator-routing/create-factory.ts @@ -4,7 +4,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { setProps } from '../internals/query'; import * as customMatchers from '../matchers'; -import { SpectatorOverrides, overrideComponentIfProviderOverridesSpecified } from '../spectator/create-factory'; +import { SpectatorOverrides, overrideComponentIfProviderOverridesSpecified, overrideModules } from '../spectator/create-factory'; import { isType } from '../types'; import { ActivatedRouteStub } from './activated-route-stub'; @@ -37,6 +37,8 @@ export function createRoutingFactory(typeOrOptions: Type | SpectatorRoutin jasmine.addMatchers(customMatchers as any); TestBed.configureTestingModule(moduleMetadata); + overrideModules(options); + overrideComponentIfProviderOverridesSpecified(options); TestBed.compileComponents(); diff --git a/projects/spectator/src/lib/spectator-service/create-factory.ts b/projects/spectator/src/lib/spectator-service/create-factory.ts index 8517bfc8..86435114 100644 --- a/projects/spectator/src/lib/spectator-service/create-factory.ts +++ b/projects/spectator/src/lib/spectator-service/create-factory.ts @@ -7,6 +7,7 @@ import { isType, doesServiceImplementsOnDestroy } from '../types'; import { initialServiceModule } from './initial-module'; import { getDefaultServiceOptions, SpectatorServiceOptions } from './options'; import { SpectatorService } from './spectator-service'; +import { overrideModules } from '../spectator/create-factory'; /** * @publicApi @@ -30,6 +31,7 @@ export function createServiceFactory(typeOrOptions: Type | SpectatorServic beforeEach(() => { TestBed.configureTestingModule(moduleMetadata); + overrideModules(options); }); afterEach(() => { diff --git a/projects/spectator/src/lib/spectator/create-factory.ts b/projects/spectator/src/lib/spectator/create-factory.ts index 80a982bd..52c7c836 100644 --- a/projects/spectator/src/lib/spectator/create-factory.ts +++ b/projects/spectator/src/lib/spectator/create-factory.ts @@ -2,7 +2,7 @@ import { Provider, Type } from '@angular/core'; import { async, TestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing'; -import { BaseSpectatorOverrides } from '../base/options'; +import { BaseSpectatorOptions, BaseSpectatorOverrides } from '../base/options'; import { setProps } from '../internals/query'; import * as customMatchers from '../matchers'; import { isType } from '../types'; @@ -49,6 +49,19 @@ export function overrideComponentIfProviderOverridesSpecified(options: Requir } } +/** + * @internal + */ +export function overrideModules(options: Required): void { + if (options.overrideModules.length) { + options.overrideModules.forEach(overrideModule => { + const [ngModule, override] = overrideModule; + + TestBed.overrideModule(ngModule, override); + }); + } +} + /** * @deprecated Use createComponentFactory instead. To be removed in v5. */ @@ -74,6 +87,8 @@ export function createComponentFactory(typeOrOptions: Type | SpectatorOpti } }); + overrideModules(options); + overrideComponentIfProviderOverridesSpecified(options); TestBed.compileComponents(); diff --git a/projects/spectator/test/override-module.spec.ts b/projects/spectator/test/override-module.spec.ts new file mode 100644 index 00000000..b3578589 --- /dev/null +++ b/projects/spectator/test/override-module.spec.ts @@ -0,0 +1,78 @@ +import { Component, Directive, HostBinding, NgModule } from '@angular/core'; +import { + createComponentFactory, + createDirectiveFactory, + createHostFactory, + Spectator, + SpectatorDirective, + SpectatorHost +} from '@ngneat/spectator'; + +import { AveragePipe } from './pipe/average.pipe'; + +@Component({ selector: 'test-comp', template: '

{{ prop | avg }}
' }) +class TestComponent { + public prop = [1, 2, 3]; +} + +@Directive({ selector: '[someDirective]' }) +class SomeDirective { + @HostBinding('class') public someClass = 'someClass'; +} + +@NgModule() +class SomeModule {} + +describe('Override Module With Component Factory', () => { + let spectator: Spectator; + const createComponent = createComponentFactory({ + component: TestComponent, + imports: [SomeModule], + overrideModules: [[SomeModule, { set: { declarations: [AveragePipe], exports: [AveragePipe] } }]] + }); + + beforeEach(() => { + spectator = createComponent(); + }); + + it('should be declared with override modules', () => { + expect(spectator.component).toBeTruthy(); + expect(spectator.query('div')?.textContent).toEqual('2'); + }); +}); + +describe('Override Module With Directive Factory', () => { + let spectator: SpectatorDirective; + const createDirective = createDirectiveFactory({ + directive: SomeDirective, + host: TestComponent, + imports: [SomeModule], + overrideModules: [[SomeModule, { set: { declarations: [AveragePipe], exports: [AveragePipe] } }]] + }); + + beforeEach(() => { + spectator = createDirective(`
{{ prop | avg }}
`); + }); + + it('should be declared with override modules', () => { + expect(spectator.query('div')?.classList).toContain('someClass'); + expect(spectator.query('div')?.textContent).toEqual('2'); + }); +}); + +describe('Override Module With Host Factory', () => { + let spectator: SpectatorHost; + const createHost = createHostFactory({ + component: TestComponent, + imports: [SomeModule], + overrideModules: [[SomeModule, { set: { declarations: [AveragePipe], exports: [AveragePipe] } }]] + }); + + beforeEach(() => { + spectator = createHost(``); + }); + + it('should be declared with override modules', () => { + expect(spectator.query('div')?.textContent).toEqual('2'); + }); +});