From ad2670996874a840e6f07a36a63c1848f77e3d3a Mon Sep 17 00:00:00 2001 From: satanTime Date: Mon, 19 Dec 2022 22:53:09 +0100 Subject: [PATCH] fix(core): respecting transform in mock pipes #4564 --- libs/ng-mocks/src/lib/common/mock.ts | 3 +- .../lib/common/ng-mocks-global-overrides.ts | 11 ++- libs/ng-mocks/src/lib/mock-pipe/mock-pipe.ts | 1 + tests/issue-4564/test.spec.ts | 99 +++++++++++++++++++ 4 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 tests/issue-4564/test.spec.ts diff --git a/libs/ng-mocks/src/lib/common/mock.ts b/libs/ng-mocks/src/lib/common/mock.ts index 49a4e6bf2a..c52e0c8952 100644 --- a/libs/ng-mocks/src/lib/common/mock.ts +++ b/libs/ng-mocks/src/lib/common/mock.ts @@ -1,4 +1,4 @@ -import { EventEmitter, Injector, Optional, Self } from '@angular/core'; +import { EventEmitter, Injector, Optional, PipeTransform, Self } from '@angular/core'; import { IMockBuilderConfig } from '../mock-builder/types'; import mockHelperStub from '../mock-helper/mock-helper.stub'; @@ -116,6 +116,7 @@ export type ngMocksMockConfig = { outputs?: string[]; queryScanKeys?: string[]; setControlValueAccessor?: boolean; + transform?: PipeTransform['transform']; }; const applyOverrides = (instance: any, mockOf: any, injector?: Injector): void => { 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 0c69ebd022..b2aeba2f14 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 @@ -192,7 +192,7 @@ const configureTestingModule = // 0b10 - mock exist // 0b01 - real exist let hasMocks = 0; - const mockBuilder: Array<[any, boolean]> = []; + const mockBuilder: Array<[any, any, boolean]> = []; for (const key of useMockBuilder ? ['imports', 'declarations'] : []) { for (const declaration of flatten(moduleDef[key as never]) as any[]) { if (!declaration) { @@ -205,10 +205,11 @@ const configureTestingModule = providers: declaration.providers, } : getSourceOfMock(declaration), + isNgModuleDefWithProviders(declaration) ? declaration.ngModule : declaration, isMockNgDef(funcGetType(declaration)), ]); if (key === 'imports') { - hasMocks |= mockBuilder[mockBuilder.length - 1][1] ? 0b10 : 0b01; + hasMocks |= mockBuilder[mockBuilder.length - 1][2] ? 0b10 : 0b01; } } } @@ -216,8 +217,10 @@ const configureTestingModule = let finalModuleDef = hasMocks === 0b11 ? undefined : moduleDef; if (!finalModuleDef) { let builder = MockBuilder(NG_MOCKS_ROOT_PROVIDERS); - for (const [def, isMock] of mockBuilder) { - builder = isMock ? builder.mock(def) : builder.keep(def); + for (const [source, def, isMock] of mockBuilder) { + const transform = def.prototype.__ngMocksConfig?.transform; + builder = + isMock && transform ? builder.mock(source, transform) : isMock ? builder.mock(source) : builder.keep(source); } finalModuleDef = builder.build(); finalModuleDef = { diff --git a/libs/ng-mocks/src/lib/mock-pipe/mock-pipe.ts b/libs/ng-mocks/src/lib/mock-pipe/mock-pipe.ts index 806765a3f0..500a40a909 100644 --- a/libs/ng-mocks/src/lib/mock-pipe/mock-pipe.ts +++ b/libs/ng-mocks/src/lib/mock-pipe/mock-pipe.ts @@ -44,6 +44,7 @@ const getMockClass = (pipe: Type, transform?: PipeTransform['transform']): helperMockService.mock(instance, 'transform', `${funcGetName(instance)}.transform`); } }, + transform, }); return mock; diff --git a/tests/issue-4564/test.spec.ts b/tests/issue-4564/test.spec.ts new file mode 100644 index 0000000000..54307a61a5 --- /dev/null +++ b/tests/issue-4564/test.spec.ts @@ -0,0 +1,99 @@ +import { + Component, CUSTOM_ELEMENTS_SCHEMA, Inject, Injectable, InjectionToken, + NgModule, + Pipe, + PipeTransform, +} from '@angular/core'; +import { TestBed } from '@angular/core/testing'; + +import {MockModule, MockPipe, MockProvider, MockRender, ngMocks} from 'ng-mocks'; + +const TOKEN = new InjectionToken('TOKEN'); + +@Injectable() +class TargetService { + func() { + return 'real'; + } +} + +@Pipe({ + name: 'target', +}) +class TargetPipe implements PipeTransform { + transform() { + return 'real'; + } +} + +@Pipe({ + name: 'standard', +}) +class StandardPipe implements PipeTransform { + transform() { + return 'standard'; + } +} + +@NgModule({ + declarations: [TargetPipe, StandardPipe], + exports: [TargetPipe, StandardPipe], + providers: [ + { + provide: TOKEN, + useValue: 'real', + }, + TargetService, + ], +}) +class PipeModule {} + +@Component({ + selector: 'target', + template: '{{ null | target }}:{{ token }}:{{ service.func() }}', +}) +class TargetComponent { + constructor(@Inject(TOKEN) public readonly token: string, public readonly service: TargetService) {} +} + +@NgModule({ + imports: [PipeModule], + declarations: [TargetComponent], + exports: [TargetComponent], +}) +class ComponentModule {} + +@Component({ + selector: 'sut', + template: '', +}) +class SubjectUnderTestComponent {} + +// @see https://github.com/help-me-mom/ng-mocks/issues/4564 +// mixed imports forget pipe customizations. +describe('issue-4564', () => { + ngMocks.throwOnConsole(); + + beforeEach(() => + TestBed.configureTestingModule({ + imports: [ComponentModule, MockModule(PipeModule)], + declarations: [ + SubjectUnderTestComponent, + MockPipe(TargetPipe, () => 'mock'), + MockPipe(StandardPipe), + ], + providers: [ + MockProvider(TOKEN, 'mock'), + MockProvider(TargetService, { + func: () => 'mock', + }), + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }).compileComponents(), + ); + + it('customizes pipe', () => { + const fixture = MockRender(SubjectUnderTestComponent); + expect(ngMocks.formatText(fixture)).toEqual('mock:mock:mock'); + }); +});