笑话:监视react-redux调用(useDispatch)



我想检查是否调用了react-redux调度。在调试模式下,我可以看到各自的代码行被执行,因此实际上调用了分派,但在我的jest测试中,结果总是0调用。正确的做法是什么?

const mockDispatchFn = jest.fn();
jest.doMock('react-redux', () => ({
...jest.requireActual('react-redux'),
useDispatch: () => mockDispatchFn,
}));
...

expect(mockDispatchFn).toHaveBeenCalledWith(...);

doMockrequireActual不是真正可靠的,特别是对于可能已经被其他模块在其常量中或通过函数闭包捕获的东西。与其搜索如何使它工作,不如避免它。

选项1。更好的一个。

Redux文档在这里相当固执己见:

更喜欢编写集成测试,让所有东西一起工作。对于使用Redux的React应用程序,渲染一个包含被测试组件的真实存储实例的<Provider>。与被测试页面的交互应该使用真正的Redux逻辑,模拟API调用,以便应用程序代码不必更改,并断言UI已适当更新。

意思是:

  1. Real store reducer
  2. 模拟存储数据,我们将在该故事中调用dispatch和相关的操作创建者mockedStore.dispatch(someDataLoadedAction(someMockedData))
  3. 不检查dispatch是否被调用,根据应该发生的情况,我们将:a.通过选择器验证新的存储状态("在Component1中单击此按钮后,我们期望Redux的选择器getSomeFlag返回true")b.或验证其他发生的事情(网络调用已发送预期参数,文档标题已更改,导航已发生等)c.或验证我们的组件已根据新商店的状态更新

像这样:

const store = createStore(reducer, applyMiddleware(thunk));
// store preparation
store.dispatch(somethingLoadedSuccess(mock1));
store.dispatch(somethingChanged(someMock2));
// rendering component 
const { getByRole, getByText } = render(<Provider store={store}>
<ComopnentUnderTest prop1="a" prop2={something} />
</Provide>);
// simulating some scenario 
fireEvent.click(getByRole('button', { name: 'Save' }));
// asserting
expect(someSelector1(store.getState())).toBe(42);
expect(getByText('Saved successfully')).toBeInTheDocument();
expect(mockedNetworkLayer.isDone()).toBe(true);

选项2。很狡猾,也不那么可靠。

使用redux-mock-store可以很容易地检查哪些动作已经被调度,但是使用这种方法:

  1. 你不能在测试期间更改Redux状态,因此将无法测试某些情况
  2. 你需要用静态数据模拟存储树;测试变得脆弱——如果你对store的结构进行内部重构并正确更新了所有的选择器,你还需要在测试中更新所有模拟的静态数据,以使它们再次通过;测试变得不可靠——如果你对store的结构进行内部重构,而没有相应地更新选择器,测试仍然会通过,尽管应用程序会被破坏
// store preparation
const store = configureStore([thunk])(staticDataMockForAStore);
// rendering component 
const { getByRole, getByText } = render(<Provider store={store}>
<ComopnentUnderTest prop1="a" prop2={something} />
</Provide>);
// simulating some scenario 
fireEvent.click(getByRole('button', { name: 'Save' }));
// asserting
expect(store.getActions()).toContainEqual({
type: 'SOME_ACTION_TYPE',
value1: 1,
value2: 'a'
});

同样,对于这种方法来断言调度的操作,您可能需要expect.objectContaining忽略一些随机数据(UUID等)的属性

最新更新