Skip to content

Commit

Permalink
fix(#333): register mock components with entryComponents
Browse files Browse the repository at this point in the history
  • Loading branch information
satanTime committed Mar 29, 2021
1 parent e4fad16 commit 7034121
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 18 deletions.
41 changes: 34 additions & 7 deletions libs/ng-mocks/src/lib/mock-builder/promise/init-ng-modules.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { NgModule } from '@angular/core';

import { mapValues } from '../../common/core.helpers';
import { isNgDef } from '../../common/func.is-ng-def';
import ngMocksUniverse from '../../common/ng-mocks-universe';
Expand All @@ -6,23 +8,48 @@ import initModule from './init-module';
import skipInitModule from './skip-init-module';
import { BuilderData, NgMeta } from './types';

const handleDef = (
def: any,
defProviders: Map<any, any>,
imports: any[],
declarations: any[],
entryComponents: any[],
) => {
if (isNgDef(def, 'm')) {
imports.push(initModule(def, defProviders));
} else {
const declaration = ngMocksUniverse.getBuildDeclaration(def);
declarations.push(declaration);
if (isNgDef(declaration, 'c')) {
entryComponents.push(declaration);
}
}
};

const handleEntryComponents = (entryComponents: any[], imports: any[]): void => {
if (entryComponents.length) {
// the way to cause entryComponents to do its work
class MockBuilderMock {}
NgModule({
entryComponents,
})(MockBuilderMock);
imports.push(MockBuilderMock);
}
};

export default ({ configDef, keepDef, mockDef, replaceDef }: BuilderData, defProviders: Map<any, any>): NgMeta => {
const { imports, declarations, providers }: NgMeta = { imports: [], declarations: [], providers: [] };
const entryComponents: any[] = [];

// Adding suitable leftovers.
for (const def of [...mapValues(mockDef), ...mapValues(keepDef), ...mapValues(replaceDef)]) {
if (skipInitModule(def, configDef)) {
continue;
}

if (isNgDef(def, 'm')) {
imports.push(initModule(def, defProviders));
} else {
declarations.push(ngMocksUniverse.getBuildDeclaration(def));
}

handleDef(def, defProviders, imports, declarations, entryComponents);
ngMocksUniverse.touches.add(def);
}
handleEntryComponents(entryComponents, imports);

return {
declarations,
Expand Down
12 changes: 1 addition & 11 deletions tests/issue-296/test.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// tslint:disable no-duplicate-imports

import * as core from '@angular/core';
import {
Component,
ComponentFactoryResolver,
Expand Down Expand Up @@ -52,16 +51,7 @@ describe('issue-296:without-entry', () => {

it('behaves correctly with and without ivy', () => {
const render = () => MockRender(TargetComponent);
if ((core as any).ɵivyEnabled) {
// ivy does not fail
expect(render).not.toThrow();
}
if (!(core as any).ɵivyEnabled) {
// no-ivy fails with @NgModule.entryComponents
expect(render).toThrowError(
/No component factory found for ModalComponent/,
);
}
expect(render).not.toThrow();
});
});

Expand Down
56 changes: 56 additions & 0 deletions tests/issue-333/test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { CommonModule } from '@angular/common';
import { Component, NgModule, Type } from '@angular/core';
import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';

@Component({
selector: 'dynamic-overlay',
template:
'<ng-container *ngComponentOutlet="component"></ng-container>',
})
export class DynamicOverlayComponent {
public component?: Type<any>;

public attachComponent(component: Type<any>) {
this.component = component;
}
}

@NgModule({
declarations: [DynamicOverlayComponent],
exports: [DynamicOverlayComponent],
imports: [CommonModule],
})
export class OverlayModule {}

@Component({
selector: 'mock-component',
template: '<h1>previous</h1>',
})
class MockComponent {}

describe('issue-333', () => {
// this should work with and without ivy
beforeEach(() =>
MockBuilder(DynamicOverlayComponent, OverlayModule).keep(
MockComponent,
),
);

it('should render', () => {
const fixture = MockRender(DynamicOverlayComponent);

expect(ngMocks.formatHtml(fixture)).toEqual(
`<dynamic-overlay></dynamic-overlay>`,
);
});

it('should project content', () => {
const fixture = MockRender(DynamicOverlayComponent);
fixture.point.componentInstance.attachComponent(MockComponent);
fixture.detectChanges();

expect(ngMocks.formatHtml(fixture)).toEqual(
`<dynamic-overlay><mock-component><h1>previous</h1></mock-component></dynamic-overlay>`,
);
});
});

0 comments on commit 7034121

Please sign in to comment.