0

withLatestFrom我正在使用 Angular 8 和 ngrx 8。我正在尝试为用于从状态中获取一些值的效果编写单元测试。我正在使用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,而是返回user已经处于状态的实例。(这只是一个示例;最终目标是避免在服务中重复 HTTP 调用,或者如果用户 id 发生更改则取消之前的调用)。

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

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

如果有人可以推荐一种更好的方法来处理和测试这种情况,那也很棒。

4

1 回答 1

1

我在模拟商店的文档中看到了这条注释,上面写着“所有调度的动作都不会影响状态”,所以我猜在弹珠图中状态不会改变。

我改变了我的测试,所以它在进入大理石之前设置了用户的状态。现在是这样的:

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);
});
于 2021-01-26T16:19:46.973 回答