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

使用Enzyme模拟React函数组件输入变更时测试失败求助

Enzyme测试React输入组件时,模拟change事件后状态未更新导致断言失败

我在测试一个React的Join组件时遇到了问题,组件里有两个输入框,绑定了state和change事件,但测试时模拟name输入框的change事件后,值始终是空字符串,断言失败。

组件代码:

import React, { useState } from 'react';
import { BrowserRouter as Router, Link } from 'react-router-dom';
import styles from './Join.module.scss';
const Join = () => {
  const [name, setName] = useState('');
  const [room, setRoom] = useState('');
  const handleChange = (e) => {
    if (e.target.name === 'name') {
      setName(e.target.value);
    } else if (e.target.name === 'room') {
      setRoom(e.target.value);
    }
  };
  return (
    <section className={styles.main}>
      <h1 className={styles.main__title}>Join</h1>
      <form className={styles.form}>
        <label className={styles.form__label}>Name</label>
        <input className={styles.form__input} name="name" type="text" onChange={handleChange} />
        <label className={styles.form__label}>Room</label>
        <input className={styles.form__input} name="room" type="text" onChange={handleChange} />
      </form>
      <Router>
        <Link onClick={(e) => (!name || !room ? e.preventDefault() : null)} to={`/chat?name=${name}&room=${room}`} >
          <button className="btn btn--submit" type="submit">
            Sign In
          </button>
        </Link>
      </Router>
    </section>
  );
};
export default Join;

我的测试代码:

import React from 'react';
import { mount } from 'enzyme';
import Join from '../Join';
describe('<Join />', () => {
  let wrapper;
  beforeEach(() => {
    wrapper = mount(<Join />);
  });
  test('1- renders without errors and matches h1', () => {
    const title = wrapper.find('h1');
    expect(title.text()).toBe('Join');
  });
  test('2- name input', () => {
    const name = wrapper.find('[name="name"]');
    console.log(name.debug());
    name.simulate('change', { target: { value: 'foo' }, });
    expect(name.text()).toBe('foo');
  });
});

请问我哪里操作有误?希望能得到帮助。


问题分析与修复方案

我看到你的问题了,主要有两个关键错误,咱们一步步来修正:

1. 模拟change事件时缺少name属性

你的组件里的handleChange函数是通过判断e.target.name来决定更新name还是room状态的,但你在模拟事件时只传递了value,没有传递name: 'name'。这会导致handleChange里的条件不匹配,根本不会触发setName,所以state里的name还是初始空值。

2. 断言input值的方式错误

name.text()获取的是input标签内部的文本内容,但input的实际值是存在value属性里的,你应该用name.props().value来获取当前输入框的value,或者直接断言组件的state值(这种方式更准确,能直接验证状态是否真的更新了)。

修正后的测试代码

import React from 'react';
import { mount } from 'enzyme';
import Join from '../Join';
describe('<Join />', () => {
  let wrapper;
  beforeEach(() => {
    wrapper = mount(<Join />);
  });
  test('1- renders without errors and matches h1', () => {
    const title = wrapper.find('h1');
    expect(title.text()).toBe('Join');
  });
  test('2- name input updates state correctly', () => {
    const nameInput = wrapper.find('[name="name"]');
    // 模拟change事件,必须包含name和value,匹配组件的handleChange逻辑
    nameInput.simulate('change', { target: { name: 'name', value: 'foo' } });
    
    // 方式1:断言输入框的value属性
    expect(nameInput.props().value).toBe('foo');
    
    // 方式2:直接断言组件的state(更准确,验证state是否更新)
    expect(wrapper.find(Join).state('name')).toBe('foo');
  });
});

另外提个小优化点:你的组件里把Router放在了Join组件内部,测试时可以用MemoryRouter来包裹组件,避免每次mount都创建新的BrowserRouter,但这不是导致当前测试失败的原因,只是让测试更规范的小建议。

内容的提问来源于stack exchange,提问作者Mugg84

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 15:42:54