【问题标题】:Angular: Testing guards that return observablesAngular:测试返回 observables 的守卫
【发布时间】:2018-11-08 16:02:49
【问题描述】:

我正在尝试测试一个返回 observable 并调用另一个函数的身份验证守卫。我的后卫看起来像这样(从 Todd Motto 解除。干杯 Todd):

@Injectable()
export class ProductSummaryLoadedGuard implements CanActivate {
  constructor(private store: Store<fromProductStore.State>) {}

  canActivate(): Observable<boolean> {
    return this.checkStore().pipe(
      switchMap(() => of(true)),
      catchError(() => of(false))
    );
  }

  checkStore(): Observable<boolean> {
    return this.store.pipe(select(fromProductStore.selectProductLoaded)).pipe(
      tap(loaded => {
        if (!loaded) {
          this.store.dispatch(new fromProductStore.LoadProductSummary());
        }
      }),
      filter(loaded => loaded),
      take(1)
    );
  }
}

我已经为此整理了规范的框架,导致问题的摘录是这样的:

it('should return true when checkStore() returns true', () => {
  spyOn(guard, 'checkStore').and.returnValue(of(true));

  const result = guard.canActivate();
  expect(result).toBeObservable(of(true));
});

执行此规范时,我在 Karma 中遇到此错误:

TypeError:无法读取未定义的属性“indexOf” 在 Function.TestScheduler.parseMarbles (./node_modules/rxjs/_esm5/internal/testing/TestScheduler.js?:243:21)

我在这里缺少什么?我不想只为这一种方法使用大理石测试,但如果有人可以建议一种方法,那么我很乐意尝试!

【问题讨论】:

  • 这里是在黑暗中拍摄的完整照片,但是如果您将 expect 行更改为 result.subscribe(res =&gt; expect(res).toEqual(true)) 是否有效?我想知道,因为 .toBeObservable() 匹配器来自大理石测试库,也许他们的代码有问题。
  • 我看到了同样的事情!您找到解决方案或解决方法了吗@serlingpa?
  • 这是因为来自toBeObservable(expectedObservable)expectedObservable 应该是具有marbles 属性的TestObservable (TestColdObservable | TestHotObservable)。您需要使用cold()hot() 函数来创建一个。 medium.com/@bencabanes/…
  • @NickDarvey 不知道你在说什么:/你能写一个答案并添加一些具体细节吗?

标签: angular unit-testing jasmine rxjs karma-runner


【解决方案1】:

来自 NgRx 的示例 Effect testing 代码显示使用 toBeObservable 因此:

const expected = hot('-------a', {
  a: {
    type: '[Customers API] Search Customers Success',
    customers: [...],
  },
});

expect(
  effects.searchCustomers$({
    debounce: 20,
    scheduler: getTestScheduler(),
  })
).toBeObservable(expected);

.toBeObservable() 期待 TestHotObservableTestColdObservable,它们具有 marbles 属性。我来到这里是因为使用不带参数的.toBeObservable() 得到TypeError: Cannot read property 'marbles' of undefined 的错误。

如果您想使用不是 TestXXXObservable 类型的 observable 进行测试,您必须订阅它们并在订阅中验证结果,如 NgRx testing example 所示:

// create an actions stream and immediately dispatch a GET action
actions$ = of({ type: '[Customers Page] Get Customers' });

// mock the service to prevent an HTTP request
customersServiceSpy.getAllCustomers.and.returnValue(of([...]));

// subscribe to the Effect stream and verify it dispatches a SUCCESS action
effects.getAll$.subscribe(action => {
  expect(action).toEqual({
    type: '[Customers API] Get Customers Success',
    customers: [...],
  });
});

【讨论】:

  • 您先生是个天才!我正在使用 of() 而不是热或冷。非常感谢。
  • 如果我是个天才,我永远不会遇到错误并写下这个,但很高兴它帮助了某人:)
猜你喜欢
  • 1970-01-01
  • 2020-01-25
  • 1970-01-01
  • 1970-01-01
  • 2019-03-26
  • 1970-01-01
  • 2019-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多