vendredi 5 mars 2021

Angular test fails with pipe in dynamically generated child component

I have an angular component which serves as a facade for some other components. This is implemented using a ComponentFactoryResolver. When I introduced a pipe to one of the generated components, my unit tests started failing in a strange way.

I was hoping someone would be able to explain why it fails in this way?

        Failed: NG0302: The pipe 'displayValue' could not be found!. Find more at https://angular.io/errors/NG0302
        error properties: Object({ code: '302' })
        Error: NG0302: The pipe 'displayValue' could not be found!. Find more at https://angular.io/errors/NG0302
            at getPipeDef$1 (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:25738:1)
            at ɵɵpipe (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:25695:1)        
            at UsesPipeComponent_Template (ng:///UsesPipeComponent.js:7:9)
            at executeTemplate (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9544:1)
            at renderView (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9351:1)     
            at renderComponent (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10626:1)
            at renderChildComponents (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9216:1)
            at renderView (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9376:1)     
            at ComponentFactory$1.create (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:25079:1)
            at ViewContainerRef.createComponent (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:23118:1)
Chrome 88.0.4324.190 (Windows 10): Executed 1 of 1 (1 FAILED) (0.082 secs / 0.074 secs)

My test

  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent,
        DisplayValuePipe
      ],
      imports: [CommonModule]
    }).compileComponents();
  }));

  it('should create the app', waitForAsync(() => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.componentInstance.title = 'testing';

    fixture.detectChanges();

    const app = fixture.componentInstance;
    console.log(fixture.nativeElement.innerHTML);
    expect(app).toBeTruthy();
  }));

AppComponent

@Component({
  selector: 'app-root',
  template: `<div></div><ng-template #control></ng-template>`,
})
export class AppComponent implements AfterViewInit {
  title = 'testing-pipe';

  @ViewChild('control', { read: ViewContainerRef })
  public controlView: ViewContainerRef | undefined;

  constructor(private factoryResolver: ComponentFactoryResolver) { }

  ngAfterViewInit(): void {
    const factory = this.factoryResolver.resolveComponentFactory(UsesPipeComponent);
    this.controlView?.clear();
    const comp = this.controlView?.createComponent(factory);
    comp?.changeDetectorRef.detach();
    comp?.changeDetectorRef.detectChanges();
  }
}

Uses-Pipe

@Component({
  selector: 'app-uses-pipe',
  template: ``,
})
export class UsesPipeComponent {
  constructor() { }
}

The pipe

@Pipe({
  name: 'displayValue'
})
export class DisplayValuePipe implements PipeTransform {
  transform(value: string, ...args: unknown[]): string {
    return value.toUpperCase();
  }
}

Aucun commentaire:

Enregistrer un commentaire