Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lifecycle hook of AfterViewInit in Jasmine test

Tags:

I am confused on lifecycle hooks in relationship with Jasmine testing. The LifeCycle Angular doc does not mention testing https://angular.io/guide/lifecycle-hooks. The testing doc only mentions OnChange https://angular.io/guide/testing. I have a sample component as follows:

import { Component, OnInit, AfterViewInit, OnDestroy, ElementRef } from '@angular/core';
...
@Component({
  selector: 'app-prod-category-detail',
  templateUrl: './prod-category-detail.component.html',
  styleUrls: ['./prod-category-detail.component.css']
})
//
export class ProdCategoryDetailComponent implements OnInit, AfterViewInit, OnDestroy {
    ...
    nav: HTMLSelectElement;
    //
    constructor(
        ...
        private _elementRef: ElementRef ) { }
    ...
    ngAfterViewInit() {
        console.log( 'ProdCategoryDetailComponent: ngAfterViewInit' );
        this.nav = this._elementRef.nativeElement.querySelector('#nav');
    }
    ...
}

As a note, this is an Angular CLI app with the latest downloads. In Karma, I do not see the console log, therefore nav is never set. I am currently invoking it in my spec as follows:

beforeEach(() => {
  fixture = TestBed.createComponent(ProdCategoryDetailComponent);
  sut = fixture.componentInstance;
  sut.ngAfterViewInit( );
  fixture.detectChanges( );
});

Is this proper way of handling this?

For shusson this is from some time ago and I have not looked at this for some time. Hope it will help. Note, I am using Primeface primeng library:

describe('ProdCategoryDetailComponent', () => {
  let sut: ProdCategoryDetailComponent;
  let fixture: ComponentFixture< ProdCategoryDetailComponent >;
  let alertService: AlertsService;
  let prodCatService: ProdCategoryServiceMock;
  let confirmService: ConfirmationServiceMock;
  let elementRef: MockElementRef;
  //
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        FormsModule,
        ButtonModule,
        BrowserAnimationsModule
      ],
      declarations: [
        ProdCategoryDetailComponent,
        AlertsComponent,
        ConfirmDialog
      ],
      providers: [
        AlertsService,
        { provide: ProdCategoryService, useClass: ProdCategoryServiceMock },
        { provide: MockBackend, useClass: MockBackend },
        { provide: BaseRequestOptions, useClass: BaseRequestOptions },
        { provide: ConfirmationService, useClass: ConfirmationServiceMock },
        { provide: ElementRef, useClass: MockElementRef }
      ]
    })
    .compileComponents();
  }));
  //
  beforeEach(inject([AlertsService, ProdCategoryService,
      ConfirmationService, ElementRef],
        (srvc: AlertsService, pcsm: ProdCategoryServiceMock,
        cs: ConfirmationServiceMock, er: MockElementRef) => {
    alertService = srvc;
    prodCatService = pcsm;
    confirmService = cs;
    elementRef = er;
  }));
  //
  beforeEach(() => {
    fixture = TestBed.createComponent(ProdCategoryDetailComponent);
    sut = fixture.componentInstance;
    sut.ngAfterViewInit( );
    fixture.detectChanges( );
  });
  //
like image 372
Phil Huhn Avatar asked Jul 11 '17 15:07

Phil Huhn


People also ask

What are life cycle hooks?

A lifecycle hook provides a specified amount of time (one hour by default) to wait for the action to complete before the instance transitions to the next state.

Which lifecycle hook is fired when a component's view is initialize?

ngOnInit() This is the lifecycle hook used for the initialization of the component/directive. One important thing to notice here is that ngOnChanges() always executes before ngOnInit().

What is AfterViewInit?

ngAfterViewInit()linkA callback method that is invoked immediately after Angular has completed initialization of a component's view. It is invoked only once when the view is instantiated.


1 Answers

I often directly call the life cycle hooks from each spec whenever necessary. And this works. Because this gives the flexibility to manipulate any data before calling ngAfterViewInit() or ngOnInit().

I have also seen few angular libraries test spec using it in the same way. For eg, check this videogular spec file. So there is no harm in calling those methods manually.

Also copying the same code here, just to avoid the link to be broken in future.

it('Should hide controls after view init', () => {
        spyOn(controls, 'hide').and.callFake(() => {});

        controls.vgAutohide = true;

        controls.ngAfterViewInit();

        expect(controls.hide).toHaveBeenCalled();
});
like image 53
Amit Chigadani Avatar answered Sep 19 '22 15:09

Amit Chigadani