Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test whether a component is dynamically loaded in angular 7 karma tests?

I have made a component in which I am dynamically loading another component which is working fine on ng serve. Below is the code for dynamically loading the component.

import { Component, OnInit, ViewChild, ComponentFactoryResolver, Type, Input} from '@angular/core';
import { AddComponentDirective } from '../add-component.directive';
import { DynamicComponent } from '../dynamic/dynamic.component';
import { ComponentData } from '../component-data';
import { ComponentItem } from '../component-item';

  export class DynamicLoaderComponent implements OnInit {
      @ViewChild (AddComponentDirective) adhost : AddComponentDirective;

      constructor(private componentFactoryResolver : ComponentFactoryResolver) { }

      ngOnInit() {
          this.loadComponent(DynamicComponent,message,this.adhost);
      }

      loadComponent(comp, message, host){
          let adItem = new ComponentItem(comp,{msg: message});
          let componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);
          let viewContainerRef = host.viewContainer;
          let componentRef = viewContainerRef.createComponent(componentFactory);
      (<ComponentData>componentRef.instance).data = adItem.data;
    }
 }

But while testing it with angular karma test, we are facing type error i.e.

TypeError: this.componentFactoryResolver.resolveComponentFactory is not a function

Below is the spec.ts file how I am testing it.

import { async, ComponentFixture, TestBed ,getTestBed,inject} from '@angular/core/testing';
import {ComponentFactoryResolver,ViewChild,DebugElement} from '@angular/core';
import { AddComponentDirective } from '../add-component.directive';
import { DynamicComponent } from '../dynamic/dynamic.component';
import { DynamicLoaderComponent } from './dynamic-loader.component';
import { BrowserDynamicTestingModule } from "@angular/platform-browser-dynamic/testing";
import { ComponentData } from "../component-data";

describe('DynamicLoaderComponent', () => {
  let component: DynamicLoaderComponent;
  let fixture: ComponentFixture<DynamicLoaderComponent>;
  let injector: TestBed;
  let componentFactoryResolver : ComponentFactoryResolver ;
  let debugElement: DebugElement

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ DynamicLoaderComponent,AddComponentDirective ,DynamicComponent],
      providers:[DynamicLoaderComponent,ComponentFactoryResolver]
    })
    .compileComponents();

    TestBed.overrideModule(BrowserDynamicTestingModule, {
      set: {
        entryComponents: [DynamicComponent]
      }
    });

  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(DynamicLoaderComponent);
    component = fixture.componentInstance;
    componentFactoryResolver =  fixture.debugElement.injector.get(ComponentFactoryResolver);
    fixture.detectChanges();
  });  

  it('should create the DynamicLoaderComponent',inject([DynamicLoaderComponent], (component : DynamicLoaderComponent) => {
    expect(component).toBeTruthy();
  }));

});

An image of the error of the test file on the browser is attached. Click to view

Can you help me solve this issue so that I can proceed further in the testing of dynamic components?

like image 327
Samir Ahmad Avatar asked Jan 04 '19 06:01

Samir Ahmad


1 Answers

There are several changes you need to make to fix those errors:

1) Remove providers from TestBed configuration

TestBed.configureTestingModule({
  declarations: [ DynamicLoaderComponent,AddComponentDirective ,DynamicComponent],
  providers:[DynamicLoaderComponent,ComponentFactoryResolver] <== remove this line
})

2) You do not need to get your component from DI,

so replace

it('should create the DynamicLoaderComponent', inject([DynamicLoaderComponent], (component : DynamicLoaderComponent) => {
  expect(component).toBeTruthy();
}));

with:

it('should create the DynamicLoaderComponent', () => {
  expect(component).toBeTruthy();
});

3) compileComponents() call is only needed if you run tests in a non-CLI environment.

From Angular doc

Calling compileComponents() closes the current TestBed instance to further configuration. You cannot call any more TestBed configuration methods, not configureTestingModule() nor any of the override... methods. The TestBed throws an error if you try.

That means that your TestBed.overrideModule call won't have any effect and DynamicComponent's factory won't be found.

So remove .compileComponents();

TestBed.configureTestingModule({
  declarations: [ DynamicLoaderComponent,AddComponentDirective ,DynamicComponent],
  providers:[DynamicLoaderComponent,ComponentFactoryResolver]
})
.compileComponents(); <==== remove this

If you're on non-angular-cli environment then you can call it after overriding module:

TestBed.overrideModule(BrowserDynamicTestingModule, {
  set: {
    entryComponents: [DynamicComponent]
  }
});

TestBed.compileComponents(); <== this line

After all changes I've written above, the test should be executed without any errors.

Plunker Example

like image 76
yurzui Avatar answered Sep 30 '22 11:09

yurzui