1

I am testing a component which dinamically inserts a checkbox in its template when ngAfterViewInit lifecycle hook is called.

export class MyComponent {

  ngAfterViewInit() {
    // checkbox insertion in the template here
    ...
  }

  ...
}

This is my test:

it('should inject the checkbox', () => {
  fixture = TestBed.createComponent(AutogeneratedTableComponent);
  fixture.detectChanges();

  rows = fixture.debugElement.queryAll(By.css('tr'));
  console.log(Object.assign({}, rows[1].nativeElement));  // *referenceLog
  console.log(rows[1].nativeElement));  // *cloneLog

  expect(rows[1].query(By.css('input')).not.toBeNull(); // FAILS
}

*refereceLog (prints the tr without the inserted td)

<tr ng-reflect-id="22" id="22">
   <td>Single Room</td>
   <td>My single room.</td>
</tr>

*cloneLog (shows that at time of testing the template is not ready)

Object{__zone_symbol__eventTasks: [ZoneTask{zone: ..., runCount: ..., _zoneDelegates: ..., _state: ..., type: ..., source: ..., data: ..., scheduleFn: ..., cancelFn: ..., callback: ..., invoke: ...}]}

I tried manually calling ngAfterViewInit()

it('should inject the checkbox', () => {
  fixture = TestBed.createComponent(AutogeneratedTableComponent);
  fixture.detectChanges();

  fixture.debugElement.componentInstance.ngAfterViewInit();
  fixture.detectChanges();

  rows = fixture.debugElement.queryAll(By.css('tr'));
  console.log(Object.assign({}, rows[1].nativeElement));  // *referenceLog
  console.log(rows[1].nativeElement));  // *cloneLog

  expect(rows[1].query(By.css('input')).not.toBeNull(); // FAILS
}

*refereceLog (prints the expected tr)

<tr ng-reflect-id="22" id="22">
   <td><input id="22" type="checkbox"></td>
   <td>Single Room</td>
   <td>My single room.</td>
</tr>

No changes in *cloneLog

Then I tried

  • Adding spyOn(component, 'ngAfterViewInit').andReturnValue(Promise.resolve(true)).and.callThrough(); and then spyOn().calls.mostRecent.returnValue.then(() => {fixture.detectChanges() ... }) with the done() at the bottom of the block

  • Adding async() to the individual test declaration and doing the evaluation inside a fixture.whenStable.then( () => { fixture.detectChanges()... } )

  • Adding fakeAsync() to the individual test declaration and a tick() calling before the evaluation

All the attempts with the same previous result. The template element is being updated after the evaluation is done.

I should find a way to stop the test execution until the nativeElement that I am testing is updated.

Graham
  • 7,431
  • 18
  • 59
  • 84
Zucca
  • 561
  • 1
  • 7
  • 21

1 Answers1

4

I had a similar problem and this solution worked for me:

I called fixture.autoDetectChanges(true); instead of (or additionally to) fixture.detectChanges().