ngrx - 大理石测试和 withLatestFrom

ngrx - marble testing and withLatestFrom

我正在使用 Angular 8 和 ngrx 8。我正在尝试为使用 withLatestFrom 从状态中获取一些值的效果编写单元测试。我为此使用 rxjs/testing/TestScheduler。在那里,我有一个像这样的弹珠图:

actions$ = hot('aa', { a: actions.fetchUser({ id: 1 }));

我的效果是这样的:

fetchUser$ = createEffect(() => this.actions$.pipe(
  ofType(actions.fetchUser),
  withLatestFrom(this.store.select(selectors.user)),
  mergeMap(([{ id }, user]) => {
    console.log(user);
    if (user.id === id) {
      return of(user);
    }
    return this.userService.getUser(id).pipe(
      map((user) => actions.updateUser({ user })),
      catchError(() => of(actions.updateUser({})))
    )
  })
))

商店中的初始用户是一个空对象。

想法是第一个弹珠框通过调用 userService 并更新状态;然后第二帧发生并且它看到 user.id,这是在第一帧期间设置的,因此它没有调用 userService,而是 returns 已经存在的 user 实例在该州。 (这只是一个示例;最终目标是避免服务中出现重复的 HTTP 调用,或者如果用户 ID 发生变化,则取消之前的调用)。

问题是弹珠图期间状态似乎没有更新,从 withLatestFrom 返回的用户对象始终是测试中设置的初始状态。

我是 Angular 和 ngrx 测试的新手,所以我不确定这是预期的行为还是我做错了什么。

如果有人能推荐一种更好的方法来处理和测试这种情况,那就太好了。

我在模拟商店的 documentation 中看到了这条注释,上面写着“所有派发的操作都不会影响状态”,所以我猜状态在弹珠图期间不会改变。

我更改了我的测试,以便它在进入弹珠之前设置用户的状态。现在是这样的:

it('should use the user in store when called with the same id', () => {
  scheduler.run(({ hot, expectObservable }) => {
    const fetchUser = actions.fetchUser({ id: 1 });
    const updateUser = actions.updateUser({ user });

    store.setState({
      user
    });

    spyOn(userService, 'getUser').and.callThrough();

    actions$ = hot(
      `a`,
      { a: fetchUser }
    );

    // The result should come immediately because the user with the given id is already in the store
    const expectedMarble = `a`;
    const expectedValues = { a: updateUser };

    expectObservable(effects.fetchUser$).toBe(expectedMarble, expectedValues);
    });

  expect(userService.getUser).not.toHaveBeenCalledWith(1);
});