【问题标题】:How to test RxJs observable callback with NgRx setState如何使用 NgRx setState 测试 RxJs 可观察回调
【发布时间】:2022-02-12 18:39:25
【问题描述】:

我想知道如何测试 .subscribe 回调中的代码,订阅位于 NgRx 存储选择器上。

环境:Angular 13、RxJs 7+、NgRx 13、Jest 27

考虑

my-component.ts

...
ngOnInit {
  this.myValue = true;
  this.store.select(mySelector).pipe(filter(data => data.attribute === true)).subscribe(data => {
    this.myValue = false; // I want to test this
  }
}
...

my-component.spec.ts

describe('MyComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;
  let store: MockStore;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [MyComponent],
      imports: [...],
      providers: [
        provideMockStore({
          initialState: { myFeature: { } },
        }),
      ],
    }).compileComponents();

    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();

    store = TestBed.inject(MockStore);
  });

  it('should perform animation & redirect to /dashboard if login successful', () => {
    store.setState({
      myFeature: {
        ...
        attribute: true,
      },
    });

    expect(component.myValue).toBe(false);
  });

这可行,但它是随机的。由于这是异步的,我可以在调用 subscribe 回调之前测试 myValue 并且测试会失败,例如,如果我的 subscribe 回调需要时间来做一些事情,就像这样(我添加了 500 毫秒的延迟):

...
ngOnInit {
  this.myValue = true;
  this.store.select(mySelector).pipe(filter(data => data.attribute === true), delay(500)).subscribe(data => {
    this.myValue = false; // I want to test this
  }
}
...

这失败了。

在测试我的值之前如何等待回调执行?我可以在测试之前等待任意时间(例如 1 秒),但它可能会在未来的任何时候中断,它不够强大。喜欢:

it('should perform animation & redirect to /dashboard if login successful', 
async () => {
    store.setState({
      myFeature: {
        ...
        attribute: true,
      },
    });
    await lastValueFrom(timer(600)); //rxjs 7
    expect(component.myValue).toBe(false);
  });

感谢您的帮助

【问题讨论】:

    标签: testing jestjs rxjs ngrx


    【解决方案1】:

    使用waitForAsyncfixture.whenStable 确保在评估expect 之前完成异步任务。

    it('should perform animation & redirect to /dashboard if login successful', waitForAsync(() => {
        store.setState({
          myFeature: {
            ...
            attribute: true,
          },
        });
        
        fixture.whenStable()
          .then(() => expect(component.myValue).toBe(false));
      }));
    

    【讨论】:

    • 它不起作用:(我认为它模拟了时间的流逝,但这里是“真实”时间,回调执行的时间。
    • 无论如何它都应该“快进”并完成所有异步操作。堆栈闪电战会很有用,它们很难将测试纳入其中,但这是可能的。仔细想想,很可能是因为组件中的 subscribe 是通过 ngrx “分离”的,所以 fakeAsync 不知道它。我有另一个想法,稍后我会发布。
    • 更改了答案,我已经用delay 对此进行了测试,它可以工作。
    猜你喜欢
    • 1970-01-01
    • 2019-05-15
    • 1970-01-01
    • 2019-10-05
    • 2019-07-15
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多