Jest Next14 useFormState TypeError: (0 , _reactdom.useFormState) 不是函数或其返回值不可迭代

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

当我尝试测试使用

useFormState
和 Next14 服务器操作的表单组件时,我收到此错误
TypeError: (0 , _reactdom.useFormState) is not a function or its return value is not iterable

我用
react@^18 react-dom@^18 [email protected] @testing-library/jest-dom@^6.1.5 @testing-library/react@^14.1.2 jest@^29.7.0 ts-jest@^29.1.1


这是我的组件

interface Props {
  signInAction: (state: any, formData: FormData) => Promise<any>;
  forgotPasswordAction: (state: any, formData: FormData) => Promise<any>;
}

type SignInError = {
  path: string[];
  message: string;
};

type FormState = {
  auth: boolean;
  errors?: SignInError[];
} | null;

const SignInForm: React.FC<Props> = ({ forgotPasswordAction, signInAction }) => {
  const [signInState, signInFormAction] = useFormState<FormState, any>(
    signInAction,
    null
  );

  const [forgotState, forgotFormAction] = useFormState<FormState, any>(
    forgotPasswordAction,
    null
  );

  let usernameError = signInState?.errors?.find((error) => error.path.includes("username"));
  let passwordError = signInState?.errors?.find((error) => error.path.includes("password"));
  let internalError = signInState?.errors?.find((error) => error.path.includes("internal_error"));
  let emailerror = forgotState?.errors?.find((error) => error.path.includes("email"));

  return (
    <Tabs defaultValue="signin" className="w-full md:w-[500px] lg:w-[900px]" data-testid="teacher-form-tabs">
      <TabsList>
        <TabsTrigger value="signin" data-testid="tab-signin-trigger">
          Sign in
        </TabsTrigger>
        <TabsTrigger value="recovery" data-testid="tab-recovery-trigger">
          Account recovery
        </TabsTrigger>
      </TabsList>
      <TabsContent value="signin">
        <Card>
          <CardHeader>
            <CardTitle>Sign in</CardTitle>
          </CardHeader>
          <CardContent>
            <form action={signInFormAction} className="flex flex-col gap-5">
              <InputGroup
                name="username"
                text="Username"
                type="text"
                error={usernameError?.message}
                testId="username-input"
              />
              <InputGroup
                name="password"
                text="Password"
                type="password"
                error={passwordError?.message}
                testId="passowrd-input"
              />
              <ButtonWithStatus error={signInState?.errors} testId="signin-submit">
                Sign in
              </ButtonWithStatus>
              {internalError && <span className="text-red-500">{internalError.message}</span>}
            </form>
          </CardContent>
        </Card>
      </TabsContent>
      <TabsContent value="recovery">
        <Card>
          <CardHeader>
            <CardTitle>Forgot password?</CardTitle>
          </CardHeader>
          <CardContent>
            <form action={forgotFormAction} className="flex flex-col gap-5">
              <InputGroup name="email" text="Email" type="email" error={emailerror?.message} />
              <ButtonWithStatus>Send email</ButtonWithStatus>
            </form>
          </CardContent>
        </Card>
      </TabsContent>
    </Tabs>
  );
};

这是我的笑话测试

describe("Sign in form", () => {
  it("renders form", () => {
    render(<SignInForm signInAction={async fnc} forgotPasswordAction{async fnc} />);

    // Get sign in and recovery tab trigger
    let signInTabTrigger = screen.getByTestId("tab-signin-trigger");
    let recoveryTabTrigger = screen.getByTestId("tab-recovery-trigger");

    // Get username input
    let usernameInput = screen.getByTestId("username-input");

    // Get password input
    let passwordInput = screen.getByTestId("password-input");

    // Check if tab triggers are rendered
    expect(signInTabTrigger).toHaveTextContent("Sign in");
    expect(recoveryTabTrigger).toHaveTextContent("Account recovery");

    // Check if username input is rendered
    expect(usernameInput).toBeInTheDocument();
    expect(usernameInput).toHaveAttribute("name", "username");

    // Check if password input is rendered
    expect(passwordInput).toBeInTheDocument();
    expect(passwordInput).toHaveAttribute("name", "password");
  });
});

我做错了什么吗?这是我第一次使用 Jest。

我尝试过设置模拟,但没有结果。

jest.mock("react-dom", () => ({
  ...jest.requireActual("react-dom"),
  useFormState: () => [() => {}, null],
}));

reactjs jestjs ts-jest next.js14
2个回答
0
投票

您可能忘记在顶部设置“use client”,因为您在客户端组件中使用“useFormState”挂钩。


0
投票

我的测试也有同样的问题。但我用这种方式模拟钩子:

  ...jest.requireActual("react-dom"),
  useFormState: () => [{}, () => {}],
  useFormStatus: () => ({ pending: false }),
}));

当我模拟两个钩子时,测试都通过了,但我遇到了其他错误:

    Warning: Invalid value for prop `action` on <form> tag. Either remove it from the element, or pass a string or number value to keep it in the DOM. For details, see https://reactjs.org/link/attribute-behavior ```
© www.soinside.com 2019 - 2024. All rights reserved.