React-Bootstrap 无效表单反馈始终可见如何测试?

lbr*_*ile 6 forms validation jestjs react-bootstrap react-testing-library

我无法使用 React-bootstrap 测试表单的正确验证。\n我想看到,当输入模式无效时,一旦验证表单,就会显示无效的反馈文本。

\n

带有测试的工作codesandbox:https://codesandbox.io/s/flamboyant-cerf-7t7jq

\n
import React, { useState } from "react";\n\nimport { Form, Button, InputGroup } from "react-bootstrap";\n\nexport default function App(): JSX.Element {\n  const [validated, setValidated] = useState<boolean>(false);\n\n  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {\n    e.preventDefault();\n    setValidated(true);\n  };\n\n  return (\n    <Form\n      className="col-12 col-lg-5 trans-form"\n      noValidate\n      validated={validated}\n      onSubmit={handleSubmit}\n    >\n      <InputGroup className="my-2">\n        <InputGroup.Prepend>\n          <InputGroup.Text>Receiver Public Key</InputGroup.Text>\n        </InputGroup.Prepend>\n        <Form.Control\n          role="textbox"\n          className="text-truncate rounded-right"\n          type="text"\n          pattern="[A-Za-z0-9]{5}"\n          required\n        />\n        <Form.Control.Feedback\n          className="font-weight-bold"\n          type="invalid"\n          role="alert"\n        >\n          Length or format are incorrect!\n        </Form.Control.Feedback>\n      </InputGroup>\n\n      <Button\n        role="button"\n        className="mt-2 font-weight-bold"\n        variant={"primary"}\n        type="submit"\n        block\n      >\n        Sign\n      </Button>\n    </Form>\n  );\n}\n
Run Code Online (Sandbox Code Playgroud)\n

测试

\n
import React from "react";\nimport { render, screen, waitFor } from "@testing-library/react";\nimport userEvent from "@testing-library/user-event";\nimport "@testing-library/jest-dom";\n\nimport App from "../src/App";\n\ndescribe("form validation", () => {\n  test("invalid receiver public key length", async () => {\n    render(<App />);\n    userEvent.click(screen.getByRole("button"));\n    userEvent.type(screen.getByRole("textbox"), "invalid");\n    expect(screen.getByRole("textbox")).toHaveValue("invalid");\n    expect(\n      await screen.findByText("Length or format are incorrect!")\n    ).toBeVisible();\n  });\n\n  // this test fails, making it seem like the invalid-feedback is always present\n  test("valid receiver public key length", async () => {\n    render(<App />);\n    userEvent.click(screen.getByRole("button"));\n    userEvent.type(screen.getByRole("textbox"), "valid");\n    expect(screen.getByRole("textbox")).toHaveValue("valid");\n    await waitFor(() => {\n      expect(\n        screen.queryByText("Length or format are incorrect!")\n      ).not.toBeVisible(); // \xe2\x86\x90 FAILS\n    });\n  });\n});\n
Run Code Online (Sandbox Code Playgroud)\n

结果

\n

第二次测试失败

\n

测试结果

\n

存储库

\n

https://github.com/lbragile/LibraCoin/tree/develop

\n

lbr*_*ile 0

我最终使用Formik获得相同(但更好)的功能,这也允许我有条件地呈现错误消息:

更新了codesandbox

// App.js
import React from "react";

import * as yup from "yup";
import { Formik, ErrorMessage, Field } from "formik";
import { Form, Button, InputGroup } from "react-bootstrap";

export default function App(): JSX.Element {
  return (
    <Formik
      validationSchema={yup.object().shape({
        from: yup
          .string()
          .matches(/^[A-Za-z0-9]{5}$/, "invalid format")
          .required("from field is required")
      })}
      onSubmit={async (data, { setSubmitting }) => {
        setSubmitting(true);
        alert("submitted: " + data.from);
        setSubmitting(false);
      }}
      initialValues={{ from: "" }}
    >
      {({ handleSubmit, isSubmitting, touched, errors }) => (
        <Form
          className="col-12 col-lg-5 trans-form"
          noValidate
          onSubmit={handleSubmit}
        >
          <InputGroup className="my-2">
            <InputGroup.Prepend>
              <InputGroup.Text>Label</InputGroup.Text>
            </InputGroup.Prepend>
            <Field
              as={Form.Control}
              role="textbox"
              aria-label="from input"
              type="text"
              name="from"
              required
              isInvalid={!!touched.from && !!errors.from}
              isValid={!!touched.from && !errors.from}
            />

            <ErrorMessage
              name="from"
              render={(errorMessage) => (
                <Form.Control.Feedback
                  className="font-weight-bold"
                  type="invalid"
                  role="alert"
                  aria-label="from feedback"
                >
                  {errorMessage}
                </Form.Control.Feedback>
              )}
            />
          </InputGroup>

          <Button
            role="button"
            className="mt-2 font-weight-bold"
            variant={"primary"}
            type="submit"
            block
            disabled={isSubmitting}
          >
            Sign
          </Button>
        </Form>
      )}
    </Formik>
  );
}



// App.test.js
import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import "@testing-library/jest-dom";

import App from "../src/App";

describe("form validation", () => {
  test("empty", async () => {
    render(<App />);

    const input = screen.getByRole("textbox", { name: /From Input/i });
    input.focus();
    input.blur(); // cause an error

    expect(input).toHaveValue("");

    const alert = await screen.findByRole("alert", { name: /From Feedback/i });
    expect(alert).toBeInTheDocument();
    expect(alert).toHaveTextContent("from field is required");
  });

  test("invalid length", async () => {
    render(<App />);

    const input = screen.getByRole("textbox", { name: /From Input/i });
    const text = "aaaaaa";
    userEvent.type(input, text);
    input.blur(); // cause an error

    expect(input).toHaveValue(text);

    const alert = await screen.findByRole("alert", { name: /From Feedback/i });
    expect(alert).toBeInTheDocument();
    expect(alert).toHaveTextContent("invalid format");
  });

  test("valid length", async () => {
    render(<App />);

    const input = screen.getByRole("textbox", { name: /From Input/i });
    const text = "bbbbb";
    userEvent.type(input, text);
    input.blur();

    expect(input).toHaveValue(text);

    expect(
      screen.queryByRole("alert", { name: /From Feedback/i })
    ).not.toBeInTheDocument();
  });
});
Run Code Online (Sandbox Code Playgroud)

  • 在这个答案中,您使用的框架与您的问题中的框架完全不同。人们会来这个问题寻找使用react bootstrap而不是formik的问题的解决方案。 (2认同)