有角spyOn ngrx /存储在Promise范围内

时间:2019-06-28 13:06:48

标签: angular promise ngrx

我正在使用以下设置编写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());
      }
    );
  }

我可以在被拒绝的回调中看到日志(在其他测试中也可以看到),但是期望没有交互就失败了。我的假设是在 Promis范围中模拟this.store$.dispatch就是问题所在。

这个假设正确吗?如何进行此测试?

1 个答案:

答案 0 :(得分:0)

根本原因是,调用服务并执行console.log时,Promise尚未解决。这是由于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 内,期望工作正常。

在好的情况下,解决方案可以使用 then async / 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());
});