How to correctly unit test (Karma, Jasmine), that emmisions of valueChanges
dispatches a FormUpdated
action?
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [...],
providers: [
{ provide: Store, useValue: MOCK_STORE },
],
declarations: [FormComponent],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FormComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
export class FormComponent implements OnInit {
searchForm: FormGroup;
constructor(private readonly fb: FormBuilder, private readonly store: Store<AppState>) {
}
ngOnInit(): void {
this.searchForm = this.fb.group({});
this.searchForm.valueChanges.subscribe(value => this.store.dispatch(new FormUpdated(value)));
}
}
I have tried something like this:
it('should dispatch action for valueChanges', () => {
const spy = spyOn(component['store'], 'dispatch');
spyOn(component.searchForm, 'valueChanges').and.returnValue(of({}));
expect(spy).toHaveBeenCalledTimes(1);
});
But this does not work - the spy has not been called.
[Edit1] - Based on comments and answer:
The problem is with the test asynchronicity. Some part of ngOnInit
calls setTimeout(() => this.searchForm.get('field').updateValueAndValidity();)
) which causes an emmision to this.searchForm.valueChanges()
so the this.store.dispatch
is actually called but after the expect(spy).toHaveBeenCalledTimes(1)
.
I have tried to add fakeAsync()
, tick()
and flushMicrotasks()
but with same outcome.
it('should dispatch action for valueChanges', () => {
const spy = spyOn(component['store'], 'dispatch');
spyOn(component.searchForm, 'valueChanges').and.returnValue(of({}));
tick();
flushMicrotasks();
expect(spy).toHaveBeenCalledTimes(1);
});
beforeEach
added – Fortifycomponent.searchForm.setValue({})
beforespyOn
? – NeopythagoreanismngOnInit
is run (automatically) with the first.detectChanges
which is located inbeforeEach()
– Fortify