错误:不变违规:Store.__emitChange():必须在调度时调用

Posted

技术标签:

【中文标题】错误:不变违规:Store.__emitChange():必须在调度时调用【英文标题】:Error: Invariant Violation: Store.__emitChange(): Must be invoked while dispatching 【发布时间】:2016-02-03 15:26:29 【问题描述】:

我正在尝试测试助焊剂商店。我使用来自flux/utilsjest 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);
  );

);

【问题讨论】:

所以,我最终切换到堆栈 mochachaisinon 并使用找到的解决方案 here 来测试商店,因为我使用 mocha 来测试我的其他模块.感谢@atomrc 提示我可以使用sinon 进行模拟,我以前不知道。 【参考方案1】:

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

所以我想出了一个更好、更简单的解决方案。这个想法:简单地模拟dispatcherisDispatching方法总是返回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);
);

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

【讨论】:

以上是关于错误:不变违规:Store.__emitChange():必须在调度时调用的主要内容,如果未能解决你的问题,请参考以下文章

测试套件无法运行。不变违规:_registerComponent(...):目标容器不是 DOM 元素

未捕获的不变违规:_registerComponent(...):目标容器不是 DOM 元素

JestJS -> 不变违规:在“连接(投资组合)”的上下文或道具中找不到“商店”

React-Redux/Jest 不变违规:找不到“商店”

不变违规:当元素在 DOM 中时,目标容器不是 DOM 元素

未捕获的不变违规:存储错误