How to pause and resume virtual time when using marble testing with rxjs?

60 views Asked by At

I'm trying to write a test for an object that has both reactive elements and non-nonreactive elements. I cannot figure out how to write the marble diagrams so the test is legible.

In the test below, I have an object I'm testing that both stores a value and publishes it to a subject. I want to write the test so I can emit some values, stop virtual time, and check some assertions. Then, I want to resume virtual time. So, I think I want to use flush.

The test below succeeds, but it's not legible: The marble diagrams for source2 and expected2 don't line up with each other, so I can't really "see" that the test is written correctly. And if I define source2 above the first call to expectObservable, then the second call to expectObservable never sees any values.

class StoresLatestValue {
  constructor() {
    this.subject = new Subject();
  }
  emit(value) {
    this.latest = value;
    this.subject.next(value);
  }
}

test("StoresLatestValue works", () => {
  new TestScheduler((actual, expected) => expect(actual).toEqual(expected)).run(
    (helpers) => {
      const { flush, hot, expectObservable } = helpers;
      const obj = new StoresLatestValue();

      // First half of the test
      const source1 = hot("a-b-c");
      const expected1 = "  a-b-c";
      source1.subscribe((val) => obj.emit(val));
      expectObservable(obj.subject).toBe(expected1);
      flush();

      // Check that the latest value is what we expect
      expect(obj.latest).toBe("c");

      // These next two marble diagrams work, but since they don't line up,
      // it's hard to know that the test is written correctly
      const source2 = hot("d-e--");
      const expected2 = "  ----d-e--";
      source2.subscribe((val) => obj.emit(val));
      expectObservable(obj.subject).toBe(expected2);
      flush();

      // Check that the latest value is what we expect
      expect(obj.latest).toBe("e");
    }
  );
});

I've tried adding the subscription operator ^ to source, but it doesn't seem to help. I also tried using a cold observable, but I still can't write the marbles so everything lines up nicely:

// Making the second observable cold works, but still doesn't line up
const source1 = hot(" a-b-c");
const expected1 = "   a-b-c";
const source2 = cold("  -d-e--");
const expected2 = "   -----d-e--";

// Making them both cold doesn't seem to work at all, nothing is observed
// by the second expectObservable
const source1 = cold("a-b-c");
const expected1 = "   a-b-c";
const source2 = cold("-----d-e--");
const expected2 = "   -----d-e--";

Is there a way to write this test so it looks correct?

0

There are 0 answers