LiveLoveApp logo

Solution - Subscription

Solution

import { TestScheduler } from 'rxjs/testing';

describe('getting started with RxJS testing with marbles', () => {
  let testScheduler: TestScheduler;

  beforeEach(() => {
    testScheduler = new TestScheduler((actual, expected) =>
      expect(actual).toEqual(expected)
    );
  });

  test('subscribe', () => {
    testScheduler.run(({ hot, expectObservable }) => {
      const values = {
        a: 0,
        b: 1,
        c: 2
      };
      const source = hot('100ms a 99ms b 99ms c|', values);
      const subscription1 = '   200ms ^ 100ms !';
      const subscription2 = '           300ms ^';
      const expected1 = '        200ms b 99ms c';
      const expected2 = '               300ms c|';
      expectObservable(source, subscription1).toBe(expected1, values);
      expectObservable(source, subscription2).toBe(expected2, values);
    });
  });
});

See example on codesandbox

Let's review the solution above:

  • A new instance of the TestScheduler is created in the beforeEach() method.
  • Within the test, we invoke the run() method on the TestScheduler instance, and provide the callback function. We use object destructuring to define block-scoped variables for the hot and expectObservable properties of the RunHelpers object.
  • For clarity, I've decided to declare the values object that represents the values of the next notifications for the source Observable.
  • We create the source Observable using the hot() function. We progress the virtual time by 100 milliseconds (or 100 frames) and then emit the value represented by a. The first value of '0' is emitted on frame 100. This is because the first frame is frame 0, which is necessary for testing a synchronous Observable. Then, we progress the virtual time by 99 milliseconds (or 99 frames), and then emit the value represented by b. Again, we progress virtual time by 99 milliseconds (or 99 frames), and then emit the value represented by c. Finally, the completion notification emits on frame 301.
  • The first subscription is represented by subscription1. After 200 milliseconds the Observer subscribes to the hot Observable. Then, after an additional 100 milliseconds the Observer unsubscribes.
  • Let's skip to the expectation for the first Observer, which is represented by expected1. First, we progress virtual time by 200 milliseconds (or 200 frames). Again, remember that the frames are 0-based. So, on frame 200 we expect a next notification of the value represented by b. Then, we progress virtual time by 99 milliseconds (or 99 frames), and then emit the value represented by c. We do not expect the first Observer to receive the completion notification from the source Observable in frame 301. This is because the Observer unsubscribed in frame 300.
  • Now, let's go back and revisit the second Observer that is represented by subscription2. After 300 milliseconds the Observer subscribes to the hot Observable. The second Observer next unsubscribes from the Observable.
  • We expect the behavior of the second Observer as defined in the expected2 string. In this instance we progress virtual time by 300 milliseconds (or 300 frames). On frame 300 (again frames are 0-based) we expect a next notification from the source Observable of the value represented by c. Finally, on frame 301 we expect the Observer to receive the completion notification.