在使用 React Testing Library (RTL) 获取元素的API时,可以根据需求进行适当的选择

首先

本文将介绍使用带有示例的 React Testing Library (RTL) 来获取页面元素的 API 的使用方法。

只需要一个选项的情况下,请将以下内容用中文进行释义:

前提

实施了样例的开发环境如下所示。
开发环境如下所示。

    • Windows11

 

    • VSCode

 

    • TypeScript 4.9.5

 

    • React 18.2.0

 

    • Vite 4.1.0

 

    • Vitest 0.28.5

 

    @testing-library/react 14.0.0

另外,在开始之前,您可以按照以下文章中提到的步骤,在Vitest上配置React Testing Library的使用。

 

API 分类是关于获取要素的。

在页面上获取元素的API可以分为以下三个方面。

    • 取得する要素の数:単一(…By…)、複数(…AllBy…)

 

    • クエリの種類:getBy (getAllBy)…、queryBy (queryAllBy)…、findBy (findAllBy)…

クエリの方法:…ByRole、…ByLabelText、…ByPlaceholderText、…ByText、…ByDisplayVaalue、…ByAltText、…ByTitle、…ByTestId

查询类型

根据元素是否找到和处理异步操作的方式,可以将getBy(getAllBy)、queryBy(queryAllBy)和findBy(findAllBy)分为以下几类。

クエリの種類要素が見つからない非同期getBy (getAllBy)エラー×queryBy (queryAllBy)null or []×findBy (findAllBy)エラー〇

获取(全部获取)的用例

如果没有特定的理由(不需要使用queryBy(queryAllBy)或findBy(findAllBy)),则可以使用getBy(getAllBy)。

例如,当您需要获取基于以下组件的文本时,请使用 getByText。

export const Home = () => {
  return <div>You are home</div>;
};
import { render, screen } from "@testing-library/react";
import { BrowserRouter } from "react-router-dom";
import { describe } from "vitest";
import { Home } from "../../../pages/Home";

describe("Home component", () => {
  test("elements", async () => {
    render(<Home />, { wrapper: BrowserRouter });

    expect(screen.getByText(/you are home/i)).toBeInTheDocument();
  });
});
image.png

查询通过(查询全部)的用例

当通过 queryBy 进行查询时,如果没有找到要素,则会返回 null(queryAllBy 则返回 [])。因此,queryBy 主要用于查找不存在的元素。

比如说,假设有一个根据 props 值来改变文本显示和隐藏的元素。

export const Home = ({ authorized }: { authorized: boolean }) => {
  return (
    <>
      {authorized && <div>You are authorized</div>}
    </>
  );
};

如果要测试显示了该元素的文本,可以使用getByText来进行测试,没有任何问题。

describe("Home component", () => {
  test("when authorized", async () => {
    render(<Home authorized={true} />, { wrapper: BrowserRouter });

    expect(screen.getByText(/you are authorized/i)).toBeInTheDocument();
  });
});
image.png

在一种情况下,如果文本被隐藏,使用getByText进行测试会导致错误。

test("when not authorized", async () => {
  render(<Home authorized={false} />, { wrapper: BrowserRouter });

  expect(screen.getByText(/you are authorized/i)).not.toBeInTheDocument();
});
image.png

因此,我們使用 queryBy 代替 getByText。

test("when not authorized", async () => {
  render(<Home authorized={false} />, { wrapper: BrowserRouter });

  expect(screen.queryByText(/you are authorized/i)).not.toBeInTheDocument();
});
image.png

查询(findAll)的用例

findBy(findAllBy)可以异步获取元素,因此可以用于UI的变化或异步API响应返回后的UI显示等,这些都与state值的更改有关。

假设有一个通过点击按钮可以改变按钮上文字的元素。

import { useState } from "react";

export const Home = () => {
  const [buttonText, setButtonText] = useState("button");
  return <button onClick={() => setButtonText("clicked")}>{buttonText}</button>;
};

当测试按钮点击后文本显示是否发生变化时,使用getByText会出现错误。

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { BrowserRouter } from "react-router-dom";
import { describe } from "vitest";
import { Home } from "../../../pages/Home";

describe("Home component", () => {
  test("when authorized", async () => {
    render(<Home />, { wrapper: BrowserRouter });

    userEvent.click(screen.getByRole("button"));
    expect(screen.getByText("clicked")).toBeInTheDocument();
  });
});
image.png

一旦使用 await 和 findByText 一起,在异步地获取元素后,您可以无错误地进行测试。

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { BrowserRouter } from "react-router-dom";
import { describe } from "vitest";
import { Home } from "../../../pages/Home";

describe("Home component", () => {
  test("test", async () => {
    render(<Home />, { wrapper: BrowserRouter });

    userEvent.click(screen.getByRole("button"));
    expect(await screen.findByText("clicked")).toBeInTheDocument();
  });
});
image.png

通过使用 getByText 方法,您可以顺利进行测试,不会出现错误。

方法1:在点击处理中添加 await

Home.test.tsx
import { render, screen } from “@testing-library/react”;
import userEvent from “@testing-library/user-event”;
import { BrowserRouter } from “react-router-dom”;
import { describe } from “vitest”;
import { Home } from “../../../pages/Home”;

describe(“Home component”, () => {
test(“test”, async () => {
render(, { wrapper: BrowserRouter });

await userEvent.click(screen.getByRole(“button”));
expect(screen.getByText(“clicked”)).toBeInTheDocument();
});
});

方法2:使用 waitFor 方法

Home.test.tsx
import { render, screen, waitFor } from “@testing-library/react”;
import userEvent from “@testing-library/user-event”;
import { BrowserRouter } from “react-router-dom”;
import { describe } from “vitest”;
import { Home } from “../../../pages/Home”;

describe(“Home component”, () => {
test(“test”, async () => {
render(, { wrapper: BrowserRouter });

userEvent.click(screen.getByRole(“button”));
await waitFor(() => {
expect(screen.getByText(“clicked”)).toBeInTheDocument();
});
});
})。

查询方法

RTL是基于以下思想开发的。

你的测试与你的软件使用方式越相似,你就越可以获得信心。

 

根据这个思想,推荐按照以下优先顺序使用查询方式(通过…)。

    1. 每个人都可以访问的查询:

通过角色获取
通过标签文本获取
通过占位文本获取
通过文本获取
通过显示值获取

语义查询:

通过替代文本获取
通过标题获取

测试ID:

通过测试ID获取

请参照下列选项。

    • About Queries

 

    • Guiding Principles

 

    • 【react-testing-library】queryBy, findByはどう使えばいいのか?

 

    testing libraryでのgetBy, queryBy, findByの違いについて
bannerAds