如何测试React组件中Redux的dispatch()被调用(Jest + Enzyme)

2023-12-22

我有很多功能性的 React 组件,它们调用dispatch()(还原)。这dispatch()函数本身是由react-redux传入的useDispatch() hook.

作为一个简化的例子:

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 组件相同,但需要设置测试的初始存储(和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>
  );
};

它在测试中用于设置酶包装组件,例如:

wrappedLogoutButton = mount(
  <TestRoot initialState={initialState}>
    <LogoutButton />
  </TestRoot>
);

这个设置对我来说效果很好(到目前为止),如果不需要的话我不想改变它。我确实尝试将 redux-mock-store 模拟存储注入 TestRoot,但这搞乱了我编写的每个测试套件。

我尝试过多种嘲笑或监视两者的方法dispatch() and 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 钩子来返回您自己的假调度函数。 我在我自己的 React 库的测试代码中使用了它来帮助管理到操作的绑定分派。这里是钩子.test.tsx https://github.com/sidecus/roth.js/blob/master/src/hooks.test.tsx.

  • 由于您使用测试 React 存储来包装组件,因此您还可以直接用伪函数替换 store.dispatch。看here https://gist.github.com/krawaller/e5d40217658fa132f3c3904987e467cd进行讨论。

第一个的好处是,您可以根据需要轻松地从 React-Redux 模拟更多东西。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何测试React组件中Redux的dispatch()被调用(Jest + Enzyme) 的相关文章

  • React-Redux:state.setIn() 和 state.set() 有什么区别?

    我见过使用setIn and set 在一些react redux代码中 state setIn state set 我在这里找到了一些文档https facebook github io immutable js https facebo
  • Cypress 在 Create React App 中返回 .scss 文件的 webpack 编译错误

    我正在尝试将 Cypress 添加到非常基本的 CRA 但遇到了 Cypress 无法理解 scss 文件的问题 当我跑步时npm run cypress运行测试 我收到以下错误 Error Webpack Compilation Erro
  • redux-observable 中的独立链取消?

    我是 RxJS 新手 在我的应用程序中 我需要独立取消延迟操作 Here s http jsbin com gayoti edit js output一个工作示例 延迟为 3 秒 但是当我选择删除多个项目并取消其中一项时 然后一次全部取消
  • IE 中未定义“代理”

    我通过 React Node 构建了一个 Excel 插件Umi https umijs org 我们已经实施了我们的身份验证系统 身份验证在 Chrome 和 Safari 中有效 我刚刚意识到它在 IE11 中不能很好地工作 F12表明
  • React - 按下按钮,继续调用函数

    我正在尝试实现缩放功能 onClick 工作正常 但我希望当我按住缩放按钮时它会连续缩放 我如何用 ReactJS 来实现这个 Jquery mousedown效果 按住左键时 https stackoverflow com questio
  • React.memo 与反应中的打字稿

    我在 tsx 文件 React typescript 中使用 React memo 现在我已经将 Props 的接口声明为 interface Props type string 我的组件看起来像 const Component React
  • 具有多种布局的 React Router v4

    我想在我的公共布局中渲染一些路线 并在我的私人布局中渲染一些其他路线 有没有一种干净的方法可以做到这一点 显然不起作用的示例 但我希望大致解释我正在寻找的内容
  • React:在哪里扩展对象原型

    我使用创建了一个纯 React 应用程序创建反应应用程序 https github com facebookincubator create react app 我想延长String类并在一个或多个组件中使用它 例如 String prot
  • React:设置 State 或设置 Prop 而无需重新渲染

    Problem 目前 我有一个LoginForm具有 成功 处理函数的组件handleOnSuccess 然后将其链接到父组件onTokenUpdate由 令牌更新 处理函数定义的属性handleUpdateToken 问题是setStat
  • 内的 ref={register} 给了我一个 path.split 错误

    嗨 我正在尝试用 React 制作一个表单 当我输入 ref register inside
  • React router.push 和 router.replace 之间的区别?

    有什么区别React 路由器推送 and 路由器 替换 路由器历史记录就像一个stack of routes 当您使用router replace 您将覆盖堆栈的顶部 当使用router push 它在顶部添加了一条新路线stack 路由器
  • 如何使用 Jest 测试对象键和值的相等性?

    我有一个mapModule我在其中导入组件并导出它们 import ComponentName from components ComponentName export default name ComponentName 我该如何测试ma
  • 函数内开玩笑模拟函数

    我不知道如何在笑话中模拟内部函数的返回值 我尝试了不同的方法 最后我找到了这个answer https stackoverflow com questions 51269431 jest mock inner function但由于某种原因
  • React 文件预览 (FIREBASE)

    我目前将文件存储在 Firebase 存储中 我希望能够实时生成每个文件的文件预览 映射 例如 PDF 文件会将第一页显示为图像 docx 将是文档的第一页 pptx 将是第一张幻灯片 未知文档将是默认文档符号 有人知道有什么好的服务可以轻
  • React Material UI CardMedia 视频组件未播放

    我看到缩略图 但无法启动或停止视频 还有什么方法可以让它自动播放和重复吗 https material ui com api card media https material ui com api card media
  • 在玩笑中运行普通转换后如何转换模块

    用笑话测试 React 组件 其中一些组件使用 OpenLayers ol 软件包 v5 2 0 在 ol 包 v4 中 我应用了 transformIgnorePatterns 来转换 ol 包 jest transformIgnoreP
  • 如何将背景图像仅应用于一个反应页面而不是整个应用程序?

    注册页面示例 register background image linear gradient to right ff5722 0 ff9800 100 margin top 150px important div div div div
  • firebase :: 无法读取 null 的属性“props”

    你好 我正在尝试将react router与firebase一起使用 但它给了我这个错误 无法读取 null 的属性 props 这正是代码 我正在其中使用我的反应路由器 向下代码位于作为登录面板组件的组件上 else if this em
  • 摆脱node-jsx

    在我的 NodeJS 应用程序的路由器中 我想渲染一个 React 应用程序 由于它没有被浏览器化 并且已反应 因此它返回unexpected token lt 构建时出错 我发现如果我require node jsx install 它不
  • 在 React.js 中编辑丰富的数据结构

    我正在尝试为数据结构创建一个简单的基于网格的编辑器 但我在使用 React js 时遇到了一些概念问题 他们的文档对此没有太大帮助 所以我希望这里有人可以提供帮助 首先 将状态从外部组件传输到内部组件的正确方法是什么 是否有可能将内部组件中

随机推荐