3

I have a very simple periodic activity which is scheduled by RxJS 5 and I'm a bit curious about how to unit test this type of code using RxJS 5:

start() {
  this._subscription = Observable
                        .interval(this._interval, SchedulerProvider.getScheduler())
                        .subscribe(_ => this.doSomething());
}
stop() {
  this._subscription.unsubscribe();
}

What I tried is to stub my SchedulerProvider.getScheduler function to return a new TestScheduler() during my tests (by default it just returns undefined so the production code just uses the default scheduler) - and then try to setup virtual "ticks" for the interval:

myTestSchedulerInstance.createColdObservable('xxxxxxxx', {x: 1}); // tick ten times
unitUnderTest.start();
myTestSchedulerInstance.flush();
... assert that doSomething() should be called 10 times ....

But it doesn't work. I guess createColdObservable and createHotObservable just returns a new observable based on the marble-syntax input string - but this doesn't affect my interval.

I went through the docs and I'm a bit confused now about the marble testing in RxJS 5, because the examples in the docs (and everywhere else) look like this:

  • in the first step: create a test scheduler
  • then create a cold/hot observable using this scheduler
  • your unit under test applies some operators on the created observable - which produces another observable
  • then you assert on the resulting observable using expectObservable

But my use-case is different. I don't want to return the Observable.interval, because I'm only interested in the side-effect of my subscription. Is it possible to write such a test using RxJS 5?

The only alternatives which I see right now:

  • use sinon's fake timers
  • inside start(), map the side effect to the interval and after subscribing to it, return the observable containing the side effect -> and use it in the assertion using expectObservable

But each solution seems to be a bit messy.

Zsolt
  • 3,263
  • 3
  • 33
  • 48
  • Does this help you? http://stackoverflow.com/questions/42732988/how-do-i-test-a-function-that-returns-an-observable-using-timed-intervals-in-rxj/42734681#42734681 – martin Mar 20 '17 at 12:33
  • @martin Your solution there looks like alternative 2. which I described in the question. While this could work, I don't want to expose RxJS outside of the module... I'd like to assert on the side effect of my subscription, not on the resulting Observable. Maybe VirtualTimeScheduler is the correct way to do this, but it's not documented.... (?) – Zsolt Mar 20 '17 at 12:48
  • So you want to test that the `this.doSomething()` is called or what? – martin Mar 20 '17 at 12:50
  • @martin Yes. Of course this is a simplification. `doSomething` can have side effects, and later I'd like to assert on them instead of testing that a single function is called. What I'd like to find out is a general solution for the scenario: if you have an observable chain and a subscription with side effects, how to assert on the side effects while you are "faking" the inputs inside your observable chain: faking the "what" and the "when". – Zsolt Mar 20 '17 at 13:00
  • Well, this is not how RxJS tests its Observables. If you want to test them properly you need some test observer that records message times so you don't want to call `.subscribe()` yourself. One common way used in the official RxJS 5 tests is chaining `.do()` and using only the `complete` handler to perform some assertion. See for example this https://github.com/ReactiveX/rxjs/blob/c81882f289ebb58aae8a60d480da6aa871ab762f/spec/operators/single-spec.ts#L167 – martin Mar 20 '17 at 13:42
  • So are you saying that my `.start()` function above should just return the `Observable.interval(100).do(_ => this.doSomething())` without doing any subscription? – Zsolt Mar 20 '17 at 14:15
  • Basically yes. Then when testing you can append another `.do()` and test that it gets called as many times as you need (or just test the output with marbles). You'll leave the subscription to the `TestScheduler`. – martin Mar 21 '17 at 06:33

0 Answers0