You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:13:54