当我尝试测试使用
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],
}));
您可能忘记在顶部设置“use client”,因为您在客户端组件中使用“useFormState”挂钩。
我的测试也有同样的问题。但我用这种方式模拟钩子:
...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 ```