Testing rxjs: How to fake-click an element and check the resulting stream with marble diagrams?

Viewed 523

My intent: I have a view component that emits a stream of instructions on clicks to its members. I want to test that clicking on the buttons emits the instructions in the expected order for all interactive elements.

I've compiled a small example with the buttons a and b, which should emit the strings 'a' and 'b' into the same observable.

I'll add the import statements for convenience:

import $ from 'jquery';
import { TestScheduler } from 'rxjs/testing/TestScheduler';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do;
import 'rxjs/add/observable/merge';

Create a container, and append both a and b buttons.

const container = document.createElement('div');
const a = document.createElement('button');
const b = document.createElement('button');
container.append(a);
container.append(b);

Create click streams from both buttons' click events and merge them.

const stream = Observable.merge(
  Observable.fromEvent(a, 'click').map(() => 'a'),
  Observable.fromEvent(b, 'click').map(() => 'b')
);

Create a test scheduler for marble-tests.

const marbles = new TestScheduler((x, y) => expect(x).to.deep.equal(y));

This cold observable should, as a side-effect, click on the buttons. I'm not sure it does, in fact, I'm pretty sure it doesn't. Why?

marbles.createColdObservable('-a-b', { a, b }).do(element => $(element).click());

I expect to see the emissions of both buttons as per definition of const stream above.

marbles.expectObservable(stream).toBe('-a-b');
marbles.flush();

The result is:

AssertionError: expected [] to deeply equal [ Array(2) ]

Because no click events ever get generated. Why? I'm assuming that my assumption is wrong that the above code actually generates click events. If so, (how else) can I test actual DOM click events using marble diagrams?

Note: this is a minimal example, the actual code I want to test is more complex, and involves some buttons changing state as a result of conditions I manipulate via other marble diagrams. I would not want to test Observable.fromEvent, I'd like to test that my stream definition in const stream does the right thing.

1 Answers

The solution turned out to be to subscribe to the cold observable created via marbles.

marbles
  .createColdObservable('-a-b', { a, b })
  .do(element => $(element).click())
  .subscribe();

Otherwise the marbles' side-effects don't get executed. Stupid mistake on my part, it turned out!

Related