【问题标题】:Cannot find alert by accessible name无法通过可访问名称找到警报
【发布时间】:2020-07-06 20:17:50
【问题描述】:

我正在编写一个满足以下业务规则的测试:

如果我们从国家下拉列表中选择Canada,如果省和邮政编码字段为空,则在模糊中显示错误消息。

我正在测试的 React 最终形式是:

<Form
  onSubmit={onSubmit}
  validate={values => {
    const errors: ValidationErrors = {};

    if (!values.country) {
      errors.country = "Country must be selected";
    }

    if (values.country === "Canada" && !values.province) {
      errors.province = "Province must be provided";
    }

    if (values.country === "Canada" && !values.postalCode) {
      errors.postalCode = "Postal code must be provided";
    }
    return errors;
  }}
  render={({
    ...
  }) => (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="country">Country</label>
        <br />
        <Field<string> id="country" name="country" component="select">
          <option />
          <option value="Canada">Canada</option>
          <option value="US">US</option>
        </Field>
      </div>

      <Condition when="country" is="Canada">
        <div>
          <label htmlFor="province">Province</label>
          <br />
          <Field id="province" name="province" component="input" />
          <Error name="province" />
        </div>
        <div>
          <label htmlFor="postalCode">Postal Code</label>
          <br />
          <Field id="postalCode" name="postalCode" component="input" />
          <Error name="postalCode" />
        </div>
      </Condition>
      ...
    </form>
  )}

我写的测试是这样的:

describe("Contact form", () => {
test("should show errors if Canada is seledted but province and postal code are blank", async () => {
const { getByLabelText, findByRole } = render(<ContactForm />);

fireEvent.change(getByLabelText("Country"), {
  target: { value: "Canada" }
});

fireEvent.change(getByLabelText("Province"), {
  target: { value: "" }
});

fireEvent.change(getByLabelText("Postal Code"), {
  target: { value: "" }
});

fireEvent.blur(getByLabelText("Postal Code"));

const postalAlert = await findByRole("alert", {
  name: "Postal code must be provided"
});
expect(postalAlert).toBeInTheDocument();

const provinceAlert = await findByRole("alert", {
  name: "Province must be provided"
});
expect(provinceAlert).toBeInTheDocument();

我正在尝试触发错误消息 - 使用 role="alert" 呈现出来 - 但我的测试失败:Unable to find role="alert"

现在,如果我删除我试图过滤的 name 属性,则找到 alert

const postalAlert = await findByRole("alert"); // SUCCESS

我可以使用findAllByRole 检索警报并对其进行迭代,但我真的只想用可访问的名称显式查询每个警报并断言它们在文档中。

我在调试屏幕的时候看到了元素,我只是想弄清楚如何直接用它的角色和名称来查询它:

<span
      role="alert"
      style="color: rgb(153, 0, 0);"
    >
      Postal code must be provided
</span>

示例表格:https://codesandbox.io/s/react-ts-unit-test-example-6scjc?file=/src/ContactForm.test.tsx

【问题讨论】:

    标签: reactjs react-testing-library react-final-form final-form testing-library


    【解决方案1】:

    有一些原因你不能通过测试

    好像 span 没有应用文本内容作为可访问的名称,您可以使用 aria-label 为其设置可访问的名称,more information here

    export const Error = (props: Props) => {
      const {
        meta: { touched, error }
      } = useField(props.name, { subscription: { touched: true, error: true } });
      return touched && error ? (
        // add aria-label to set accessiable name for span
        <span aria-label={error} role="alert" style={{ color: "#900" }}>
          {error}
        </span>
      ) : null;
    };
    

    你只调用blur“邮政编码”,但是你的测试也包括省份错误,实现是你在模糊省份输入时显示省份错误,所以你需要将它添加到你的测试中

    import * as React from "react";
    import { render, fireEvent } from "@testing-library/react";
    import { ContactForm } from "./ContactForm";
    
    describe("Contact form", () => {
      test("should show errors if Canada is seledted but province and postal code are blank", async () => {
        const { getByLabelText, findByRole } = render(<ContactForm />);
    
        fireEvent.change(getByLabelText("Country"), {
          target: { value: "Canada" }
        });
    
        fireEvent.change(getByLabelText("Province"), {
          target: { value: "" }
        });
    
        fireEvent.change(getByLabelText("Postal Code"), {
          target: { value: "" }
        });
    
        // you only blur "Postal Code"
        fireEvent.blur(getByLabelText("Postal Code"));
    
        const postalAlert = await findByRole("alert", {
          name: "Postal code must be provided"
        });
        expect(postalAlert).toBeInTheDocument();
        
        // This will not shown because you have not called blur Province
        // comment this or add the line below to pass the test
        // fireEvent.blur(getByLabelText("Province"));
        const provinceAlert = await findByRole("alert", {
          name: "Province must be provided"
        });
        expect(provinceAlert).toBeInTheDocument();
      });
    });
    

    【讨论】:

      【解决方案2】:

      findByRole() 不能像传递 name 那样工作。我会使用getByText() 编写这个测试。另请注意,您必须“模糊”Province 字段以显示其错误,因为您仅在“触摸”该字段时才显示错误。

      【讨论】:

      • 我正在尝试遵循 Kent Dodds 建议我们在大多数情况下使用 getByRole 的指导:kentcdodds.com/blog/… name 表示可访问名称,我认为它等于文本节点在我的alert 元素中。这不正确吗?
      • 这篇文章似乎不同意你关于findByRole不允许参数的说法。 kentcdodds.com/blog/…
      猜你喜欢
      • 2014-04-07
      • 2020-11-20
      • 1970-01-01
      • 1970-01-01
      • 2018-07-14
      • 1970-01-01
      • 2019-06-15
      • 2021-09-24
      • 1970-01-01
      相关资源
      最近更新 更多