I have a component which is dispatched actions in constructor:
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
constructor(store: Store<State>) {
store.dispatch(action1());
store.dispatch(action2());
}
}
I need to test if action1 and action2 is dispatched. I'm trying to do it with MockStore:
import {MockStore, provideMockStore} from '@ngrx/store/testing';
let store: MockStore;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
AppComponent
],
providers: [
provideMockStore({ initialState }),
],
}).compileComponents();
store = TestBed.inject(MockStore);
});
And here is my tests:
it('should dispatch an action1 in constructor', () => {
TestBed.createComponent(AppComponent);
const expected = cold('a', {a: action1()});
expect(store.scannedActions$).toBeObservable(expected);
});
it('should dispatch an action2 in constructor', () => {
TestBed.createComponent(AppComponent);
const expected = cold('a', {a: action2()});
expect(store.scannedActions$).toBeObservable(expected);
});
This is strange but only one test is passed. It depends on the order of the dispatch() calls.
store.scannedActions$ contains only one value. If component code is:
constructor(store: Store<State>) {
store.dispatch(action1());
store.dispatch(action2());
}
then store.scannedActions$ contains only action2()
if component code is:
constructor(store: Store<State>) {
store.dispatch(action2());
store.dispatch(action1());
}
then store.scannedActions$ contains only action1()
How to test both actions?
It seems like scannedActions$
even though it is plural (actions) only has the last Action dispatched stored looking at its interface.
I would just use spyOn
and spy on store.dispatch
and see if it was called with the right actions.
import {MockStore, provideMockStore} from '@ngrx/store/testing';
let store: MockStore;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
AppComponent
],
providers: [
provideMockStore({ initialState }),
],
}).compileComponents();
store = TestBed.inject(MockStore);
});
it('should dispatch action1 and action 2 in constructor', () => {
const dispatchSpy = spyOn(store, 'dispatch').and.callThrough(); // spy on the store
// dispatch but still call the actual implementation
TestBed.createComponent(AppComponent);
fixture.detectChanges(); // used to call ngOnInit, maybe it is not needed
expect(dispatchSpy).toHaveBeenCalledWith(action1());
expect(dispatchSpy).toHaveBeenCalledWith(action2());
});