unit-testingrxjsrxjs-test-scheduler

How to test RxJS observable that emits multiple values in 1 frame?


Given the following code:

import {merge, Observable} from "rxjs";

export function springLatch(handle$: Observable<boolean>, closedByDefault: boolean): Observable<boolean> {
    const latch$ = new Observable<boolean>((subscriber) => {
        if (closedByDefault) {
            subscriber.next(false);
        } else {
            subscriber.next(true);
        }
        handle$.subscribe({
            next(value: boolean) {
                if (closedByDefault && value) {
                    subscriber.next(value);

                } else {
                    subscriber.next(value);
                }
            }
        })
    });

    return merge(handle$, latch$);
}

Tested by this unit-test:

describe('SpringLatchTest', () => {
    let testScheduler: TestScheduler;
    beforeEach(() => {
        testScheduler = new TestScheduler((actual, expected) => {
            expect(actual).toBe(expected);
        });
    });

    it('should do something', () => {
        testScheduler.run(({cold, expectObservable}) => {
            // Assemble
            const handle$ = cold('-t-f', {t: true, f: false});
            // Act
            const actual: Observable<boolean> = springLatch(handle$, true);
            // Assert
            expectObservable(actual).toBe('fttff', {t: true, f: false});
        });
    });
});

Based on the above I have several questions related to value emissions and frames.

Versioning

"jest": "^29.5.0",
"rxjs": "^7.8.0"

Solution

  • RxJS has a very good documentation regarding RxJS marble testing. If you need to test that there were multiple next emissions within the same frame you can wrap expected emissions with parenthesis ().

    For example, '(fttff)' means all emissions happened at frame 0. Or '(ft)(tff)' means ft were emitted at frame 0 and then tff at frame 4.

    There's a known limitation with marble tests. You can't expect groups of emissions that would overlap because each group start at char index of its (.