Jest单元测试报错:TypeError: component.setState is not a function及优化咨询
问题分析与解决方案
报错原因
测试用例里的component是用jest.fn()创建的空模拟函数,它既没有setState方法,也没有state属性,调用OnChange时自然会抛出TypeError: component.setState is not a function错误。同时原测试的断言逻辑也不正确——OnChange没有返回可调用的函数,toBeCalledWith断言不适用。
方案一:修复现有测试用例
如果暂时不修改原OnChange函数,只需调整测试用例,给模拟的component添加必要的state属性和setState模拟方法:
test('should update property and trigger setState', () => { const property = { name: 'test', }; // 创建包含state和mock setState的模拟组件对象 const mockSetState = jest.fn(); const component = { state: property, setState: mockSetState, }; const event = { preventDefault: jest.fn(), target: { name: 'name', value: 'the-value' } }; OnChange(component, property, event); // 验证属性值是否更新 expect(property.name).toBe('the-value'); // 验证setState是否被正确调用 expect(mockSetState).toHaveBeenCalledWith({ ...component.state, }); });
方案二:优化OnChange函数(推荐)
原OnChange直接修改this.state对象的做法违反React的状态管理规则——React类组件的state是不可直接修改的,必须通过setState更新。以下是优化后的实现,同时提升类型安全性和通用性:
优化后的通用handleChange函数
import { ChangeEvent } from 'react'; // 支持类组件的版本 export const handleChange = (component: { setState: (updater: any) => void }, event: ChangeEvent<HTMLInputElement>) => { const { name, value } = event.target; // 使用函数式setState确保获取最新状态 component.setState(prevState => ({ ...prevState, [name]: value, })); }; // 更通用的版本(支持类组件+函数组件) export const handleChangeUniversal = <T>(setState: (updater: T | ((prev: T) => T)) => void, event: ChangeEvent<HTMLInputElement>) => { const { name, value } = event.target; setState(prevState => ({ ...prevState, [name]: value, })); };
类组件调用方式(简化)
// 使用类组件版本 this.onChangeHandler = (event: ChangeEvent<HTMLInputElement>) => handleChange(this, event); // 或者使用通用版本 this.onChangeHandler = (event: ChangeEvent<HTMLInputElement>) => handleChangeUniversal((updater) => this.setState(updater), event);
优化后的测试用例(通用版本)
import { handleChangeUniversal } from './CommonFunctions'; import { ChangeEvent } from 'react'; test('should update state with input value', () => { const mockSetState = jest.fn(); const event = { target: { name: 'name', value: 'the-value' } } as ChangeEvent<HTMLInputElement>; handleChangeUniversal(mockSetState, event); // 验证setState被调用,且传入了更新函数 expect(mockSetState).toHaveBeenCalledWith(expect.any(Function)); // 执行更新函数,验证返回的新状态是否正确 const updaterFn = mockSetState.mock.calls[0][0]; expect(updaterFn({ name: 'test' })).toEqual({ name: 'the-value' }); });
内容的提问来源于stack exchange,提问作者Ankit Jain
相关产品推荐
相关产品推荐

