I have written a component test for a simple component which only displays an input field for a property name
.
In the component test I'm setting the component's input property name
to 'Stephan'
and I'm expecting my name to appear in the input field, but it doesn't.
In the test I have wrapped my component in a host component (as suggested in multiple tutorials and similar questions on Stack Overflow).
I tried various combinations of detectChanges()
/whenStable()
calls, but none of them worked.
name.component.html
<input id="name" [(ngModel)]="name" />
name.component.ts
import { Component, Input } from '@angular/core';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'name',
templateUrl: './name.component.html',
standalone: true,
imports: [FormsModule],
})
export class NameComponent {
@Input() name: string = '';
}
name.component.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NameComponent } from './name.component';
import { Component } from '@angular/core';
import { By } from '@angular/platform-browser';
describe('NameComponent', () => {
@Component({
imports: [NameComponent],
standalone: true,
template: `<name [name]="name"></name>`,
})
class TestHostComponent {
name: string = '';
}
let hostComponent: TestHostComponent;
let hostFixture: ComponentFixture<TestHostComponent>;
beforeEach(async () => {
hostFixture = TestBed.createComponent(TestHostComponent);
hostComponent = hostFixture.componentInstance;
hostFixture.detectChanges();
});
it('should display my name', async () => {
hostComponent.name = 'Stephan';
hostFixture.detectChanges();
const input = hostFixture.debugElement.query(By.css('input[id="name"]'));
console.log(input.nativeElement);
expect(input.nativeElement.textContent).toEqual('Stephan');
});
});
You can try it on Stackblitz here: https://stackblitz.com/edit/stackblitz-starters-gqas1y?file=src%2Fname-component%2Fname.component.spec.ts
Firstly <input>
element has .value
, not .textContent
. Secondly, ngModel has some async code inside which is there to handle control state and to be able to use it in the parent template like control.valid
, .prestine
and similar.
So the fixed tests would look like this:
it('should display my name', async () => {
hostComponent.name = 'Stephan';
hostFixture.detectChanges();
await hostFixture.whenStable();
const input = hostFixture.debugElement.query(By.css('input[id="name"]'));
console.log(input.nativeElement);
expect(input.nativeElement.value).toEqual('Stephan');
});