Я пишу тест жасмина для моего angular 8 приложения, которое проверяет, вызван ли метод onOverlayClicked для события click. Во время выполнения теста я получаю сообщение об ошибке
Error: No component factory found for undefined. Did you add it to @NgModule.entryComponents?
error properties: Object({ ngComponent: undefined, ngDebugContext: DebugContext_({ view: Object({ def: Object({ factory: Function, nodeFlags: 37928961, rootNodeFlags: 33554433, nodeMatchedQueries: 0, flags: 0, nodes: [ Object({ nodeIndex: 0, parent: null, renderParent: null, bindingIndex: 0, outputIndex: 0, checkIndex: 0, flags: 33554433, childFlags: 4374528, directChildFlags: 4374528, childMatchedQueries: 0, matchedQueries: Object({ }), matchedQueryIds: 0, references: Object({ }), ngContentIndex: null, childCount: 1, bindings: [ ], bindingFlags: 0, outputs: [ ], element:
Object({ ns: '', name: 'app-dialog', attrs: [ ], template: null, componentProvider: Object({ nodeIndex: 1, parent: <circular reference: Object>, renderParent: <circular reference: Object>, bindingIndex: 0, outputIndex: 0, checkIndex: 1, flags: 4374528, childFlags: 0, directChildFlags: 0, childMatchedQueries: 0, matchedQueries: Object, matchedQueryIds: 0, references: Object, ngContentIndex:
-1, childCount: 0, bindings: Array, b ...
Если я добавляю InsertionDirective к элементу entryComponents, я получаю сообщение об ошибке
Cannot add directive to entryComponents.
Я не уверен, в чем проблема
Модуль
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DialogComponent } from '../../components/dialog/dialog.component';
import { InsertionDirective } from '../../shared/directives/insertion.directive';
@NgModule({
imports: [CommonModule],
declarations: [DialogComponent, InsertionDirective],
entryComponents: [DialogComponent]
})
export class DialogModule {}
Компонент
import { AfterViewInit, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, OnDestroy, Type, ViewChild } from '@angular/core';
import { Subject } from 'rxjs';
import { InsertionDirective } from '../../shared/directives/insertion.directive';
import { DialogRef } from './config/dialog-ref';
@Component({
selector: 'app-dialog',
templateUrl: './dialog.component.html'
})
export class DialogComponent implements AfterViewInit, OnDestroy {
private readonly _onClose = new Subject<any>();
public componentRef: ComponentRef<any>;
public childComponentType: Type<any>;
public onClose = this._onClose.asObservable();
// add this:
@ViewChild(InsertionDirective, { static: false })
insertionPoint: InsertionDirective;
constructor(public componentFactoryResolver: ComponentFactoryResolver,
public cd: ChangeDetectorRef,
public dialog: DialogRef) {
console.log('My InsertionPoint');
console.log(this.insertionPoint);
}
ngAfterViewInit() {
this.loadChildComponent(this.childComponentType);
this.cd.detectChanges();
}
ngOnDestroy() {
if (this.componentRef) {
this.componentRef.destroy();
}
}
onOverlayClicked(evt: MouseEvent) {
// close the dialog
}
onDialogClicked(evt: MouseEvent) {
evt.stopPropagation();
}
loadChildComponent(componentType: Type<any>) {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentType);
const viewContainerRef = this.insertionPoint.viewContainerRef;
console.log(viewContainerRef);
viewContainerRef.clear();
this.componentRef = viewContainerRef.createComponent(componentFactory);
}
closeModal() {
this.dialog.close();
}
}
Тестовый компонент
describe('DialogComponent', () => {
let component: DialogComponent;
let fixture: ComponentFixture<DialogComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [SharedModule, DialogModule], // DialogModule
// declarations: [ InsertionDirective ],
providers: [ DialogRef ]
})
.overrideModule(BrowserDynamicTestingModule, { set: { entryComponents: [DialogComponent] } })
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
fit('should set call onOverlayClicked click', () => {
// const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
spyOn(component, 'onOverlayClicked');
const overlay = fixture.debugElement.query(By.css('.overlay'));
overlay.triggerEventHandler('click', {});
fixture.detectChanges();
expect(component.onOverlayClicked).toHaveBeenCalled();
});
});
InsertionDirective
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appInsertion]',
})
export class InsertionDirective {
constructor(public viewContainerRef: ViewContainerRef) {}
}