Angular Test Change Detection
April 27, 2022
On this page we will learn Angular test change detection.
1. A component property is bound to HTML template only after calling
detectChanges()
method of ComponentFixture
.
2. If we change the value of component property at runtime, then we need to call
detectChanges()
again to observe the new value.
3. We can enable auto change detection by configuring
ComponentFixtureAutoDetect
API in test application module. In this way we can avoid calling detectChanges()
in every test case.
Technologies Used
Find the technologies being used in our example.1. Angular 13.1.0
2. Node.js 12.20.0
3. Jasmine 3.10
4. Karma 6.3
Example-1: detectChanges()
In our component, we have a property as following.person.component.ts
@Component({ selector: 'app-person', templateUrl: './person.component.html' }) export class PersonComponent { title = "Hello World"; }
title
property is bound to HTML template.
person.component.html
<h1>{{title}}</h1>
In our component we have a property as
title
. To bind it in HTML as {{title}}
, we need to call detectChanges()
method. The fixture.detectChanges()
tells the TestBed
to perform data binding. Only after data binding, HTML template gets data from component properties.
beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [PersonComponent] }).compileComponents(); fixture = TestBed.createComponent(PersonComponent); component = fixture.componentInstance; }); it('should match H1 text', fakeAsync(() => { const h1 = fixture.debugElement.nativeElement.querySelector('h1'); fixture.detectChanges(); expect(component.title).toBe(h1.textContent); }));
Example-2: Automatic change detection
We can enable automatic change detection by usingComponentFixtureAutoDetect
API. In this way we can avoid calling detectChanges()
in every test case.
The
ComponentFixtureAutoDetect
is used as following.
beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [PersonComponent], providers: [ { provide: ComponentFixtureAutoDetect, useValue: true } ] }).compileComponents(); fixture = TestBed.createComponent(PersonComponent); component = fixture.componentInstance; }); it('should match H1 text', fakeAsync(() => { const h1 = fixture.debugElement.nativeElement.querySelector('h1'); expect(component.title).toBe(h1.textContent); }));
Example-3
In this example we will configureComponentFixtureAutoDetect
that will enable auto change detection. As we know that if we change the component property value at run time, then to observe the changes, we need to call detectChanges()
method.
person.component.spec.ts
import { ComponentFixture, TestBed, fakeAsync, ComponentFixtureAutoDetect } from '@angular/core/testing'; import { PersonComponent } from './person.component'; describe('PersonComponent', () => { let component: PersonComponent; let fixture: ComponentFixture<PersonComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [PersonComponent], providers: [ { provide: ComponentFixtureAutoDetect, useValue: true } ] }).compileComponents(); fixture = TestBed.createComponent(PersonComponent); component = fixture.componentInstance; }); it('should match H1 text', fakeAsync(() => { const h1 = fixture.debugElement.nativeElement.querySelector('h1'); // fixture.detectChanges() is not needed. expect(component.title).toBe(h1.textContent); })); it('should match H1 old text', fakeAsync(() => { const h1 = fixture.debugElement.nativeElement.querySelector('h1'); component.title = "Welcome"; // Component property value is changed but h1 text is not changed. expect(component.title === h1.textContent).toBe(false); })); it('should match H1 text with detectChanges', fakeAsync(() => { const h1 = fixture.debugElement.nativeElement.querySelector('h1'); fixture.detectChanges(); // detect changes explicitly. expect(component.title).toBe(h1.textContent); })); });
