使用Enzyme测试recompose组件:props访问问题
测试Recompose创建的函数式组件(Jest/Enzyme)
嘿,我完全理解你的困扰——刚接触Jest/Enzyme的时候,再加上Recompose的高阶组件,确实容易摸不着头脑。我之前也遇到过类似的问题,下面结合你的场景给你一步步拆解解决方案。
首先,先把你的示例代码补全(方便大家理解场景):
原始组件 UserDetails.js
import React from 'react'; const UserDetails = ({ name, email, isEditing, toggleEdit, saveChanges }) => ( <div className="user-details"> {isEditing ? ( <div> <input type="text" defaultValue={name} /> <input type="email" defaultValue={email} /> <button onClick={saveChanges}>保存</button> <button onClick={toggleEdit}>取消</button> </div> ) : ( <div> <p>姓名: {name}</p> <p>邮箱: {email}</p> <button onClick={toggleEdit}>编辑</button> </div> )} </div> ); export default UserDetails;
增强后的组件 index.js
import { withState, withHandlers, compose } from 'recompose'; import UserDetails from './UserDetails'; const enhance = compose( withState('isEditing', 'setIsEditing', false), withHandlers({ toggleEdit: ({ setIsEditing, isEditing }) => () => { setIsEditing(!isEditing); }, saveChanges: ({ setIsEditing }) => () => { // 模拟保存逻辑 console.log('保存用户信息'); setIsEditing(false); } }) ); export default enhance(UserDetails);
解决方案1:直接测试原始函数式组件(推荐新手先从这里入手)
Recompose的HOC本质是给原始组件注入props,所以直接测试未被增强的原始组件是最简单的方式——你可以手动传入模拟的props,验证组件的渲染逻辑和交互行为,不用关心HOC的内部实现。
测试代码示例
import React from 'react'; import { shallow } from 'enzyme'; import UserDetails from './UserDetails'; describe('UserDetails (原始组件)', () => { const mockProps = { name: '张三', email: 'zhangsan@example.com', isEditing: false, toggleEdit: jest.fn(), saveChanges: jest.fn() }; it('默认显示用户信息和编辑按钮', () => { const wrapper = shallow(<UserDetails {...mockProps} />); // 验证渲染内容 expect(wrapper.find('p').at(0).text()).toBe('姓名: 张三'); expect(wrapper.find('button').text()).toBe('编辑'); // 验证编辑按钮点击会调用toggleEdit wrapper.find('button').simulate('click'); expect(mockProps.toggleEdit).toHaveBeenCalledTimes(1); }); it('编辑状态下显示输入框和保存/取消按钮', () => { const editProps = { ...mockProps, isEditing: true }; const wrapper = shallow(<UserDetails {...editProps} />); expect(wrapper.find('input')).toHaveLength(2); expect(wrapper.find('button').at(0).text()).toBe('保存'); expect(wrapper.find('button').at(1).text()).toBe('取消'); // 测试保存按钮点击 wrapper.find('button').at(0).simulate('click'); expect(mockProps.saveChanges).toHaveBeenCalledTimes(1); }); });
解决方案2:测试增强后的组件(验证HOC逻辑)
如果你需要验证Recompose的HOC组合逻辑(比如withState的初始值、withHandlers的函数是否正确工作),可以测试增强后的组件。
测试代码示例
import React from 'react'; import { mount } from 'enzyme'; import EnhancedUserDetails from './index'; import UserDetails from './UserDetails'; describe('EnhancedUserDetails (带Recompose的组件)', () => { it('初始状态isEditing为false', () => { const wrapper = mount(<EnhancedUserDetails name="李四" email="lisi@example.com" />); // 获取原始组件的props const userDetailsProps = wrapper.find(UserDetails).props(); expect(userDetailsProps.isEditing).toBe(false); }); it('点击编辑按钮切换isEditing状态', () => { const wrapper = mount(<EnhancedUserDetails name="李四" email="lisi@example.com" />); // 点击编辑按钮 wrapper.find('button').simulate('click'); // 重新获取props const userDetailsProps = wrapper.find(UserDetails).props(); expect(userDetailsProps.isEditing).toBe(true); // 点击取消按钮切回原状态 wrapper.find('button').at(1).simulate('click'); expect(wrapper.find(UserDetails).props().isEditing).toBe(false); }); it('保存后关闭编辑状态', () => { const wrapper = mount(<EnhancedUserDetails name="李四" email="lisi@example.com" />); wrapper.find('button').simulate('click'); // 进入编辑 wrapper.find('button').at(0).simulate('click'); // 保存 expect(wrapper.find(UserDetails).props().isEditing).toBe(false); }); });
小技巧:用shallow + dive简化渲染
如果你不想用mount(避免渲染整个DOM树),可以用shallow渲染增强后的组件,然后用dive()深入到原始组件:
const wrapper = shallow(<EnhancedUserDetails name="李四" email="lisi@example.com" />); const userDetailsWrapper = wrapper.dive(); // 获取原始组件的shallow实例 expect(userDetailsWrapper.props().isEditing).toBe(false);
关键要点总结
- 优先测试原始组件:逻辑更清晰,耦合度更低,适合单元测试
- 测试增强组件时,通过
find(原始组件)或dive()获取内部props:Recompose的HOC会把状态和处理函数传递给原始组件,所以可以通过这种方式访问 - 用jest.fn()模拟处理函数:方便验证函数是否被正确调用
内容的提问来源于stack exchange,提问作者sbcreates
相关产品推荐
相关产品推荐

