错误:不变违规:存储.__ emitChange():必须在调度时调用

时间:2015-11-03 12:57:55

标签: unit-testing reactjs reactjs-flux jestjs immutable.js

我正在尝试测试助焊剂储存。我使用ReduceStore中的flux/utilsjest v0.7.0。当我向模拟的调度员发送动作时,我收到一个错误:

Error: Invariant Violation: Store.__emitChange(): Must be invoked while dispatching.

如果我在真实浏览器中使用此商店,它会按预期工作。

这是我的商店:

import {ReduceStore} from 'flux/utils';
import Immutable from 'immutable';
import Dispatcher from '../dispatcher';
import actionConstants from '../action-constants';

class EntryStore extends ReduceStore {

  getInitialState() {
    return Immutable.List();
  }

  reduce(state, action) {
    switch (action.type) {
      case actionConstants.ENTRIES_REQUEST_SUCCESS:
        return state.merge(action.payload.entries);

      default:
        return state;
    }
  }

}

const instance = new EntryStore(Dispatcher);
export default instance;

并且,这是一个测试文件:

jest.autoMockOff();
jest.mock('../../dispatcher');
const actionConstants = require('../../action-constants');    

describe('EntryStore', function() {

  let Dispatcher, EntryStore, callback;

  // mock entries
  entries = [1, 2, 3];
  // mock actions
  const Immutable = require('immutable');
  const entriesRequestSuccess = {
    type: actionConstants.ENTRIES_REQUEST_SUCCESS,
    payload: {
      entries: Immutable.List(entries)
    }
  }

  beforeEach(function() {
    Dispatcher = require('../../dispatcher');
    EntryStore = require('../entry-store');
    callback = Dispatcher.register.mock.calls[0][0];
  });

  it('should update entries when entries request succeed', function(done) {
    callback(entriesRequestSuccess);
    let all = EntryStore.getState();
    expect(all.size).toBe(3);
  });

});

1 个答案:

答案 0 :(得分:1)

[编辑] 好的,我在这里提出的第一个解决方案实际上是错误的关于它的坏处是,当真正使用dispatch时,它会将动作发送到所有经过测试的商店。因此,您最终只需要测试一个商店就可以调用所有商店。这可能是你不想要的副作用。

所以我提出了一个更好,更简单的解决方案。想法:只需模仿isDispatching dispatcher方法即可始终返回true
通过这种方式,您的商店在调用emitChange方法时不会抱怨。例如sinon.js

sinon.stub(dispatcher, "isDispatching", function () { return true; });

看起来好多了不是吗? :)

--------------------- 以前的解决方案 ----------------- -------

这不是一个可行的解决方案!!

好好看一下这段代码(https://github.com/facebook/flux/blob/master/src/stores/FluxStore.js#L131),因为state.merge()方法调用__emitChange()方法,我想我们无法用模拟的调度程序来测试我们的商店。

所以我最终没有嘲笑我的调度员,只是在我的测试中调用dispatch方法。

var dispatcher = require("path/to/appDispatcher")
     UserStore = require("path/to/userStore");

var userStore = new UserStore(dispatcher);

it("should load user datas", function () {
    var user = {
       firstname: "Felix",
       lastname: "Anon"
    };


    //actually dispatch the event
    dispatcher.dispatch(actions.RECEIVE_USER, { user: user });
    //test the state of the store
    expect(userStore.get()).to.be(user);
});

我想这是一个可以接受的解决方案,即使它不是官方文档中建议的解决方案。