【问题标题】:Why Form Test Fails While Using React Hook Form?为什么使用 React Hook 表单时表单测试失败?
【发布时间】:2021-10-25 10:20:58
【问题描述】:

我正在使用 react-hook-form 构建一个表单。表单运行良好,但测试未通过。

当我不使用react-hook-form 并且jsut pass 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获得

【问题讨论】:

    标签: javascript reactjs react-hooks react-testing-library react-hook-form


    【解决方案1】:

    handleSubmit 在签名下方,如您所见,它的返回值是一个 promise。它是异步的。

    这意味着像这样调用它handleSubmit(onSubmit)(e) 将返回一个承诺。

    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);
      }) 
    });
    
    

    如果不等待异步代码完成,它可能会在断言结束后执行。

    Codesandbox

    参考source code

    【讨论】:

    • 你救了我的朋友,关于这个常见问题的信息很少
    猜你喜欢
    • 1970-01-01
    • 2020-03-12
    • 2018-01-04
    • 1970-01-01
    • 1970-01-01
    • 2021-03-29
    • 1970-01-01
    • 2020-06-06
    • 2017-06-25
    相关资源
    最近更新 更多