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

如何使用Jest测试React组件中的输入框功能

如何完善React组件的Jest输入测试用例?

我是测试方法学的新手,一直尝试研究如何测试不同的输入方法,但始终没有头绪。以下是我的React组件代码:

const App = (props) => {
    const newGame = props.newGame;
    const [typeracertext, setTyperacertext] = useState(props.typeracertext);
    const [wholeText, setWholeText] = useState("");

    const onChange = (e) => {
       //此处有读取输入值并与typeracertext变量对比的代码,若匹配则将wholeText状态设为该输入值
    };
    return (
        <input ref={(node) => this.textInput = node}  placeholder="Message..." onChange={onChange}></input> 
    );
}

我想要编写一个测试用例:将typeracertext设为特定值(例如"This is a test"),输入框值设为"This",当onChange()校验通过时,wholeText应被设为"This"。目前我写出了以下测试代码,但不知道expect语句中应该填写什么内容:

test('Test the input value', () => {
const node = this.textInput;
node.value = 'This';
ReactTestUtils.Simulate.change(node);
expect()
});

第一步:修正组件的ref问题

你的函数组件误用了类组件的this来存储ref,函数组件必须用useRef来创建DOM引用,否则测试中无法正确获取输入框节点。修正后的组件代码:

import { useState, useRef } from 'react';

const App = (props) => {
    const [typeracertext, setTyperacertext] = useState(props.typeracertext);
    const [wholeText, setWholeText] = useState("");
    // 用useRef创建输入框的引用
    const textInput = useRef(null);

    const onChange = (e) => {
        const inputValue = e.target.value;
        // 示例校验逻辑:输入值为目标文本的前缀则更新状态
        if (typeracertext.startsWith(inputValue)) {
            setWholeText(inputValue);
        }
    };

    return (
        <input ref={textInput} placeholder="Message..." onChange={onChange} /> 
    );
}

第二步:完善测试用例

测试React组件时,优先验证用户可见的行为而非内部状态,这样测试更稳定。以下提供两种常用的测试方案:

方案1:使用React Testing Library(推荐)

React Testing Library更贴近用户真实操作,测试逻辑更直观:

import { render, screen, fireEvent } from '@testing-library/react';
import App from './App';

test('输入匹配目标文本前缀时更新状态', () => {
    // 渲染组件并传入预设的typeracertext属性
    render(<App typeracertext="This is a test" />);
    
    // 获取输入框元素
    const input = screen.getByPlaceholderText('Message...');
    
    // 模拟用户输入"This"
    fireEvent.change(input, { target: { value: 'This' } });

    // 假设组件会将wholeText渲染到页面(比如添加了<div>{wholeText}</div>),直接验证UI结果
    expect(screen.getByText('This')).toBeInTheDocument();

    // 额外测试:输入不匹配内容时状态不更新
    fireEvent.change(input, { target: { value: 'Wrong' } });
    expect(screen.queryByText('Wrong')).not.toBeInTheDocument();
});

方案2:使用ReactTestUtils(原测试框架)

如果坚持使用ReactTestUtils,可以通过mockuseState的更新函数来断言状态变化:

import React from 'react';
import ReactTestUtils from 'react-dom/test-utils';
import App from './App';
import { render, unmountComponentAtNode } from 'react-dom';

let container = null;

beforeEach(() => {
    container = document.createElement('div');
    document.body.appendChild(container);
});

afterEach(() => {
    unmountComponentAtNode(container);
    container.remove();
    container = null;
});

test('输入匹配时触发wholeText更新', () => {
    // Mock useState的第二个返回值(状态更新函数)
    const mockSetWholeText = jest.fn();
    jest.spyOn(React, 'useState')
        // 保留typeracertext的初始状态逻辑
        .mockImplementationOnce(initial => [initial, jest.fn()])
        // 替换wholeText的状态更新函数
        .mockImplementationOnce(initial => [initial, mockSetWholeText]);

    // 渲染组件
    render(<App typeracertext="This is a test" />, container);
    
    // 获取输入框元素
    const input = container.querySelector('input');
    
    // 模拟输入变化
    ReactTestUtils.Simulate.change(input, { target: { value: 'This' } });

    // 断言状态更新函数被正确调用
    expect(mockSetWholeText).toHaveBeenCalledWith('This');
});

关键注意点

  • 函数组件禁止使用this存储ref,必须用useRef。
  • 优先测试UI表现而非内部状态,避免测试与组件实现细节耦合。
  • 若需验证内部状态,可通过mockuseState的更新函数来实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 06:30:56