The right way to test rxjs
Time has passed, and now it is definitely possible (even easy) to use these marble tests yourself using TestScheduler
. They are a great way to comprehensively test emissions over time, errors, completions and subscriptions in an easy-to-understand format. Here is a sample from their docs:
import { TestScheduler } from 'rxjs/testing';
const testScheduler = new TestScheduler((actual, expected) => {
// asserting the two objects are equal
// e.g. using chai.
expect(actual).deep.equal(expected);
});
// This test will actually run *synchronously*
it('generate the stream correctly', () => {
testScheduler.run(helpers => {
const { cold, expectObservable, expectSubscriptions } = helpers;
const e1 = cold('-a--b--c---|');
const subs = '^----------!';
const expected = '-a-----c---|';
expectObservable(e1.pipe(throttleTime(3, testScheduler))).toBe(expected);
expectSubscriptions(e1.subscriptions).toBe(subs);
});
});
If you use Jasmine, I wrote a little helper called marbleTest()
to reduce boilerplate, available in @s-libs/ng-dev
:
import { marbleTest } from "s-ng-dev-utils";
it("generate the stream correctly", marbleTest(helpers => {
const { cold, expectObservable, expectSubscriptions, testScheduler } = helpers;
const e1 = cold(" -a--b--c---|");
const subs = " ^----------!";
const expected = "-a-----c---|";
expectObservable(e1.pipe(throttleTime(3, testScheduler))).toBe(expected);
expectSubscriptions(e1.subscriptions).toBe(subs);
}));
I have been getting this question a lot from my colleagues. I finally got around to document my ways of testing RxJs on my blog. Since your question seems to be related to RxJs5 i will only quote the relevant part of my post here.
Testing in RxJs5 the RxJs4 way
When you migrate your codebase from RxJs4 towards 5 you will find out that a lot of things have been moved, renamed and above all that the implementation of the TestScheduler is no longer available. RxJs contributor kwonoj has created a compatibility shim to help migration towards RxJs5. You can install it using npm npm install @kwonoj/rxjs-testscheduler-compat
. Not all features of the TestScheduler are implemented but the most important .startScheduler
is working.
const TestScheduler = require('@kwonoj/rxjs-testscheduler-compat').TestScheduler;
const next = require('@kwonoj/rxjs-testscheduler-compat').next;
const complete = require('@kwonoj/rxjs-testscheduler-compat').complete;
it('works in RxJs5 with the compat package', () => {
const scheduler = new TestScheduler(); // Note; no longer the Rx.TestScheduler
const results = scheduler.startScheduler(
() => Rx.Observable.interval(100, scheduler).take(3),
{ created: 100, subscribed: 200, unsubscribed: 1000 } // NOTE: disposed is now renamed to unsubscribed
);
collectionAssert.assertEqual(res.messages, [
next(200 + 100, 0),
next(200 + 200, 1),
next(200 + 300, 2),
complete(200 + 300)
]);
});
Testing in RxJs5 using the new Marble testing syntax
The RxJs team has introduced marble testing syntax to more visually define how your operator or custom code should operate.
var e1 = hot('----a--^--b-------c--|');
var e2 = hot( '---d-^--e---------f-----|');
var expected = '---(be)----c-f-----|';
expectObservable(e1.merge(e2)).toBe(expected);
At the time of writing this post they have not yet made this approach really easy to use outside of the RxJs5 library itself. There are implementations available to see how to do it yourself. You can also look around in the codebase of RxJs5 to see how to setup your testing framework to do your own marble tests. There is an open issue about documenting testing with RxJs5. I have not yet succeeded to get my testing framework setup to do marble testing in this way.