【问题标题】:How to assert that "some" value is emitted by an RxJS Observable如何断言“一些”值是由 RxJS Observable 发出的
【发布时间】:2022-09-28 18:05:27
【问题描述】:

在测试一个发出值的 observable 时,我想断言最终会发出一个值。对于每个要测试的值,我希望能够使用matcher,类似于.resolves 匹配器。

import { from } from \'rxjs\';
test(\'observable eventually matches value\', async () => {
   const testObservable$ = from([{ a: 1 }, { a: 2 }, { a: 3 }]);
   await expect(testObservable$).some.toMatch({ a: 2 });
});

使用lastValueFromfirstValueFrom 测试第一个或最后一个值会很简单。但是在firstValueFrom 的情况下,测试的弹性会降低,因为向可观察对象发出任何新的“中间”值可能会过度破坏测试。

    标签: jestjs rxjs


    【解决方案1】:

    首先,我将假设您想要一个发出三个单独值的 observable,而不是(如您所写)发出一个包含三个值的数组的 observable。

    除非您想编写自己的匹配器(或找到一些现有的 RxJS Jest 匹配器库),否则最简单的方法是编写一个帮助器来获取是否从可观察对象发出匹配值的承诺,例如:

    import { first, firstValueFrom, from, Observable } from 'rxjs';
    
    test('observable eventually matches value', async () => {
      const testObservable$ = from([{ a: 1 }, { a: 2 }, { a: 3 }]);
      await expect(eventually(testObservable$, { a: 2 })).resolves.toBe(true);
    });
    
    function eventually<T>(stream$: Observable<T>, expected: T): Promise<boolean> {
      return firstValueFrom(stream$.pipe(first((actual) => {
        try {
          expect(actual).toEqual(expected);
          return true;
        } catch {
          return false;
        }
      }))).then(() => true).catch(() => false);
    }
    

    如果匹配值是绝不发出,这失败了:

    • 如果 observable 在超时内完成(包括错误),则比较失败:

      Expected: true
      Received: false
      
    • 否则超时错误:

      thrown: "Exceeded timeout of 5000 ms for a test.
      Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
      

    【讨论】:

    • 关于数组的要点,我已经相应地更新了问题以使用from() 而不是of(),谢谢!
    【解决方案2】:

    万一有人想为此添加一个依赖项,我创建了RxJeSt。导入这个包扩展了 Jest 对 observables 的新.toEmit 断言的期望。

    在空目录中创建一个最小包:

    $ npm init --yes
    $ npm install rxjs
    $ npm install --save-dev jest rxjest
    $ npm pkg set scripts.test=jest
    

    然后将以下内容添加到index.test.js

    require("rxjest");
    const { from } = require("rxjs");
    
    it("works like this", () => {
      const testObservable$ = from([{ a: 1 }, { a: 2 }, { a: 3 }]);
      return expect(testObservable$).toEmit({ a: 2 });
    });
    

    您应该可以使用 npm run test 运行它并看到它失败:

    $ npm t
    
    > temp@0.1.0 test
    > jest
    
     FAIL  ./index.test.js
      ✕ works like this (3 ms)
    
      ● works like this
    
        expect(received).toEmit(expected) // deep equality
    
        Expected value: "foo"
        Emitted values: [{"a": 1}, {"a": 2}, {"a": 3}]
    
          4 | it("works like this", () => {
          5 |   const testObservable$ = from([{ a: 1 }, { a: 2 }, { a: 3 }]);
        > 6 |   return expect(testObservable$).toEmit("foo");
            |                                  ^
          7 | });
          8 |
    
          at Object.toEmit (index.test.js:6:34)
    
    Test Suites: 1 failed, 1 total
    Tests:       1 failed, 1 total
    Snapshots:   0 total
    Time:        0.306 s, estimated 1 s
    Ran all test suites.
    

    现在将期望值更新为实际发出的值,例如.toEmit({ a: 2 });,它应该通过就好了。

    【讨论】:

      猜你喜欢
      • 2019-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-03
      • 2019-02-24
      • 2019-10-09
      • 2018-01-18
      相关资源
      最近更新 更多