使用RTL测试MUI密码TextField时,输入值不更新且onChange未触发
MUI密码TextField在RTL测试中值不更新的问题解决
问题场景
基于React、MUI和React Testing Library搭建环境,实现了一个仅包含密码类型的MUI TextField组件,但测试时遇到异常:用RTL填充输入框后,值未发生变化,onChange事件也未触发。尝试过fireEvent.change(触发错误)和userEvent.type两种方式均无效。
组件代码
import React, { useState } from "react"; import TextField from "@mui/material/TextField"; export default function MuiMock() { const [variable, setVariable] = useState(""); return ( <TextField margin="normal" required name="password" label="Password" type="password" id="password" data-testid="password" autoComplete="current-password" onChange={(e) => setVariable(e.target.value)} /> ); }
原测试代码
import React from "react"; import { screen, render } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import MuiMock from "./Mock"; it("mock test", async () => { const user = userEvent.setup(); render( <React.StrictMode> <MuiMock/> </React.StrictMode> ); const passwordInput = screen.getByTestId("password"); expect(passwordInput).toBeInTheDocument(); await user.type(passwordInput, "test12"); expect(screen.getByTestId("password")).toHaveValue("test12"); });
问题原因
MUI的TextField是封装组件,会渲染多层DOM结构,你设置的data-testid="password"会被添加到组件最外层的<div>上,而非实际接收输入的<input>标签。直接操作外层div无法触发input的change事件,自然也不会更新输入值。
解决方法
需要获取真实的<input>元素再执行操作,推荐两种实现方式:
方式1:通过标签文本获取(RTL推荐方案)
利用getByLabelText方法,MUI的TextField会自动关联label与内部input,这种方式更贴近用户实际操作逻辑:
it("mock test", async () => { const user = userEvent.setup(); render( <React.StrictMode> <MuiMock/> </React.StrictMode> ); // 通过标签文本定位真实input const passwordInput = screen.getByLabelText("Password"); expect(passwordInput).toBeInTheDocument(); await user.type(passwordInput, "test12"); expect(passwordInput).toHaveValue("test12"); });
方式2:从外层容器中查找input
如果必须依赖data-testid,可从获取到的外层容器中查询内部input元素:
it("mock test", async () => { const user = userEvent.setup(); render( <React.StrictMode> <MuiMock/> </React.StrictMode> ); const passwordContainer = screen.getByTestId("password"); // 从容器中定位真实input const passwordInput = passwordContainer.querySelector("input"); expect(passwordInput).toBeInTheDocument(); await user.type(passwordInput, "test12"); expect(passwordInput).toHaveValue("test12"); });
内容的提问来源于stack exchange,提问作者Adi M
相关产品推荐
相关产品推荐

