I'm adding unit testing to my angular/rxjs project, and I'm using the marble test
solution. And since I'm using the newer version of rxjs, so I used the build-in "TestScheduler" module.
I'm following this post: https://brianflove.com/2018/06/28/ngrx-testing-effects/, And it gave an example as following:
export class UserEffects {
@Effect()
addUser: Observable<Action> = this.actions$
.ofType<AddUser>(UserActionTypes.AddUser)
.pipe(
map(action => action.payload),
exhaustMap(payload => this.userService.addUser(payload.user)),
map(user => new AddUserSuccess({ user })),
catchError(error => of(new AddUserFail({ error })))
);
constructor(private actions$: Actions, private userService: UserService) {}
}
and the unit test is below:
describe('addUser', () => {
it('should return an AddUserSuccess action, with the user, on success', () => {
const user = generateUser();
const action = new AddUser({ user });
const outcome = new AddUserSuccess({ user });
actions.stream = hot('-a', { a: action });
const response = cold('-a|', { a: user });
const expected = cold('--b', { b: outcome });
userService.addUser = jest.fn(() => response);
expect(effects.addUser).toBeObservable(expected);
});
});
I can understand the logic(marble string) here expect one confusing point:
cold('--b', { b: outcome })
why not --b|
? Since the response observable has a completion event |
in cold('-a|', { a: user });
.
Btw, in this post, it will third-party library, but I use native TestScheduler
and have the same result.
I want to preface this by saying I'm not too familiar with ngrx, so this is just me guessing: It looks like everything is being passed into an action reducer. The action stream -a
is being tested with --b
, and you don't want your action reducer to end because you want it to be able to take in the next action.