React组件在Jest测试中无法触发回调函数的问题求助
React Jest测试点击事件报错:TypeError: tree.props.handleClick is not a function
我正在用React开发简易天气Web应用,编写Jest测试时组件快照生成正常,但触发点击事件时出现类型错误:
TypeError: tree.props.handleClick is not a function
我参照Jest文档写的测试,以为这是触发点击的正确方式,是不是对点击函数的引用有误?刚接触测试编写,求React+Jest测试的相关指导!
React组件代码
import React from "react" import { useEffect, useState } from 'react' // import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' const CityEntry = ({ weatherDatum, deleteLocation }) => { const capitalizeFirstLetter = (string) => { return string.charAt(0).toUpperCase() + string.slice(1); } const handleClick= () => { deleteLocation(weatherDatum.id) } return ( <div className="city"> <p className="location flex-item">{capitalizeFirstLetter(weatherDatum.location)} </p> <p className="temp flex-item">{weatherDatum.temperature} ℉</p> <p className="feels-like flex-item">Feels like: {weatherDatum.feelsLike}</p> <p className="description flex-item">{capitalizeFirstLetter(weatherDatum.description)}</p> <p><img className="icon flex-item" src={`https://openweathermap.org/img/w/${weatherDatum.icon}.png`}></img></p> <button className="delete" onClick={handleClick}>Delete</button> </div> ) } export default CityEntry;
Jest测试代码
import renderer from 'react-test-renderer'; import CityEntry from '../src/Components/CityEntry.js' it('deletes a city entry when clicked', () => { const component = renderer.create( <CityEntry weatherDatum={{ id: '', lat: '', lon: '', location: '', temperature: '', feelsLike: '', description: '', icon: '' }} /> ); let tree = component.toJSON(); expect(tree).toMatchSnapshot() renderer.act(() => { tree.props.handleClick() }); tree = component.toJSON(); expect(tree).toMatchSnapshot() })
生成的Jest快照
exports[`deletes a city entry when clicked 1`] = ` <div className="city" > <p className="location flex-item" > </p> <p className="temp flex-item" > ℉ </p> <p className="feels-like flex-item" > Feels like: </p> <p className="description flex-item" /> <p> <img className="icon flex-item" src="https://openweathermap.org/img/w/.png" /> </p> <button className="delete" onClick={[Function]} > Delete </button> </div> `;
问题原因及修复方案
1. 核心错误原因
tree是组件渲染后的JSON快照,仅包含DOM节点的属性和结构,不包含组件内部的handleClick方法,直接调用tree.props.handleClick()必然报错。- 测试中未给
CityEntry传入必填的deleteLocationprops,即便点击逻辑触发,也会因该prop未定义抛出新错误。
2. 修复后的测试代码
import renderer from 'react-test-renderer'; import CityEntry from '../src/Components/CityEntry.js' it('deletes a city entry when clicked', () => { // 创建jest模拟函数,用于验证回调是否被触发 const mockDeleteLocation = jest.fn(); // 构造测试用的天气数据 const testWeatherData = { id: '123', lat: '', lon: '', location: 'london', temperature: '72', feelsLike: '70', description: 'sunny', icon: '01d' }; const component = renderer.create( // 传入完整的props <CityEntry weatherDatum={testWeatherData} deleteLocation={mockDeleteLocation} /> ); let tree = component.toJSON(); expect(tree).toMatchSnapshot() // 找到按钮元素,触发它的onClick事件 renderer.act(() => { tree.children[5].props.onClick(); }); // 验证模拟函数是否被正确调用,且传入了预期的id参数 expect(mockDeleteLocation).toHaveBeenCalledWith('123'); // 重新生成快照(若组件删除后有UI变化则保留,否则可省略) tree = component.toJSON(); expect(tree).toMatchSnapshot() })
3. 新手测试实用建议
- 优先用
@testing-library/react:它的API更贴近真实用户行为(比如fireEvent.click、screen.getByText),比直接操作快照更符合测试逻辑。 - 测试行为而非实现:不要纠结组件内部方法名称,重点验证用户操作后的结果(如回调是否触发、UI是否更新)。
- 必传所有依赖props:组件依赖的props必须在测试中提供,避免未定义导致的错误。
- 用模拟函数验证回调:对于父组件传入的回调,用
jest.fn()创建模拟函数,测试调用次数、参数是否符合预期。
内容的提问来源于stack exchange,提问作者maximosis
相关产品推荐
相关产品推荐

