Mokkapps Logo

How To Easily Write And Debug RxJS Marble Tests

Michael Hoffmann (Mokkapps) - Senior Frontend Developer (Freelancer)
September 09, 2019
2 Minuten Lesezeit
- Ansichten
How To Easily Write And Debug RxJS Marble Tests Image

End of 2018 I wrote an article about how I write marble tests for RxJS observables in Angular. The content in there is still valid but I found recently a new library which I like and which makes debugging marble tests easier.

If you do not know RxJS marble tests yet then I would recommend you to first read my article which covers the basics.

As quick catchup, the following example shows a marble diagram which can be used in tests to represent an observable:

const obs = `-a-^-b--|`;
//              012345`, emits 'b' on frame 2, completes on 5 - hot observable ^ represents when the subscription started

In this article, I want to talk about rx-sandbox which is a marble diagram DSL based test suite for RxJS 6. It also has support for RxJS 5 in pre-1.x versions if you need that in your application.

Why rx-sandbox?

I found this library as I was looking for a better way to debug marble tests as it was not possible to see such a test output using the jasmine-marbles library:

+ Source: "--x-x--|"
- Expected: "---x-x--|"

In my opinion, this is a really easy and understandable representation of what went wrong in the test.

The library also has some other nice features:

  • No dependencies to a specific test framework
  • Near-zero configuration, works out of box
  • Supports extended marble diagram DSL
  • Provides feature parity to TestScheduler

Hello World Example

This is simple example of a marble test using rx-sandbox from the official GitHub repository:

import { expect } from 'chai';
import { rxSandbox } from 'rx-sandbox';

it('testcase', () => {
  const { hot, cold, flush, getMessages, e, s } = rxSandbox.create();
  const e1 = hot('  --^--a--b--|');
  const e2 = cold('   ---x--y--|', {x: 1, y: 2});

  const expected = e('       ---q--r--|');
  const sub =      s('       ^        !');

  const messages = getMessages(e1.merge(e2));



More Realistic Example

As things are typically more complicated than in the simple examples, I have created a project which contains a more realistic scenario with this simple architecture:

Angular test project architecture
Angular test project architecture

The demo application contains these services:

  • NewsApiService: Represents a service which simulates an API communication to fetch news
  • AppFacadeService: The facade which is used between AppComponent and NewsApiService to handle the communication and add additional functionality on top of the API calls

The relevant marble tests are located in app-facade.service.spec.ts.

Create Test Instance

import { rxSandbox } from 'rx-sandbox';

import { AppFacadeService } from './app-facade.service';
import { NewsApiService, testData } from '../api/news-api.service';

describe('AppFacadeService', () => {
  let sut: AppFacadeService;
  let newsApiService: any;
  let rx: any;

  beforeEach(() => {
    // we need to create a  sandbox for each test run  
    rx = rxSandbox.create();
    const { cold, hot } = rx;

    // we mock the API service and return mocked observables which are created by marble strings
    newsApiService = jasmine.createSpyObj('NewsApiService', [
      cold('a', {
        a: testData
      hot('a-^-a-b-c|', {
        a: testData[0],
        b: testData[1],
        c: testData[2]

    // we create a new instance of the service and pass the mock service to its constructor
    sut = new AppFacadeService(newsApiService);

Marble Test

After creating the test setup we are now ready for our first test:

it('should return news from stream', () => {
    const { e, getMessages, flush } = rx;

    // create the expected observable by using marble string
    const expectedObservable = e('--a-b-c|', {
      a: testData[0],
      b: testData[1],
      c: testData[2]

    // get metadata from observable to assert with expected metadata values
    const messages = getMessages(sut.connect());

    // execute observables

    // When assertion fails, 'marbleAssert' will display visual / object diff with raw object values for easier debugging.

A failed test will show a similar output:

Angular Karma output failed test
Angular Karma output failed test

We can immediately see that the received observable emitted the events on different frames:

"Source:   --a-b-c|"
"Expected: --a-b---c|"

Additionally, the frames may be correct but the emitted values from source and expected observable differ.

The output for each event is in this format:

    "frame": 2,           // at which frame the event occurred
    "notification": {
      "error": undefined, // any error information
      "hasValue": true,   // true if there is a value
      "kind": "N",        // type of the event, N: next, E: error, C: complete
      "value": {          // content of the next event
        "author": "Mike", 
        "date": 2019-09-11T00:00:00.000Z, 
        "title": "New Xbox revealed"

So you will then compare these values from the received and expected observables. rx-sandbox will print you a diff to see the difference in the values:

@@ -17,18 +17,18 @@
     "notification": Notification {
       "error": undefined,
       "hasValue": true,
       "kind": "N",
       "value": Object {
-        "author": "Chris",
-        "date": 2019-12-12T00:00:00.000Z,
-        "title": "Overwatch 5 announced",
+        "author": "Florian",
+        "date": 2019-05-12T00:00:00.000Z,
+        "title": "Halo X Review",


In my experience, most developers struggle with interpreting the result of marble tests as libraries like jasmine-marbles do not provide a good visual representation of the expected and received streams.

rx-sandbox solves this problem by providing a visual representation of the expected & received marble string and a more readable diff of the values. Additionally, you can use the library in any frontend test framework.

Let me know your thoughts about this library in the comments.

Sie haben einen Fehler in diesem Artikel gefunden? Sie möchten gerne etwas klarstellen, aktualisieren oder hinzufügen?

Alle meine Artikel können auf Github editiert werden. Jeder Fix ist willkommen, egal wie klein er sein mag!

Ändern auf Github
Wenn Sie diesen Artikel hilfreich fanden. Werden Sie diese diese lieben.
How I Write Marble Tests For RxJS Observables In Angular Image

November 12, 2018

How I Write Marble Tests For RxJS Observables In Angular
How To Generate Angular & Spring Code From OpenAPI Specification Image

March 02, 2020

How To Generate Angular & Spring Code From OpenAPI Specification
Manually Lazy Load Modules And Components In Angular Image

January 07, 2020

Manually Lazy Load Modules And Components In Angular
How To Build An Angular App Once And Deploy It To Multiple Environments Image

December 09, 2019

How To Build An Angular App Once And Deploy It To Multiple Environments