为什么在使用 React Hook 表单时表单测试失败?
Why Form Test Fails While Using React Hook Form?
我正在使用 react-hook-form 来构建表单。表单运行良好,但测试未通过。
当我不使用 react-hook-form
并且仅通过 onSubmit <form onSubmit={onSubmit}>
时测试通过。当我通过 handleSubmit <form onSubmit={handleSubmit(onSubmit)}>
传递 onSubmit 时,它没有通过。
这是我的表格
App.js
import { useForm } from "react-hook-form";
export default function App({ onSubmit = (data) => console.log(data) }) {
const { handleSubmit, register } = useForm();
return (
// <form onSubmit={onSubmit}> <--- This works
// <form onSubmit={handleSubmit(onSubmit)}> <--- This doesn't work
<form onSubmit={handleSubmit(onSubmit)}>
<input
placeholder="Email"
defaultValue=""
key="email"
{...register("email")}
/>
<input
placeholder="Password"
defaultValue=""
key="password"
{...register("password")}
/>
<input type="submit" value="submit" />
</form>
);
}
这是我为它编写的测试
App.test.js
import { render, screen } from "@testing-library/react";
import App from "./App";
import userEvent from "@testing-library/user-event";
test("email and password field are clear for submit", async () => {
const handleSubmit = jest.fn();
render(<App onSubmit={handleSubmit} />);
userEvent.type(screen.getByPlaceholderText(/email/i), "test@example.com");
userEvent.type(screen.getByPlaceholderText(/password/i), "password");
userEvent.click(screen.getByText(/submit/i));
expect(handleSubmit).toHaveBeenCalledTimes(1);
});
工作代码也可在 https://codesandbox.io/s/react-hook-form-testing-olo4i
获得
handleSubmit
在签名下方,如您所见,它的 return 值是一个 承诺。它是异步的。
这意味着像这样调用它 handleSubmit(onSubmit)(e)
将 return 一个承诺。
type UseFormHandleSubmit<TFieldValues extends FieldValues> = <TSubmitFieldValues extends FieldValues = TFieldValues>(onValid: SubmitHandler<TSubmitFieldValues>, onInvalid?: SubmitErrorHandler<TFieldValues>) => (e?: React.BaseSyntheticEvent) => Promise<void>;
您需要使用 waitFor 的 RTL:
import { render, screen, waitFor } from "@testing-library/react";
import App from "./App";
import userEvent from "@testing-library/user-event";
test("email and password field are clear for submit", async () => {
const handleSubmit = jest.fn();
render(<App onSubmit={handleSubmit} />);
userEvent.type(screen.getByPlaceholderText(/email/i), "test@example.com");
userEvent.type(screen.getByPlaceholderText(/password/i), "password");
userEvent.click(screen.getByText(/submit/i));
await waitFor(() => {
expect(handleSubmit).toHaveBeenCalledTimes(1);
})
});
如果不等待异步代码完成,它可能会在断言结束后执行。
我正在使用 react-hook-form 来构建表单。表单运行良好,但测试未通过。
当我不使用 react-hook-form
并且仅通过 onSubmit <form onSubmit={onSubmit}>
时测试通过。当我通过 handleSubmit <form onSubmit={handleSubmit(onSubmit)}>
传递 onSubmit 时,它没有通过。
这是我的表格
App.js
import { useForm } from "react-hook-form";
export default function App({ onSubmit = (data) => console.log(data) }) {
const { handleSubmit, register } = useForm();
return (
// <form onSubmit={onSubmit}> <--- This works
// <form onSubmit={handleSubmit(onSubmit)}> <--- This doesn't work
<form onSubmit={handleSubmit(onSubmit)}>
<input
placeholder="Email"
defaultValue=""
key="email"
{...register("email")}
/>
<input
placeholder="Password"
defaultValue=""
key="password"
{...register("password")}
/>
<input type="submit" value="submit" />
</form>
);
}
这是我为它编写的测试
App.test.js
import { render, screen } from "@testing-library/react";
import App from "./App";
import userEvent from "@testing-library/user-event";
test("email and password field are clear for submit", async () => {
const handleSubmit = jest.fn();
render(<App onSubmit={handleSubmit} />);
userEvent.type(screen.getByPlaceholderText(/email/i), "test@example.com");
userEvent.type(screen.getByPlaceholderText(/password/i), "password");
userEvent.click(screen.getByText(/submit/i));
expect(handleSubmit).toHaveBeenCalledTimes(1);
});
工作代码也可在 https://codesandbox.io/s/react-hook-form-testing-olo4i
获得handleSubmit
在签名下方,如您所见,它的 return 值是一个 承诺。它是异步的。
这意味着像这样调用它 handleSubmit(onSubmit)(e)
将 return 一个承诺。
type UseFormHandleSubmit<TFieldValues extends FieldValues> = <TSubmitFieldValues extends FieldValues = TFieldValues>(onValid: SubmitHandler<TSubmitFieldValues>, onInvalid?: SubmitErrorHandler<TFieldValues>) => (e?: React.BaseSyntheticEvent) => Promise<void>;
您需要使用 waitFor 的 RTL:
import { render, screen, waitFor } from "@testing-library/react";
import App from "./App";
import userEvent from "@testing-library/user-event";
test("email and password field are clear for submit", async () => {
const handleSubmit = jest.fn();
render(<App onSubmit={handleSubmit} />);
userEvent.type(screen.getByPlaceholderText(/email/i), "test@example.com");
userEvent.type(screen.getByPlaceholderText(/password/i), "password");
userEvent.click(screen.getByText(/submit/i));
await waitFor(() => {
expect(handleSubmit).toHaveBeenCalledTimes(1);
})
});
如果不等待异步代码完成,它可能会在断言结束后执行。