So it seems that there are some asynchronous tasks that need to complete (we await fixture.whenStable
and then we need to call fixture.detectChanges()
. This is one of the reasons why I use reactive forms almost always because it is much easier to test. You can test them just by the TypeScript code alone and you don’t have to look at the HTML at all.
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let el: DebugElement;
let button: HTMLButtonElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [AppComponent],
imports: [FormsModule]
}).compileComponents();
}));
beforeEach(async () => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
el = fixture.debugElement;
fixture.detectChanges();
});
describe('submit button', () => {
it('should be disabled by default', async () => {
await fixture.whenStable(); // wait for all asynchronous tasks to complete
fixture.detectChanges(); // call detectChanges again
button = fixture.debugElement.query(By.css('button')).nativeElement;
expect(button.disabled).toBe(true);
});
});
});
Things to note:
1.) Every time you call fixture.detectChanges
, you need a new reference to fixture.debugElement.query...
because the view changes every time you call fixture.detectChanges
. If we were to keep using el
like you have in the beforeEach
, you would have an old reference to how the HTML looked like.
2.) You don’t need to import CommonModule
in Angular unit tests.
CLICK HERE to find out more related problems solutions.