Search code examples
javascriptunit-testingmocha.jsrefluxjs

Test state change of a reflux store with mocha


I am writing mocha tests against a Reflux store, to validate that an action causes the state within a store to change. The scaled-down version of the code is given below:

Store:

var AppStore = Reflux.createStore({
  init: function () {
    this.foo = false;
  },
  listenables: [AppActions],
  onFooAction: function() {
    this.foo = !this.foo;
    this.trigger({action: "foo-ed"});
  };
});

Action:

var AppActions = Reflux.createActions([
  "fooAction"
]);

Test:

it("toggles foo", function () {
  expect(AppStore.foo).to.equal(false);

  AppStore.listenables[0].fooAction();

  expect(AppStore.foo).to.equal(true);
});

However, the second assertion (expect(AppStore.foo).to.equal(true);) fails saying that foo is still false.

By performing a console.log within the onFooAction method, I've verified that the method is actually triggered and this.foo is getting toggled.

Is there anything fundamental that I am missing here: conceptually or otherwise? I sincerely hope that it is not a timing issue!


Solution

  • Actions emit events to which the stores listen. Basically, your test is just running too quickly.

    Usually, in my tests, I assume that Reflux is going to do what it does correctly, and I call the listener function directly. You'd want to add a few more assertions to make sure that Reflux is wired up correctly.

    it("is configured", function () {
      expect(AppStore.listenables).to.include(AppActions);
      expect(AppActions.fooAction).to.be.a('function');
    });
    
    it("toggles foo", function () {
      expect(AppStore.foo).to.equal(false);
    
      AppStore.onFooAction();
    
      expect(AppStore.foo).to.equal(true);
    });
    

    Another way you could test this is with a timeout, but I feel dirty when I put timeouts inside tests.

    it("toggles foo", function (done) {
      expect(AppStore.foo).to.equal(false);
    
      AppStore.listenables[0].fooAction();
    
      setTimeout(function () {
        try {
          expect(AppStore.foo).to.equal(true);
          done();
        } catch (e) {
          done(e);
        }
      }, 15);
    });