Lifecycle hook of AfterViewInit in Jasmine test

Viewed 21646

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( );
  });
  //
2 Answers

We can't directly call the life cycle hooks from spec but we can the call custom methods. Because for calling lifecycle books we need to create an instance of the component using fixture.

Example: In my example, I need to set padding-left, and right to 0 as bootstrap gives some padding left and right by default So I need to remove it.

HTML File - app.component.ts

import { Component, ViewChild, ElementRef, Renderer2 } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  @ViewChild('navCol', { static: true }) navCol: ElementRef;

  constructor(private renderer: Renderer2) {  }

  ngAfterViewInit() {
    this.renderer.setStyle(this.navCol.nativeElement, 'padding-left', '0px');
    this.renderer.setStyle(this.navCol.nativeElement, 'padding-right', '0px');
  }
}

app.component.spec.ts

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

describe('AppComponent', () => {
  it('should load page and remove padding', () => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.componentInstance.ngAfterViewInit();
    const styles = window.getComputedStyle(fixture.nativeElement);

    expect(styles.paddingLeft).toBe('0px');
    expect(styles.paddingRight).toBe('0px');
  });
});
Related