Angular Testing and Change Detection: fixture.detectChanges() only works once in test. Why?

46 Views Asked by At

I trying to test a simple component:

HTML:

<ng-container *ngIf="lessThanTen(value) else moreThanTen">
  <div
    class="circle"
    [ngClass]="{'active': isActive}"
  >
    {{value}}
  </div>
</ng-container>

<ng-template #moreThanTen>
  <div
    class="rounded-rectangle"
    [ngClass]="{'active': isActive}"
  >
    {{value}}
  </div>
</ng-template>

TS:

export class MatchesCounterComponent {
  @Input() public value: number;

  @Input() public isActive: boolean;

  public lessThanTen(value: number): boolean {
    return value < 10;
  }
}

And test:

describe('MatchesCounterComponent', () => {
  let component: MatchesCounterComponent;
  let fixture: ComponentFixture<MatchesCounterComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [MatchesCounterComponent],
    }).compileComponents();

    fixture = TestBed.createComponent(MatchesCounterComponent);
    component = fixture.componentInstance;

    fixture.detectChanges(); // IF REMOVE IT ALL WORKS CORRECT
  });

  it('should render circle if value is less than 10', () => {
    component.value = 5;
    fixture.detectChanges(); // DOESN'T WORK

    const compiled = fixture.nativeElement as HTMLElement;
    expect(compiled.querySelector('.rounded-rectangle')).toBeNull();
    expect(compiled.querySelector('.circle')).not.toBeNull();
  });
});

Problem:
The test fails because the change detector does not fire a second time

Question: Why fixture.detectChanges() doesn't work second time in the "it" block? (value is undefined, but I directly changed it: component.value = 5).

If I remove fixture.detectChanges() from beforeEach block - all works correct.

If I set value via fixture.componentRef.setInput() - all works correct.

But I really interesting how CD works in this code.

1

There are 1 best solutions below

0
slim On

Does your component use ChangeDetectionStrategy.OnPush? If so, wrap it in a test host, as there is an issue with change detection for OnPush components in tests. The test host can be used as a workaround.