如何使用 useActionState 钩子对表单进行单元测试?

问题描述 投票:0回答:1

我想使用 useActionState 挂钩测试表单。它确实使用简单的异步函数,而不是服务器操作。我想断言状态会增加,但在我做出这样的断言之前测试就失败了。

import React from "react";
import { useActionState } from "react";
import { describe, test, expect } from "vitest";
import { act, render, screen } from "@testing-library/react";
import { userEvent } from "@testing-library/user-event";

describe("useActionState", () => {
  test("it works", async () => {
    async function increment(previousState: number, formData: any) {
      return previousState + 1;
    }

    function StatefulForm({}) {
      const [state, formAction] = useActionState(increment, 0);
      return (
        <>
          <p data-testid="state">{state}</p>
          <form action={formAction}>
            <button type="submit" data-testid="submit">
              Increment
            </button>
          </form>
        </>
      );
    }

    const { debug } = render(<StatefulForm />);

    expect(screen.getByTestId("state")).toBeInTheDocument();

    debug();

    const submit = screen.getByTestId("submit");
    await act(() => userEvent.click(submit));
    // throws error:
    // Error: A React form was unexpectedly submitted. If you called form.submit() manually,   consider using form.requestSubmit() instead. If you're trying to use event.stopPropagation()      in a submit event handler, consider also calling event.preventDefault().

  });
});
reactjs unit-testing react-hooks react-testing-library
1个回答
0
投票

事实证明,“action”属性创建了一个隐式的 Action Context(它会抛出错误)。 我们可以通过使用

useTransition
钩子创建显式的 Action Context 来避免这种情况:

import { type FormEvent, useTransition} from "react";
 
  function StatefulForm({}) {
      const [state, formAction] = useActionState(increment, 0);
      const [,startTransition] = useTransition();
      return (
        <>
          <p data-testid="state">{state}</p>
          <form onSubmit={(event: FormEvent<HTMLFormElement>) => {
            // by using custom event handler, we can prevent the reset of form
            event.preventDefault();
            const form = event.currentTarget;

            // the formAction must be called in an ActionContext - transition
            startTransition(() => {
              formAction(new FormData(form));
            });
           }
          }>
            <button type="submit" data-testid="submit">
              Increment
            </button>
          </form>
        </>
      );
    }
© www.soinside.com 2019 - 2024. All rights reserved.