at backyard

Color my life with the chaos of trouble.

React Testing Libraryでidやclass名などのセレクターを利用してテストする方法

最近React Testing Libraryを少し触ってみようと思い、簡単なTodoリストアプリを作成した上でテストを書いている。
(実際に書いたソースコードGitHub上に上げており、他にviteやvitestなども併せて試している)

github.com

React Testing Libraryを使っていく上で、id名やclassName名などのセレクターを用いてelementを指定してテストをする場合はどうすれば良いか分からなかったので調べた内容をメモする。

なお、これはReact Testing Library側で推奨されている機能かどうかは分からない。
(ぱっとドキュメントを流し読みした限りではそういう記述はなかったように感じたため)

そのためReact Testing Libraryとしてはidやclassで指定してテストをするよりも、もっと別の方法でテストをすべきという考えがあるのかもしれない。

あとは data-testid を用いる方法がある。
こちらのほうがより明示的にテストに使うIDというのを示せるので、実装とテストを分けるという意味では安心感があるように思う。

testing-library.com

React Testing Libraryでidやclass名などのセレクターを利用してテストする方法

では、さっそく本題。

まずは下記のようなソースコードがあるとする。
(なお、最初に書いたGitHubにあげているソースコードを一部抜粋したものとなる)

return (
    <div style={{ padding: 16 }}>
      <h2>Choose task filter</h2>
      <div>
        <input
          type="checkbox"
          id="all"
          name="all"
          value="all"
          checked={filter === "all"}
          onChange={(e) => onChange(e.target.value)}
        />
        <label htmlFor="all">All</label>
        <input
          type="checkbox"
          id="active"
          name="active"
          value="active"
          checked={filter === "active"}
          onChange={(e) => onChange(e.target.value)}
        />
        <label htmlFor="Active">Active</label>
        <input
          type="checkbox"
          id="completed"
          name="completed"
          value="completed"
          checked={filter === "completed"}
          onChange={(e) => onChange(e.target.value)}
        />
        <label htmlFor="completed">Completed</label>
      </div>
    </div>
  );

このソースコードで各チェックボックスの初期チェック状態をテストしたい。
そして各チェックボックスを取得する際に、各チェックボックスに付与した id をもとに取得したい。

そのような状況で実際に書いたテストコードが下記となる。
(こちらも一部抜粋)

  test("Should checked all checkbox", () => {
    const { container } = render(
      <Filter filter={selectedFilter} setFilter={emptySetFilter} />,
    );
    expect(container.querySelector("#all")).toBeChecked();
  });

  test("Should active and complete are unchecked in the initial display", () => {
    const { container } = render(
      <Filter filter={selectedFilter} setFilter={emptySetFilter} />,
    );
    expect(container.querySelector("#active")).not.toBeChecked();
    expect(container.querySelector("#completed")).not.toBeChecked();
  });

このように React Testing Libraryの render 関数の返り値として得られる container は通常のDOMノードと同じように querySelector が使えるので、こちらにID名を指定して想定される状態をテストするということが可能。
(もちろん、class名も同じように container.querySelector('.foo') という形で利用することが可能)