Error: Invariant Violation: Store.__emitChange(): Must be invoked while dispatching
Error: Invariant Violation: Store.__emitChange(): Must be invoked while dispatching
我正在尝试测试助焊剂存储。我使用来自 flux/utils
、jest
v0.7.0 的 ReduceStore
。当我使用模拟调度程序调度操作时出现错误:
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);
});
});
[编辑]
好的,我在这里提出的第一个解决方案实际上是错误的。它的坏处是,当真正使用 dispatch
时,它会将操作发送到所有经过测试的商店。因此,您最终会调用所有商店,而只测试一个商店。这是您可能不想要的副作用。
所以我想出了一个更好更简单的解决方案。这个想法:简单地模拟dispatcher
的isDispatching
方法总是returntrue
.
这样您的商店在调用 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);
});
我想这是一个可以接受的解决方案,即使它不是官方文档中建议的解决方案。
我正在尝试测试助焊剂存储。我使用来自 flux/utils
、jest
v0.7.0 的 ReduceStore
。当我使用模拟调度程序调度操作时出现错误:
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);
});
});
[编辑]
好的,我在这里提出的第一个解决方案实际上是错误的。它的坏处是,当真正使用 dispatch
时,它会将操作发送到所有经过测试的商店。因此,您最终会调用所有商店,而只测试一个商店。这是您可能不想要的副作用。
所以我想出了一个更好更简单的解决方案。这个想法:简单地模拟dispatcher
的isDispatching
方法总是returntrue
.
这样您的商店在调用 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);
});
我想这是一个可以接受的解决方案,即使它不是官方文档中建议的解决方案。