1

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.

  • How do I prevent the unit-test from failing due to mismatching frames between the actual observable and the expected observable based on the marble diagram?
  • Do values emissions have a a 1-to-1 relationship with frames?

Versioning

"jest": "^29.5.0",
"rxjs": "^7.8.0"
Byebye
  • 934
  • 7
  • 24

1 Answers1

1

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 (.

martin
  • 93,354
  • 25
  • 191
  • 226
  • Amazing! Thank you, I can't believe I read passed that. – Byebye Mar 17 '23 at 10:13
  • Question. I just tested this and it seems that I am not getting the results I was expecting. Reading the documentation: '--(abc)-|': on frame 2 emit a, b, and c, then on frame 8, complete. Whereas what I would expect is: on frame 2 emit a, b, and c, then on frame 5, complete. I tested this out with TestScheduler.parseMarbles('(tf)(tf)', {t: true, f: false}); and I'm getting the first 2 emissions on frame 0 and the second on frame 4. Do you think this is a bug? – Byebye Mar 17 '23 at 10:45
  • I just saw you already had this in your answer. My bad. Still it seems counter-intuitive. – Byebye Mar 17 '23 at 11:09
  • I agree it isn't completely obvious and sometimes confusing. But when you get used to it and you're aware of possible issues, it's great :). – martin Mar 17 '23 at 13:23