Angular 2 unit testing - @ViewChild is undefined

会有一股神秘感。 提交于 2019-12-04 15:03:35

问题


I am writing an Angular 2 unit test. I have a @ViewChild subcomponent that I need to recognize after the component initializes. In this case it's a Timepicker component from the ng2-bootstrap library, though the specifics shouldn't matter. After I detectChanges() the subcomponent instance is still undefined.

Pseudo-code:

@Component({
    template: `
        <form>
            <timepicker
                #timepickerChild
                [(ngModel)]="myDate">
            </timepicker>
        </form>
    `
})
export class ExampleComponent implements OnInit {
    @ViewChild('timepickerChild') timepickerChild: TimepickerComponent;
    public myDate = new Date();
}


// Spec
describe('Example Test', () => {
    let exampleComponent: ExampleComponent;
    let fixture: ComponentFixture<ExampleComponent>;

    beforeEach(() => {
        TestBed.configureTestingModel({
            // ... whatever needs to be configured
        });
        fixture = TestBed.createComponent(ExampleComponent);
    });

    it('should recognize a timepicker'. async(() => {
        fixture.detectChanges();
        const timepickerChild: Timepicker = fixture.componentInstance.timepickerChild;
        console.log('timepickerChild', timepickerChild)
    }));
});

The pseudo-code works as expected until you reach the console log. The timepickerChild is undefined. Why is this happening?


回答1:


I think it should work. Maybe you forgot to import some module in your configuration. Here is the complete code for test:

import { TestBed, ComponentFixture, async } from '@angular/core/testing';

import { Component, DebugElement } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { ExampleComponent } from './test.component';
import { TimepickerModule, TimepickerComponent } from 'ng2-bootstrap/ng2-bootstrap';

describe('Example Test', () => {
  let exampleComponent: ExampleComponent;
  let fixture: ComponentFixture<ExampleComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [FormsModule, TimepickerModule.forRoot()],
      declarations: [
        ExampleComponent
      ]
    });
    fixture = TestBed.createComponent(ExampleComponent);
  });

  it('should recognize a timepicker', async(() => {
    fixture.detectChanges();
    const timepickerChild: TimepickerComponent = fixture.componentInstance.timepickerChild;
    console.log('timepickerChild', timepickerChild);
    expect(timepickerChild).toBeDefined();
  }));
});

Plunker Example




回答2:


In most cases just add it to deceleration and you are good to go.

beforeEach(async(() => {
        TestBed
            .configureTestingModule({
                imports: [],
                declarations: [TimepickerComponent],
                providers: [],
            })
            .compileComponents() 



回答3:


Make sure your child component does not have a *ngIf that is evaluating to false. If so, it will result in the child component as being undefined.




回答4:


If you want to test the main component with a stub child component, you need to add a provider to the stub child component; as explained in the article Angular Unit Testing @ViewChild.

import { Component } from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
  selector: 'app-child',
  template: '',
  providers: [
    {
      provide: ChildComponent,
      useClass: ChildStubComponent
    }
  ]
})
export class ChildStubComponent {
  updateTimeStamp() {}
}

Note the providers metadata, to use the class ChildStubComponent when ChildComponent is required.

You can then create your parent component normally, its child will be created with the type ChildStubComponent.



来源:https://stackoverflow.com/questions/42724179/angular-2-unit-testing-viewchild-is-undefined

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!