Несоответствие RxJS BehaviorSubject getValue после передачи значения (во время тестирования в Jest)

Я не понимаю почему .getValue()возвращает значение по умолчанию для Observable, а не последнее выданное значение. При тестировании Observable он правильно возвращает выданное значение.

class TestA {
  readonly aSource: BehaviorSubject<number> = new BehaviorSubject(null);

  getA(): number {
    return this.aSource.getValue();
  }

  promise(): void {
    Promise.reject()
      .catch(() => {
        this.aSource.next(2);

        console.log(this.getA()); // Outputs: 2
      });
  }
}

describe('TestA', () => {
  it('promise', () => {
    const a = new TestA();
    a.promise();

    // Test 1 OK
    expect(a.aSource.asObservable()).toBeObservable(hot('a', {a: 2}));

    // Test 2 FAIL (returns null)
    expect(a.aSource.getValue()).toEqual(2);

    // Test 3 FAIL (returns null)
    expect(a.getA()).toEqual(2);
  });
});

Чтобы уточнить, getValue() Метод отлично работает вне тестов, он терпит неудачу только при тестировании с помощью Jest.

Благодарность!

3 ответа

Решение

Даже если я сделаю Promise.reject() код не оказывается синхронным, поэтому в этом случае вам нужно очистить очередь выполнения, чтобы протестировать этот код.

Решение с использованием вспомогательных функций Angular:

  it('promise', fakeAsync(() => {
    const a = new TestA();
    a.promise();

    flush();

    expect(a.aSource.asObservable()).toBeObservable(hot('a', {a: 2}));
    expect(a.aSource.getValue()).toEqual(2);
    expect(a.getA()).toEqual(2);
  }));

Причина в асинхронности функции обратного вызова catch. Итак, я думаю, что если вы обернете свое выражение ожидания в setTimeout, и запустите тест async, он стал зеленым.

Первое утверждение асинхронное. Внутренне он разрешитObservable, так что вы действительно получите 2.

Однако пока это ожидается, срабатывают два других утверждения. И они синхронны. Ничто не гарантирует вам, что в то время.nextзвонок был сделан. Так вы все равно получите исходное значение.

Вот почему я бы рекомендовал не использовать .getValue метод BehaviorSubjectа лучше подпишитесь на него как следует. Таким образом, вы избежите такой путаницы, всегда выполняя асинхронные операции.

Другие вопросы по тегам