Angular NgRx 集成测试不工作(使用 Nx 和 Jest)

Angular NgRx integration test not working (with Nx and Jest)

我有一个在幕后使用 NgRx 的外观 class。当我在我的应用程序中使用它时,外观本身正在工作,但通过集成测试它不起作用(更好的说法是:测试不起作用)。我正在使用 Nx(不要认为那很重要)和 Jest。

注意:对于集成测试,我的意思是我不想模拟 NgRx 部分,我也想测试 NgRx 逻辑。只有数据服务被模拟。

外观class非常简单。这是它的摘录:

@Injectable({
  providedIn: 'root'
})
export class ProfileFacade {
  public isProfileLoaded$ = this.store.select(Selectors.isProfileLoaded);

  public constructor(private store: Store<fromProfile.PartialState>) {
    /* */
  }

  public loadProfile(): void {
    this.dispatch(Actions.loadProfile());
  }

  private dispatch(action: Action): void {
    this.store.dispatch(action);
  }
}

dipatched loadProfile 操作触发的效果是 returns ProfileLoadSucceeded 操作包含通过 ProfileService 获取的数据。然后,reducer 捕获此操作,将配置文件数据放入存储中,并将 isProfileLoaded 属性 设置为 true。

这是我的集成测试设置:

describe('ProfileFacade integration', () => {
  let facade: ProfileFacade;
  let store: Store<fromProfile.PartialState>;
  let profileServiceSpy: SpyObject<ProfileService>;

  beforeEach(() => {
    @NgModule({
      imports: [
        StoreModule.forFeature(fromProfile.PROFILE_FEATURE_KEY, fromProfile.reducer),
        EffectsModule.forFeature([ProfileEffects])
      ],
      providers: [
        ProfileFacade,
        mockProvider(ProfileService),
      ]
    })
    class CustomFeatureModule {}

    @NgModule({
      imports: [NxModule.forRoot(), StoreModule.forRoot({}), EffectsModule.forRoot([]), CustomFeatureModule]
    })
    class RootModule {}
    TestBed.configureTestingModule({ imports: [RootModule] });

    store = TestBed.inject(Store);
    facade = TestBed.inject(ProfileFacade);
    profileServiceSpy = TestBed.inject(ProfileService) as SpyObject<ProfileService>;
  });

  ...
});

以下是我在集成测试中尝试过的许多事情的精选:

  1. 用 expect(...).toBeObservable(...)

      it(`should set isProfileLoaded to true`, () => {
        profileServiceSpy.get.and.returnValue(hot('^x|', { x: profile }));  // I've tried several variations of hot and cold
        facade.loadProfile();
    
        const expected = cold('--b', { b: true });
        expect(facade.isProfileLoaded$).toBeObservable(expected);
      });
    
  2. 使用 toPromise() 和 then()

      it(`should set isProfileLoaded to true`, () => {
        // same 2 lines as in 1)
    
        return facade.isProfileLoaded$.toPromise().then(result => expect(result).toBe(true));
      });
    
  3. 用 expect(...toPromise()).resolves()

      it(`should set isProfileLoaded to true`, () => {
        // same 2 lines as in 1)
    
        return expect(facade.isProfileLoaded$.toPromise()).resolves.toBe(true);
      });
    
  4. 订阅并完成()

      it(`should set isProfileLoaded to true`, done => {
        // same 2 lines as in 1)
    
        facade.isProfileLoaded$.subscribe(result => {
          expect(result).toBe(true);
          done();
        });
      });
    

我只是展示了 isProfileLoaded 的测试,但我对数据本身的测试也有同样的问题。结果值始终为 false 或 null:门面的选择器结果似乎没有反映商店的内容。

虽然商店本身似乎运作良好。通过在不同的地方添加 console.log 语句,我可以看到来自模拟服务的数据正在按预期流动。它存在于 effect、reducer 和结果状态中。

我想我遗漏了一些明显的东西,但是什么?我还没有找到使用这种技术组合执行这种集成测试的示例。

由于您已经在使用 Nx,我能想到的一种方法是:

import { readFirst } from '@nrwl/nx/testing';

it(`should set isProfileLoaded to true`, async (done) => {
  try {
    profileServiceSpy.get.and.returnValue(of(profile));

    facade.loadProfile();

    const isProfileLoaded = await readFirst(facade.isProfileLoaded$);

    expect(isProfileLoaded).toBeTruthy();

    done();
  } catch (error) {
    done.fail(error);
  }
});