首页 > 解决方案 > Angular spyOn ngrx/store 在 Promise 范围内

问题描述

我正在使用以下设置编写带有 Angular TestBed 的测试:

let cacheService: CacheService;
let store: Store<PsaAppState>;
let service: ConfigService;

beforeEach(() => {
  TestBed.configureTestingModule({
    providers: [
      ConfigService,
      { provide: TranslateService, useValue: getMock(TranslateService) },
      { provide: CacheService, useValue: getMock(CacheService) },
      { provide: Store, useValue: getMock(Store) }
    ]
  });
  const injector: TestBed = getTestBed();
  service = injector.get(ConfigService);
  cacheService = injector.get(CacheService);
  store = injector.get(Store);
});

测试看起来像这样:

it('Should dispatch FetchFeatureConfigAction when promise is rejected', () => {
    spyOn(store, 'dispatch').and.stub();
    spyOn(cacheService, 'getRawItem').and.returnValue(Promise.reject('error'));

    service.getFeatureConfig();
    expect(store.dispatch).toHaveBeenCalledTimes(1);
    expect(store.dispatch).toHaveBeenCalledWith(new FetchFeatureConfigAction());
});

它测试的代码如下所示:

getFeatureConfig() {
    console.log('###Service called!!!');
    this.cacheService.getRawItem('APP_STATE_NAME').then(
      (appState: PsaAppState) => {
        console.log('###Resolve with ', appState);
        !isNil(appState.featureConfigState.featureConfig)
          ? this.store$.dispatch(new FetchFeatureConfigSuccessAction(appState.featureConfigState.featureConfig))
          : this.store$.dispatch(new FetchFeatureConfigAction());
      },
      err => {
        console.log('###Rejected with ', err);
        this.store$.dispatch(new FetchFeatureConfigAction());
      }
    );
  }

我可以在被拒绝的回调中看到日志(也可以在其他测试的已解决)中看到日志,但是期望失败且没有交互。我的假设是this.store$.dispatchPromis 范围内进行模拟是问题所在。

这个假设是否正确,我怎样才能使这个测试运行?

标签: angularpromisengrx

解决方案


根本原因是当服务被调用并被执行时,Promise 还没有解决console.log。这是由于 Javascript事件循环处理异步请求的方式。

错误情况的修复如下:

it('Should dispatch FetchFeatureConfigAction when promise is rejected', () => {
    spyOn(store, 'dispatch').and.stub();
    const expectedPromise = Promise.reject('error');
    spyOn(cacheService, 'getRawItem').and.returnValue(expectedPromise);

    service.determineFeatureConfig();
    expectedPromise.catch(() => {
      expect(store.dispatch).toHaveBeenCalledTimes(1);
      expect(store.dispatch).toHaveBeenCalledWith(new FetchFeatureConfigAction());
    });
});

我将 Promise 提取到一个变量中,然后在catch中期望工作正常。

对于好的情况,解决方案可以使用thenasync/await语法。后者的示例如下所示:

it('Should dispatch FetchFeatureConfigAction when promise is resolved', async () => {
    spyOn(store, 'dispatch').and.stub();
    const expectedPromise = Promise.resolve('success');
    spyOn(cacheService, 'getRawItem').and.returnValue(expectedPromise);

    service.determineFeatureConfig();
    await expectedPromise;
    expect(store.dispatch).toHaveBeenCalledTimes(1);
    expect(store.dispatch).toHaveBeenCalledWith(new FetchFeatureConfigAction());
});

推荐阅读