如何使用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表现而非内部状态,避免测试与组件实现细节耦合。
- 若需验证内部状态,可通过mock
useState的更新函数来实现。
内容的提问来源于stack exchange,提问作者Venoz
相关产品推荐
相关产品推荐

