使用React Testing Library测试自定义组件下载链接点击事件时,onDownload方法未被调用,求解决方法
React Testing Library测试自定义组件下载链接点击事件时,onDownload方法未被调用,求解决方法
看起来你遇到的核心问题是测试里定义的mock onDownload和组件实际使用的onDownload完全是两个不相关的函数,组件根本没用到你写的mock,所以点击后自然不会有调用记录。我来一步步帮你解决:
先理清楚几个关键问题
- 你的组件代码有语法错误:
state.[file_id]应该改成state.file_id,state[file_name]改成state.file_name,不然组件本身运行就会报错。 - 组件定义
const CustomModal = (state) => {...}里的state其实是React组件的props对象,不是Redux的全局state——如果你是想从Redux拿file_id和file_name,组件里应该用useSelector来获取,而不是直接接收state作为props。 - 测试里你定义了
const onDownload= jest.fn();,但没有把这个mock函数传给组件,组件用的是外部定义的那个onDownload,和你的mock没关系。
具体修复方案
根据onDownload的实际来源,分两种情况处理:
情况1:onDownload是组件的props
如果onDownload是父组件传给CustomModal的props,那我们可以直接在测试里把mock函数传进去:
第一步:修正组件代码
import React from 'react'; import { useSelector } from 'react-redux'; // 用useSelector从Redux拿数据 const CustomModal = ({ onDownload }) => { // 接收onDownload作为props // 从Redux获取file_id和file_name const { file_id, file_name } = useSelector(state => state.import.state); return ( <div> <a href="#" onClick={(event) => { event.preventDefault(); onDownload(file_id); // 修正语法错误 }} > {file_name} </a> // 修正语法错误 </div> ) };
第二步:修正测试代码
import React from 'react'; import { Provider } from 'react-redux'; import { render, screen, fireEvent, cleanup } from '@testing-library/react'; import '@testing-library/jest-dom'; import { configureStore } from '@reduxjs/toolkit'; // 确保导入configureStore describe('CustomModal', () => { let store; let rendered; describe('render', () => { beforeEach(() => { store = configureStore({ reducer: { // 注意这里应该是reducer,不是你原来的import import: (state = { state: { file_id: 123456789, file_name: 'test_file.xlsx', }, }) => state, // 简单的空reducer,保持store结构 }, }); }); afterEach(() => { cleanup(); }); it('should call the onDownload when the download link is clicked', () => { const mockOnDownload = jest.fn(); // 定义mock函数 // 把mock函数作为props传给CustomModal rendered = render( <Provider store={store}> <CustomModal onDownload={mockOnDownload} /> </Provider>, ); fireEvent.click(screen.getByText('test_file.xlsx')); expect(mockOnDownload).toHaveBeenCalledTimes(1); expect(mockOnDownload).toHaveBeenCalledWith(123456789); // 还可以验证传参是否正确 }); }); });
情况2:onDownload是外部导入的函数(比如Redux action)
如果onDownload是从某个文件导入的(比如action creator),那我们可以用jest.mock来mock这个导入:
第一步:组件代码(假设onDownload是导入的action)
import React from 'react'; import { useSelector } from 'react-redux'; import { onDownload } from './actions'; // 导入onDownload action const CustomModal = () => { const { file_id, file_name } = useSelector(state => state.import.state); return ( <div> <a href="#" onClick={(event) => { event.preventDefault(); onDownload(file_id); }} > {file_name} </a> </div> ) };
第二步:修正测试代码
import React from 'react'; import { Provider } from 'react-redux'; import { render, screen, fireEvent, cleanup } from '@testing-library/react'; import '@testing-library/jest-dom'; import { configureStore } from '@reduxjs/toolkit'; import { onDownload } from './actions'; // 导入要mock的函数 // mock整个actions模块,让onDownload变成jest mock函数 jest.mock('./actions', () => ({ onDownload: jest.fn(), })); describe('CustomModal', () => { let store; let rendered; describe('render', () => { beforeEach(() => { store = configureStore({ reducer: { import: (state = { state: { file_id: 123456789, file_name: 'test_file.xlsx', }, }) => state, }, }); rendered = render( <Provider store={store}> <CustomModal /> </Provider>, ); }); afterEach(() => { cleanup(); }); it('should call the onDownload when the download link is clicked', () => { fireEvent.click(screen.getByText('test_file.xlsx')); expect(onDownload).toHaveBeenCalledTimes(1); expect(onDownload).toHaveBeenCalledWith(123456789); }); }); });
额外注意点
- 测试里的
configureStore需要确保是正确导入的,如果你用的是redux-toolkit的configureStore,要从@reduxjs/toolkit导入;如果是传统redux的,要从redux导入。 - 原来的测试里
rendered变量没有声明,记得要提前声明let rendered;。 - 你原来的store配置里写了
import: { state: {...} },但configureStore的参数里应该是reducer字段,对应各个reducer函数,我在上面的测试里用了一个简单的空reducer来保持store结构,你可以替换成你实际的reducer。
这样修改后,测试就能正确捕获到onDownload的调用了。
备注:内容来源于stack exchange,提问作者Mar
相关产品推荐
相关产品推荐

