From d58693eb679698fddb659af84d42aa1066683ad9 Mon Sep 17 00:00:00 2001 From: MG Date: Wed, 30 Jun 2021 17:47:39 +0200 Subject: [PATCH] fix(MockBuilder): params support tokens and modules with providers #762 --- .../src/lib/mock-builder/mock-builder.ts | 13 ++-- ...d-missing-keep-declarations-and-modules.ts | 2 +- .../src/lib/mock-builder/promise/types.ts | 16 ++--- tests-failures/mock-builder-constructor.ts | 8 +-- tests/issue-762/module.spec.ts | 71 +++++++++++++++++++ tests/issue-762/string.spec.ts | 70 ++++++++++++++++++ tests/issue-762/token.spec.ts | 71 +++++++++++++++++++ 7 files changed, 230 insertions(+), 21 deletions(-) create mode 100644 tests/issue-762/module.spec.ts create mode 100644 tests/issue-762/string.spec.ts create mode 100644 tests/issue-762/token.spec.ts diff --git a/libs/ng-mocks/src/lib/mock-builder/mock-builder.ts b/libs/ng-mocks/src/lib/mock-builder/mock-builder.ts index 77d6947b56..0bd013faab 100644 --- a/libs/ng-mocks/src/lib/mock-builder/mock-builder.ts +++ b/libs/ng-mocks/src/lib/mock-builder/mock-builder.ts @@ -2,22 +2,19 @@ import { InjectionToken } from '@angular/core'; import { flatten } from '../common/core.helpers'; import { AnyType } from '../common/core.types'; +import { NgModuleWithProviders } from '../common/func.is-ng-module-def-with-providers'; import { MockBuilderPerformance } from './mock-builder.performance'; import { IMockBuilder } from './types'; +export type MockBuilderParam = string | AnyType | InjectionToken | NgModuleWithProviders; + /** * @see https://ng-mocks.sudo.eu/api/MockBuilder */ export function MockBuilder( - keepDeclaration?: - | string - | AnyType - | InjectionToken - | Array | InjectionToken> - | null - | undefined, - itsModuleToMock?: AnyType | Array> | null | undefined, + keepDeclaration?: MockBuilderParam | MockBuilderParam[] | null | undefined, + itsModuleToMock?: MockBuilderParam | MockBuilderParam[] | null | undefined, ): IMockBuilder { const instance = new MockBuilderPerformance(); diff --git a/libs/ng-mocks/src/lib/mock-builder/promise/add-missing-keep-declarations-and-modules.ts b/libs/ng-mocks/src/lib/mock-builder/promise/add-missing-keep-declarations-and-modules.ts index 697bd0e586..4d3651a2ea 100644 --- a/libs/ng-mocks/src/lib/mock-builder/promise/add-missing-keep-declarations-and-modules.ts +++ b/libs/ng-mocks/src/lib/mock-builder/promise/add-missing-keep-declarations-and-modules.ts @@ -12,7 +12,7 @@ export default (ngModule: NgMeta, { keepDef, configDef }: BuilderData): void => continue; } - if (isNgInjectionToken(def)) { + if (isNgInjectionToken(def) || typeof def === 'string') { ngMocksUniverse.touches.add(def); continue; } diff --git a/libs/ng-mocks/src/lib/mock-builder/promise/types.ts b/libs/ng-mocks/src/lib/mock-builder/promise/types.ts index 32776a3e3c..2855c66991 100644 --- a/libs/ng-mocks/src/lib/mock-builder/promise/types.ts +++ b/libs/ng-mocks/src/lib/mock-builder/promise/types.ts @@ -4,14 +4,14 @@ import { Type } from '../../common/core.types'; import { NgModuleWithProviders } from '../../common/func.is-ng-module-def-with-providers'; export type BuilderData = { - configDef: Map | InjectionToken, any>; - defProviders: Map | InjectionToken, Provider[]>; - defValue: Map | InjectionToken, any>; - excludeDef: Set | InjectionToken>; - keepDef: Set | InjectionToken>; - mockDef: Set | InjectionToken>; - providerDef: Map | InjectionToken, Provider>; - replaceDef: Set | InjectionToken>; + configDef: Map | InjectionToken | string, any>; + defProviders: Map | InjectionToken | string, Provider[]>; + defValue: Map | InjectionToken | string, any>; + excludeDef: Set | InjectionToken | string>; + keepDef: Set | InjectionToken | string>; + mockDef: Set | InjectionToken | string>; + providerDef: Map | InjectionToken | string, Provider>; + replaceDef: Set | InjectionToken | string>; }; export type NgMeta = { diff --git a/tests-failures/mock-builder-constructor.ts b/tests-failures/mock-builder-constructor.ts index 286d260798..1470c4981f 100644 --- a/tests-failures/mock-builder-constructor.ts +++ b/tests-failures/mock-builder-constructor.ts @@ -60,16 +60,16 @@ MockBuilder(null, undefined); MockBuilder(undefined, null); MockBuilder(undefined, undefined); -// @ts-expect-error: does not support not modules. +// supports tokens. MockBuilder(null, TOKEN_UNKNOWN); -// @ts-expect-error: does not support not modules. +// supports not string tokens. MockBuilder(null, 'param'); -// @ts-expect-error: does not support modules with providers. +// supports modules with providers. MockBuilder(null, moduleWithProviders); -// @ts-expect-error: does not support modules with providers. +// supports modules with providers. MockBuilder(moduleWithProviders); const promise: Promise = diff --git a/tests/issue-762/module.spec.ts b/tests/issue-762/module.spec.ts new file mode 100644 index 0000000000..380c20cf5a --- /dev/null +++ b/tests/issue-762/module.spec.ts @@ -0,0 +1,71 @@ +import { Injectable, NgModule } from '@angular/core'; +import { + MockBuilder, + MockRender, + NgModuleWithProviders, +} from 'ng-mocks'; + +@Injectable() +class TargetService { + public readonly name?: string = 'target'; +} + +@NgModule() +class TargetModule { + public static forRoot(): NgModuleWithProviders { + return { + ngModule: TargetModule, + providers: [TargetService], + }; + } +} + +describe('issue-762:module', () => { + describe('as keep single', () => { + beforeEach(() => MockBuilder(TargetModule.forRoot())); + + it('works correctly', () => { + const fixture = MockRender(TargetService); + expect(fixture.point.componentInstance).toEqual( + jasmine.any(TargetService), + ); + expect(fixture.point.componentInstance.name).toEqual('target'); + }); + }); + + describe('as keep multi', () => { + beforeEach(() => MockBuilder([TargetModule.forRoot()])); + + it('works correctly', () => { + const fixture = MockRender(TargetService); + expect(fixture.point.componentInstance).toEqual( + jasmine.any(TargetService), + ); + expect(fixture.point.componentInstance.name).toEqual('target'); + }); + }); + + describe('as mock single', () => { + beforeEach(() => MockBuilder(null, TargetModule.forRoot())); + + it('works correctly', () => { + const fixture = MockRender(TargetService); + expect(fixture.point.componentInstance).toEqual( + jasmine.any(TargetService), + ); + expect(fixture.point.componentInstance.name).toEqual(undefined); + }); + }); + + describe('as mock multi', () => { + beforeEach(() => MockBuilder(null, [TargetModule.forRoot()])); + + it('works correctly', () => { + const fixture = MockRender(TargetService); + expect(fixture.point.componentInstance).toEqual( + jasmine.any(TargetService), + ); + expect(fixture.point.componentInstance.name).toEqual(undefined); + }); + }); +}); diff --git a/tests/issue-762/string.spec.ts b/tests/issue-762/string.spec.ts new file mode 100644 index 0000000000..35c338fe3c --- /dev/null +++ b/tests/issue-762/string.spec.ts @@ -0,0 +1,70 @@ +import { NgModule } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { MockBuilder } from 'ng-mocks'; + +@NgModule({ + providers: [ + { + provide: 'STRING', + useValue: 'TOKEN', + }, + ], +}) +class TargetModule {} + +describe('issue-762:string', () => { + describe('as keep single lonely', () => { + beforeEach(() => MockBuilder('STRING')); + + it('works correctly', () => { + expect(() => TestBed.get('STRING')).toThrowError( + /No provider for STRING/, + ); + }); + }); + + describe('as keep single', () => { + beforeEach(() => MockBuilder('STRING', TargetModule)); + + it('works correctly', () => { + const token = TestBed.get('STRING'); + expect(token).toEqual('TOKEN'); + }); + }); + + describe('as keep multi', () => { + beforeEach(() => MockBuilder(['STRING'], TargetModule)); + + it('works correctly', () => { + const token = TestBed.get('STRING'); + expect(token).toEqual('TOKEN'); + }); + }); + + describe('as mock single lonely', () => { + beforeEach(() => MockBuilder(null, 'STRING')); + + it('works correctly', () => { + const token = TestBed.get('STRING'); + expect(token).toEqual(undefined); + }); + }); + + describe('as mock single', () => { + beforeEach(() => MockBuilder(TargetModule, 'STRING')); + + it('works correctly', () => { + const token = TestBed.get('STRING'); + expect(token).toEqual(undefined); + }); + }); + + describe('as mock multi', () => { + beforeEach(() => MockBuilder(TargetModule, ['STRING'])); + + it('works correctly', () => { + const token = TestBed.get('STRING'); + expect(token).toEqual(undefined); + }); + }); +}); diff --git a/tests/issue-762/token.spec.ts b/tests/issue-762/token.spec.ts new file mode 100644 index 0000000000..2ee89f05c1 --- /dev/null +++ b/tests/issue-762/token.spec.ts @@ -0,0 +1,71 @@ +import { InjectionToken, NgModule } from '@angular/core'; +import { MockBuilder, MockRender } from 'ng-mocks'; + +const TOKEN = new InjectionToken('TOKEN'); + +@NgModule({ + providers: [ + { + provide: TOKEN, + useValue: 'TOKEN', + }, + ], +}) +class TargetModule {} + +describe('issue-762:token', () => { + describe('as keep single lonely', () => { + beforeEach(() => MockBuilder(TOKEN)); + + it('works correctly', () => { + expect(() => MockRender(TOKEN)).toThrowError( + /No provider for InjectionToken TOKEN/, + ); + }); + }); + + describe('as keep single', () => { + beforeEach(() => MockBuilder(TOKEN, TargetModule)); + + it('works correctly', () => { + const fixture = MockRender(TOKEN); + expect(fixture.point.componentInstance).toEqual('TOKEN'); + }); + }); + + describe('as keep multi', () => { + beforeEach(() => MockBuilder([TOKEN], TargetModule)); + + it('works correctly', () => { + const fixture = MockRender(TOKEN); + expect(fixture.point.componentInstance).toEqual('TOKEN'); + }); + }); + + describe('as mock single lonely', () => { + beforeEach(() => MockBuilder(null, TOKEN)); + + it('works correctly', () => { + const fixture = MockRender(TOKEN); + expect(fixture.point.componentInstance).toEqual(undefined); + }); + }); + + describe('as mock single', () => { + beforeEach(() => MockBuilder(TargetModule, TOKEN)); + + it('works correctly', () => { + const fixture = MockRender(TOKEN); + expect(fixture.point.componentInstance).toEqual(undefined); + }); + }); + + describe('as mock multi', () => { + beforeEach(() => MockBuilder(TargetModule, [TOKEN])); + + it('works correctly', () => { + const fixture = MockRender(TOKEN); + expect(fixture.point.componentInstance).toEqual(undefined); + }); + }); +});