Skip to content

Commit

Permalink
fix: ngMocks.guts reuses mock pipes
Browse files Browse the repository at this point in the history
closes #241
  • Loading branch information
satanTime committed Dec 1, 2020
1 parent 2e8f5cf commit 13dd2c9
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 26 deletions.
15 changes: 14 additions & 1 deletion lib/common/ng-mocks-universe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ import { AnyType } from './core.types';
// istanbul ignore next
const getGlobal = (): any => window || global;

interface NgMocksUniverse {
builtDeclarations: Map<any, any>;
builtProviders: Map<any, any>;
cacheDeclarations: Map<any, any>;
cacheProviders: Map<any, any>;
config: Map<any, any>;
flags: Set<string>;
global: Map<any, any>;
isExcludedDef: (def: any) => boolean;
isProvidedDef: (def: any) => boolean;
touches: Set<AnyType<any> | InjectionToken<any> | string>;
}

getGlobal().ngMocksUniverse = getGlobal().ngMocksUniverse || {
builtDeclarations: new Map(),
builtProviders: new Map(),
Expand All @@ -29,4 +42,4 @@ getGlobal().ngMocksUniverse = getGlobal().ngMocksUniverse || {
*
* @internal
*/
export default (() => getGlobal().ngMocksUniverse)();
export default ((): NgMocksUniverse => getGlobal().ngMocksUniverse)();
2 changes: 1 addition & 1 deletion lib/mock-builder/mock-builder-stash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class MockBuilderStash {

public restore(): void {
for (const key of Object.keys(this.data)) {
ngMocksUniverse[key] = (this.data as any)[key];
(ngMocksUniverse as any)[key] = (this.data as any)[key];
}
}
}
20 changes: 11 additions & 9 deletions lib/mock-helper/mock-helper.guts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,18 @@ const resolve = (data: Data, def: any, skipDestruction = true): void => {
}
};

const generateData = (keep: any, mock: any, exclude: any): Data => ({
declarations: [],
exclude: new Set(flatten(exclude || [])),
imports: [],
keep: new Set(flatten(keep || [])),
mock: new Set(flatten(mock || [])),
providers: [],
skip: new Set(),
});

export default (keep: any, mock: any = null, exclude: any = null): TestModuleMetadata => {
const data: Data = {
declarations: [],
exclude: new Set(flatten(exclude || [])),
imports: [],
keep: new Set(flatten(keep || [])),
mock: new Set(flatten(mock || [])),
providers: [],
skip: new Set(),
};
const data: Data = generateData(keep, mock, exclude);

for (const def of mapValues(data.mock)) {
resolve(data, def, false);
Expand Down
28 changes: 20 additions & 8 deletions lib/mock-module/mock-ng-def.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,38 @@ const flatToExisting = <T, R>(data: T | T[], callback: (arg: T) => R | undefined

type processMeta = 'declarations' | 'entryComponents' | 'bootstrap' | 'providers' | 'imports' | 'exports';

const configureProcessMetaKeys = (
resolve: (def: any) => any,
resolveProvider: (def: Provider) => any,
): Array<[processMeta, (def: any) => any]> => [
['declarations', resolve],
['entryComponents', resolve],
['bootstrap', resolve],
['providers', resolveProvider],
['imports', resolve],
['exports', resolve],
];

const processMeta = (
ngModule: NgModule,
resolve: (def: any) => any,
resolveProvider: (def: Provider) => any,
): NgModule => {
const mockModuleDef: NgModule = {};
const keys = configureProcessMetaKeys(resolve, resolveProvider);

const keys: Array<[processMeta, (def: any) => any]> = [
['declarations', resolve],
['entryComponents', resolve],
['bootstrap', resolve],
['providers', resolveProvider],
['imports', resolve],
['exports', resolve],
];
const cachePipe = ngMocksUniverse.flags.has('cachePipe');
if (!cachePipe) {
ngMocksUniverse.flags.add('cachePipe');
}
for (const [key, callback] of keys) {
if (ngModule[key]?.length) {
mockModuleDef[key] = flatToExisting(ngModule[key], callback);
}
}
if (!cachePipe) {
ngMocksUniverse.flags.delete('cachePipe');
}

return mockModuleDef;
};
Expand Down
2 changes: 1 addition & 1 deletion lib/mock-service/mock-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const createClassProvider = (provider: any, provide: any) =>
? provider
: helperUseFactory(provide, () => MockService(provider.useClass));

const createMockProvider = (provider: any, provide: any, cacheProviders: Map<any, any>): Provider | undefined => {
const createMockProvider = (provider: any, provide: any, cacheProviders?: Map<any, any>): Provider | undefined => {
let mockProvider: Provider | undefined;
if (typeof provide === 'function') {
mockProvider = createFactoryProvider(provider, provide);
Expand Down
12 changes: 6 additions & 6 deletions tests/get-mocked-ng-def-of/test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@ class TargetDirective {}
class TargetModule {}

describe('getMockedNgDefOf:legacy', () => {
it('returns mock for a module', () => {
const mock = MockModule(TargetModule);
expect(getMockedNgDefOf(TargetModule, 'm')).toBe(mock);
expect(getMockedNgDefOf(TargetModule)).toBe(mock);
});

it('returns mock for a component', () => {
const mock = MockComponent(TargetComponent);
expect(getMockedNgDefOf(TargetComponent, 'c')).toBe(mock);
Expand All @@ -70,6 +64,12 @@ describe('getMockedNgDefOf:legacy', () => {
/There is no mock for TargetPipe/,
);
});

it('returns mock for a module', () => {
const mock = MockModule(TargetModule);
expect(getMockedNgDefOf(TargetModule, 'm')).toBe(mock);
expect(getMockedNgDefOf(TargetModule)).toBe(mock);
});
});

describe('getMockedNgDefOf:mocks', () => {
Expand Down
35 changes: 35 additions & 0 deletions tests/issue-241/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Component, NgModule, Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'target',
})
export class TargetPipe implements PipeTransform {
public transform(value: string): string {
return `${value.length}`;
}
}

@NgModule({
declarations: [TargetPipe],
exports: [TargetPipe],
})
export class PipeModule {}

@NgModule({
exports: [TargetPipe],
imports: [PipeModule],
})
export class TargetModule {}

@Component({
selector: 'target',
template: `{{ 'target' | target }}`,
})
export class TargetComponent {}

@NgModule({
declarations: [TargetComponent],
exports: [TargetComponent],
imports: [TargetModule],
})
export class AppModule {}
16 changes: 16 additions & 0 deletions tests/issue-241/test.builder.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { MockBuilder, MockRender } from 'ng-mocks';

import { AppModule, TargetComponent } from './fixtures';

describe('issue-241:builder', () => {
beforeEach(() => MockBuilder(TargetComponent, AppModule));

it('it exports pipe', () => {
const fixture = MockRender(TargetComponent);

// A mock pipe returns nothing.
expect(fixture.nativeElement.innerHTML).toEqual(
'<target></target>',
);
});
});
21 changes: 21 additions & 0 deletions tests/issue-241/test.classic.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { TestBed } from '@angular/core/testing';
import { MockModule, MockRender } from 'ng-mocks';

import { AppModule, TargetComponent } from './fixtures';

describe('issue-241:classic', () => {
beforeEach(() =>
TestBed.configureTestingModule({
imports: [MockModule(AppModule)],
}).compileComponents(),
);

it('it exports pipe', () => {
const fixture = MockRender(TargetComponent);

// A mock pipe returns nothing.
expect(fixture.nativeElement.innerHTML).toEqual(
'<target></target>',
);
});
});
21 changes: 21 additions & 0 deletions tests/issue-241/test.guts.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { TestBed } from '@angular/core/testing';
import { MockRender, ngMocks } from 'ng-mocks';

import { AppModule, TargetComponent } from './fixtures';

describe('issue-241:guts', () => {
beforeEach(() =>
TestBed.configureTestingModule(
ngMocks.guts(TargetComponent, AppModule),
).compileComponents(),
);

it('it exports pipe', () => {
const fixture = MockRender(TargetComponent);

// A mock pipe returns nothing.
expect(fixture.nativeElement.innerHTML).toEqual(
'<target></target>',
);
});
});
21 changes: 21 additions & 0 deletions tests/issue-241/test.real.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { TestBed } from '@angular/core/testing';
import { MockRender } from 'ng-mocks';

import { AppModule, TargetComponent } from './fixtures';

describe('issue-241:real', () => {
beforeEach(() =>
TestBed.configureTestingModule({
imports: [AppModule],
}).compileComponents(),
);

it('it exports pipe', () => {
const fixture = MockRender(TargetComponent);

// A real pipe returns the string's length.
expect(fixture.nativeElement.innerHTML).toEqual(
'<target>6</target>',
);
});
});

0 comments on commit 13dd2c9

Please sign in to comment.