reactjs - 如何在 React 组件中测试 Redux 的 dispatch() 是否被调用(Jest + Enzyme)

标签 reactjs redux react-redux jestjs enzyme

我有很多函数式 React 组件调用 dispatch() (还原)。 dispatch()函数本身由 react-redux 的 useDispatch() 传入钩。
作为一个简化的例子:

const LogoutButton: FC = () => {
  const dispatch: Dispatch = useDispatch();
  
  return (
   <button onClick={() => {
     console.log("Clicked...") // To check that onClick() simulation is working
     dispatch(authActions.logout())  
   }}>
   LOGOUT
   </button> 
  )
}
使用 Jest 和 Enzyme,我需要做什么才能断言 expect(dispatch).toHaveBeenCalledWith(authActions.logout) ?
我没有模拟商店的功能或使用 redux-mock-store。相反,我将组件包装在我为测试而制作的 Root 组件中。它与我真正的 Root 组件相同,但需要 Prop 来设置测试的初始存储(和 history.location):
const TestRoot: FC<RootProps> = ({ children, initialState = {}, initialEntries = defaultLocation }) => {
  const store = createStore(reducers, initialState, applyMiddleware(thunk));

  return (
    <Provider store={store}>
      <MemoryRouter initialEntries={initialEntries}>
        <ScrollToTop />
        <StylesProvider jss={jss}>
          <ThemeProvider theme={theme}>{children}</ThemeProvider>
        </StylesProvider>
      </MemoryRouter>
    </Provider>
  );
};

它在测试中用于设置 Enzyme-wrapped 组件,如:
wrappedLogoutButton = mount(
  <TestRoot initialState={initialState}>
    <LogoutButton />
  </TestRoot>
);
这个设置对我来说很好(到目前为止),如果我不需要,我不想改变它。我确实尝试将 redux-mock-store 模拟存储注入(inject) TestRoot,但这搞砸了我编写的每个测试套件。
我已经尝试了多种方式来 mock 或监视两者 dispatch()useDispatch()但我没能看到模拟被调用。 onClick()模拟正在运行,因为我可以看到“点击...”被记录。这是一个示例测试(真实代码,不是简化示例):
test('should log learner out', () => {
    const event = {
      preventDefault: () => {},
      target: { textContent: en.common['log-out-title'] } as unknown,
    } as React.MouseEvent<HTMLButtonElement, MouseEvent>;

    const wrappedLogOut = wrappedMenuDrawer.find(ListItem).at(3).find('a');

    // @ts-ignore
    act(() => wrappedLogOut.prop('onClick')(event));

    // TODO: test authService.logout is called
    // assert that dispatch was called with authActions.logout()
    expect(amplitude.logAmpEvent).toHaveBeenCalledWith('from main menu', { to: 'LOGOUT' }); // This assertion passes
  });
根据文档、Medium 帖子和 Stack Overflow 上的类似问题,我尝试过的模拟/监视调度的方法/变体包括:
import * as reactRedux from 'react-redux'
const spy = jest.spyOn(reactRedux, 'useDispatch'
import store from '../../store';
const spy = jest.spyOn(store, 'dispatch')
const mockUseDispatch = jest.fn();
const mockDispatch = jest.fn();

jest.mock('react-redux', () => ({
  useDispatch: () => mockUseDispatch.mockReturnValue(mockDispatch),
}));

// or...

jest.mock('react-redux', () => ({
  useDispatch: () => mockUseDispatch,
}));

mockUseDispatch.mockReturnValue(mockDispatch) // inside the actual test
  

最佳答案

有多种方法可以做到这一点。 AFAIK:

  • 你可以模拟 useDispatch 钩子(Hook)来返回你自己的假调度函数。
    我在我自己的 React 库的测试代码中使用,以帮助管理对 Action 的绑定(bind)调度。这是hooks.test.tsx .
  • 由于您使用测试 React 商店包装您的组件,因此您也可以直接将 store.dispatch 替换为一个假函数。见 here进行讨论。

  • 第一个的好处是您可以根据需要轻松地从 react-redux 中模拟更多内容。

    关于reactjs - 如何在 React 组件中测试 Redux 的 dispatch() 是否被调用(Jest + Enzyme),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62568505/

    相关文章:

    javascript - React 不渲染新组件,新的 webpack 设置

    javascript - 有没有办法有条件地更改 package.json 中的主条目文件?

    javascript - Css变量插值Styled Components

    redux - 使用 Redux 克隆整个状态还是仅克隆切片?

    reactjs - React Redux 更新来自笨 child 的状态

    reactjs - 超过最大调用堆栈大小 react

    reactjs - ReactDOMServer.renderToString() - 它到底是做什么的?

    javascript - 401(未经授权)在 Chrome 中,但在 IE 中没有

    javascript - 调度 Action 创建者语法react-redux

    reactjs - react /Redux : Events - state of the art