如何移除React useFormContext组件测试时的DOM元素mock props警告
问题:React Testing Library测试使用useFormContext的组件时出现prop警告
运行测试时出现如下警告:
console.error Warning: React does not recognize the `mockResolvedValueOnce` prop on a DOM element. Warning: React does not recognize the `mockRejectedValueOnce` prop on a DOM element.
组件代码
const TextField: React.FC<OptionsField> = ({ name, value, placeholder, label, required, type, disabled, fieldCaption = "", autoComplete = "off", customProps = {}, }) => { const methods = useFormContext(); const [currentValue, setCurrentValue] = useState(value); const [status, setStatus] = useState(""); useEffect(() => { methods.clearErrors(name); // eslint-disable-next-line react-hooks/exhaustive-deps }, [status]); const validateText = (e: React.ChangeEvent<HTMLInputElement>) => { const text = e.target.value; text !== "" ? setStatus("writing") : setStatus("not writing"); }; const emptyFieldWhenRequired = methods.formState.errors[name] && methods.formState.errors[name].type === "required"; const valueNotChanged = currentValue === value; const errorStyle = emptyFieldWhenRequired && (currentValue === "" || valueNotChanged) ? "input-error" : ""; const caption = fieldCaption && ( <span className={fieldStyles["field-caption"]}>{fieldCaption}</span> ); const requiredMessage = emptyFieldWhenRequired && (currentValue === "" || valueNotChanged) && ( <span className={styles["error-text"]}>Este campo es requerido</span> ); return ( <div className={styles.container}> <label>{label}</label> <input {...methods.register(name, { value, required })} className={`${styles.input} ${styles[errorStyle]}`} defaultValue={currentValue} type={type} placeholder={placeholder} disabled={disabled} autoComplete={autoComplete} onChange={(e) => { const value = e.target.value; setCurrentValue(value); methods.formState.errors[name] && validateText(e); methods.setValue(name, value); }} {...customProps} /> {caption} {requiredMessage} </div> ); };
测试文件代码
import { render } from "@testing-library/react"; import TextField from "../TextField"; import { fireEvent, screen, waitFor } from "@testing-library/react"; const mockSubmit = jest.fn(); jest.mock("react-hook-form", () => ({ ...jest.requireActual("react-hook-form"), useFormContext: () => ({ register: () => jest.fn(), handleSubmit: () => mockSubmit, errors: () => jest.fn(), formState: { errors: {} }, clearErrors: () => jest.fn(), setValue: () => jest.fn(), }), })); describe("TextField", () => { const setup = () => { return render( <TextField label="Mock TextField" required={true} placeholder="Mock Placeholder" type="text" value="mock value" name="mock name" /> ); }; it("renders TextField without problem", () => { const view = setup(); expect(view).toMatchSnapshot(); }); it("simulates change on input", async () => { setup(); const input = screen.getByPlaceholderText("Mock Placeholder"); fireEvent.change(input, { target: { value: "Mock something" }, }); await waitFor(() => { expect((input as HTMLInputElement).value).toBe("Mock something"); }); }); });
已尝试的方案:在setupTests.js和测试文件中mock console.error = jest.fn(),使用--silent参数,mock window.scrollTo解决了相关错误,但上述警告仍存在。
解决方案
问题根源
你在mock useFormContext时,让register返回了一个jest mock函数,但react-hook-form的register实际会返回包含input属性(如name、onChange、ref等)的对象。当你把这个mock函数展开到input元素上时,jest函数自带的mockResolvedValueOnce、mockRejectedValueOnce等方法会被当成DOM props传递,React不识别这些props,因此抛出警告。
修复方法
修改mock的register实现,让它返回一个空对象或者符合实际结构的对象,而非jest.fn():
基础修复(仅消除警告)
修改测试文件中的jest.mock部分:
jest.mock("react-hook-form", () => ({ ...jest.requireActual("react-hook-form"), useFormContext: () => ({ register: () => ({}), // 替换jest.fn()为空对象 handleSubmit: () => mockSubmit, errors: () => jest.fn(), formState: { errors: {} }, clearErrors: () => jest.fn(), setValue: () => jest.fn(), }), }));
贴近实际场景的修复(若组件依赖register返回的属性)
如果你的组件需要register返回的特定属性(如onChange、ref),可以在返回对象中添加对应的mock:
register: () => ({ name: "mock-name", onChange: jest.fn(), onBlur: jest.fn(), ref: jest.fn(), })
备选方案:过滤特定警告
如果暂时不想修改mock逻辑,也可以在测试文件中添加警告过滤:
beforeAll(() => { const originalError = console.error; console.error = (...args) => { // 忽略目标警告 if (/React does not recognize the `mockResolvedValueOnce` prop/.test(args[0])) { return; } // 保留其他错误输出 originalError(...args); }; });
推荐优先使用第一种修复方式,从根源解决问题而非掩盖警告。
内容的提问来源于stack exchange,提问作者Mark Rivera
相关产品推荐
相关产品推荐

