React Hook 表单“isValid”在测试时始终为 false

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

我制作注册模式屏幕,并在提交时检查 isValid 值。

本地环境(npm start启动),这个isValid值没有问题。
但是在 jest 的单元测试过程中,即使满足验证规则并且在错误变量中没有检测到错误,isValid 值也始终为 false。

所以我想问一下为什么。

TeamUpdateModal.tsx

import React, { FC } from "react";
import { useAppDispatch, useAppSelector } from "../../../../redux/hooks";
import { Team, getTeamsAsync, selectProgress, updateTeamAsync } from "../../../../redux/features/teams/teamsSlice";
import {
  Box,
  Button,
  CircularProgress,
  FormControlLabel,
  FormLabel,
  Modal,
  Stack,
  Switch,
  TextField,
  Typography,
} from "@mui/material";
import { Controller, useForm } from "react-hook-form";
import { useParams } from "react-router-dom";

interface Props {
  open: boolean;
  handleClose: () => void;
  team: Team | undefined;
}

const TeamUpdateModal: FC<Props> = ({ open, handleClose, team }) => {
  const dispatch = useAppDispatch();
  const { teamId } = useParams();
  const isProgress = useAppSelector<boolean>(selectProgress);
  const {
    control,
    handleSubmit,
    formState: { isValid, errors },
    register,
  } = useForm();

  const style = {
    position: "absolute",
    top: "50%",
    left: "50%",
    transform: "translate(-50%, -50%)",
    width: 400,
    bgcolor: "background.paper",
    border: "2px solid #000",
    boxShadow: 24,
    pt: 2,
    px: 4,
    pb: 3,
  };

  const onCancel = () => {
    handleClose();
  };

  const updateTeam = handleSubmit(async (data) => {
    if (!isValid) return;
    if (teamId != undefined) {
      const result = await dispatch(
        updateTeamAsync({
          teamId,
          teamName: data["teamName"],
          companyName: data["companyName"],
        })
      );
    }
  });

  return (
    <Modal
      open={open}
      onClose={() => handleClose()}
      aria-labelledby="update-team-modal"
      aria-describedby="update modal for team setting"
    >
      <Box sx={{ ...style, width: 800 }}>
        <Typography sx={{ mt: 2, mb: 2, fontWeight: "bold", fontSize: "20px" }}>Team Update</Typography>
        <form onSubmit={updateTeam}>
          <Stack spacing={3}>
            <Controller
              name="companyName"
              control={control}
              defaultValue={team?.companyName || ""}
              render={(): JSX.Element => {
                return (
                  <TextField
                    variant="outlined"
                    label="Company Name *"
                    error={!!errors["companyName"]}
                    InputProps={{
                      inputProps: { maxLength: 50 },
                    }}
                    sx={{ width: "100%" }}
                    {...register("companyName", {
                      required: "required",
                      maxLength: 50,
                    })}
                    autoComplete="true"
                    helperText={errors["companyName"]?.message}
                  />
                );
              }}
            />
            <Controller
              name="teamName"
              control={control}
              defaultValue={team?.teamName || ""}
              render={(): JSX.Element => {
                return (
                  <TextField
                    variant="outlined"
                    label="Team Name *"
                    error={!!errors["teamName"]}
                    sx={{ width: "100%" }}
                    InputProps={{
                      inputProps: { maxLength: 50 },
                    }}
                    {...register("teamName", {
                      required: "required",
                      maxLength: 50,
                    })}
                    autoComplete="true"
                    helperText={errors["teamName"]?.message}
                  />
                );
              }}
            />
             <Stack direction="row" marginTop={5} justifyContent="flex-end" spacing={3}>
              <Button type="submit" disabled={isProgress}>
                {isProgress ? <CircularProgress /> : "SUBMIT"}
              </Button>
              <Button onClick={onCancel}>CANCEL</Button>
            </Stack>
          </Stack>
        </form>
      </Box>
    </Modal>
  );
};

export default TeamUpdateModal;

TeamUpdateModal.test.tsx

import { act, fireEvent, render, screen } from "@testing-library/react";
import React from "react";
import TeamRegistrationModal from "./TeamRegistrationModal";

const mockDispatch = jest.fn();

const mockCreateTeamAsync = jest.fn();
const mockSelectProgress = jest.fn();
const mockHandleClose = jest.fn();

jest.mock("../../../../redux/hooks", () => ({
  useAppDispatch: () => mockDispatch,
  useAppSelector: (arg: () => void) => {
    if (arg.name === "selectProgress") false;
    return arg();
  },
}));

jest.mock("../../../../redux/features/teams/teamsSlice", () => ({
  __esModule: true,
  ...jest.requireActual("../../../../redux/features/teams/teamsSlice"),
  createTeamAsync: (payload: {
    teamName: string;
    companyName: string;
  }) => mockCreateTeamAsync(payload),
  selectProgress: () => mockSelectProgress(),
}));

describe("TeamRegistrationModal", () => {
  beforeEach(() => {
    mockCreateTeamAsync.mockClear();
    mockSelectProgress.mockClear();
    mockHandleClose.mockClear();
  });
  test("Input is submitted successfully", async () => {
    act(() => {
      render(<TeamRegistrationModal open={true} handleClose={mockHandleClose} />);
    });

    const teamNameInput = screen.getByLabelText("Team Name *", { selector: "input" }) as HTMLInputElement;
    const companyNameInput = screen.getByLabelText("Company Name *", { selector: "input" }) as HTMLInputElement;

    fireEvent.input(teamNameInput, { target: { value: "username" } });
    fireEvent.input(companyNameInput, { target: { value: "company" } });


    const button = screen.getByText("SUBMIT");

    fireEvent.click(button);

    expect(mockCreateTeamAsync).toBeCalledTimes(1); <= error occurs 
  });
});

我将 useForm 模式插入为 onBlur,但错误并未消除。

javascript reactjs typescript jestjs react-hook-form
1个回答
0
投票

https://github.com/orgs/react-hook-form/discussions/9699

将其放在单击之前,让 useForm 将 isValid 设置为 true

// Add custom wait to get correct form state in next re-rendering
        await new Promise((resolve) => setTimeout(resolve, 0));
© www.soinside.com 2019 - 2024. All rights reserved.