I am trying to test interactions between a components internals and its HTML.
In the following test code, I have an app-component with an input-field, which is linked to an attribute within the component using two-way binding.
Test1 passes with the use of fixture.detectChanges and waiting it to be stable. So, in this test the components test-attribute is synchronised with the input-field.
However, test2 fails due to the fact that the compontent has not been updated with the new test-attribute value. So, what am I missing or doing wrong to synchronise the changes before entering into the assertion?
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
test = 'hello';
}
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import {BrowserModule, By} from '@angular/platform-browser';
import {FormsModule} from '@angular/forms';
import {ComponentFixture} from '../../node_modules/@angular/core/testing';
import {detectChanges} from '../../node_modules/@angular/core/src/render3';
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
FormsModule
],
declarations: [
AppComponent,
],
}).compileComponents();
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
});
it('test1', () => {
const inputElement = fixture.debugElement.query(By.css('input'));
const el = inputElement.nativeElement;
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(el.value).toBe('hello');
})
});
it('test2', () => {
const inputElement = fixture.debugElement.query(By.css('input'));
const el = inputElement.nativeElement;
el.value = 'test';
expect(el.value).toBe('test');
el.dispatchEvent(new Event('input'));
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.test).toBe('test');
})
});
});
<div>
<input [(ngModel)]="test" type="text">
<p>{{test}}</p>
</div>
I took the answer below and looked at the minimal from the answer to get my test to pass. The key seems to have been to move the fixture.detectChanges() to the beforeEach() function.
I believe this was the minimum I needed to include for a passing test, in addition to adding the fixture.detectChanges in the beforeEach. It seems that the done and the fixture.whenStable is not necessary.
it('test2', () => {
const inputElement = fixture.debugElement.query(By.css('input'));
const el = inputElement.nativeElement;
el.value = 'test';
el.dispatchEvent(new Event('input'));
expect(component.test).toBe('test');
});