How to make change detection in unit tests work properly? From sources, changeDetection should be ran after microtasks are empty (including event tasks?).
this._onMicrotaskEmptySubscription = ngZone.onMicrotaskEmpty.subscribe({
next: () => {
if (this._autoDetect) {
// Do a change detection run with checkNoChanges set to true to check
// there are no changes on the second run.
this.detectChanges(true);
}
}
});
In this short example, change detection ran after setTimeout, but not after manually clicking on the element. Is there a proper way to trigger change detection after event dispatching (inside fakeAsync zone, without fixture.detectChanges because in this case change detection will not be the same as in real life)?
import {
fakeAsync, tick, ComponentFixture, TestBed, ComponentFixtureAutoDetect
} from '@angular/core/testing';
import {
Component, QueryList, ViewChildren
} from '@angular/core';
import { By } from '@angular/platform-browser';
import { CommonModule } from '@angular/common';
describe('bug', () => {
let host: Host;
let fixture: ComponentFixture<Host>;
@Component({
selector: 'child',
template: ``,
})
class Child {}
@Component({
template: `
<ng-container *ngFor="let show of shows">
<child *ngIf="show"></child>
</ng-container>
<button (click)="shows[1] = true">show</button>`
})
class Host {
shows = [false, false];
@ViewChildren(Child) children: QueryList<Child>;
constructor() {
setTimeout(() => this.shows[0] = true, 50);
}
}
fit('test', fakeAsync(() => {
TestBed.configureTestingModule({
imports: [
CommonModule,
],
declarations: [
Host, Child,
],
providers: [{
provide: ComponentFixtureAutoDetect,
useValue: true,
}]
});
fixture = TestBed.createComponent(Host);
host = fixture.componentInstance;
tick(10);
expect(host.children.length).toEqual(0);
tick(50);
expect(host.children.length).toEqual(1);
const button = fixture.debugElement.query(By.css('button'));
button.triggerEventHandler('click', new Event('click'));
tick(50);
// fixture.detectChanges();
expect(host.children.length).toEqual(2); // fails here
}));
});