Testing Libraryで<select>と<option>を操作するテストケースを書く

クリックすると複数の選択肢が表示され、一つまたは複数を選ぶことができるUIパーツを「ドロップダウン」「プルダウン」「セレクトボックス」などと表現する。HTML選択要素とも表現される。HTMLタグは<select>1と表現する。ここではMDN日本語ドキュメントに合わせt「ドロップダウン」の表現で統一する。

ドロップダウンコンポーネントテストはサンプルが少ないため、TODOをベースにしたシチュエーション別に書き方を解説する。

一つの選択肢しか選べない場合

基本のドロップダウンは複数の<option>2(HTML 選択肢要素とも表現される)から、一つだけ選択肢を選んで決定する動きをとる。これをベースにしたTODOを記載する。

  • 選択肢は「前泊(previous)のみ」「後泊(next)のみ」「前泊と後泊(both)」「宿泊なし(none)」の4種類
  • 一つだけを選んで選択できる
  • 最初は「宿泊なし」が選択されている

比較しやすいようにするため、 過去記事のラジオボタンと同じ動きになるようにしている。このTODOに従ってテストを書いてみる。

rimarimadan.hatenablog.com

初期選択状態をテストする

ドロップダウンに対するUIコンポーネントテストを書くポイントは「選択されている状態」と「各選択肢」の要素が分かれている点である。選択肢のリストを確かめたいのに「各選択肢」の要素を確かめても、意図通りの結果にならない。逆もありうる。字面にすると簡単そうだが、パニックになっていると早とちりして時間を無駄にしやすい。

「選択されている状態」のUIコンポーネントテストは<select>、「各選択肢」のUIコンポーネントテストは<option>に行うと覚えておけば間違いなく記載できる。

選択肢のテスト

選択肢は<option>タグで記載する。これもWAI-ARIA3という規格でrole="option"4 として定義されている。そのためgetByRole()5で要素を取得できる。<option>複数存在することがほとんどなので、getByAllRole()を使う。

選択肢が4つ存在することを確かめるテストケースを書く場合、次のようになる。

  it("選択肢は全部で4つ存在する", () => {
    const content = render(<StayExtensionSelectBox />);
    expect(content.getAllByRole("option")).toHaveLength(4);
  });

ラベルテキストはgetByText()で取得できる。要素の値valueはTesting Libraryのjest-dom6toHaveValue7またはtoHaveAttribute8を使ってvalueの値を確かめることができる。

<option>要素のラベルテキストとvalueを検証するテストケースを記載すると次のようになる。

  it("前泊のみのラベルテキストとvalueがデグレードしていない", () => {
    const content = render(<StayExtensionSelectBox />);
    expect(content.getByText("前泊のみ")).toBeTruthy();
    // toHaveValueでvalueを確認する場合
    expect(content.getByRole("option", { name: "前泊のみ" })).toHaveValue("previous");
    // toHaveAttributeでvalueを確認する場合
    expect(content.getByRole("option", { name: "前泊のみ" })).toHaveAttribute(
      "value",
      "previous"
    );
  });

個人的にはtoHaveValueを使う方がマッチャーだけで意図を伝えられるため好ましいように感じる。とはいえ、こだわってテストが書けないなら本末転倒なので、まずはtoHaveAttributeを使って属性を取得してテストを書くでも十分良いと思う。