Testing Libraryを用いてラジオボタンの選択状態をテストする

ラジオボタンやチェックボックスなど、クリックしたときchecked属性を切り替えてON・OFFを表現するUIコンポーネントがある。 これのテスト方法を毎回探し回っていたため、記録しておく。

ラジオボタンをクリックしたとき選択状態が切り替わるかテストする

ラジオボタンをクリックしたとき選択状態が切り替わるか確かめるためには、次の2つを確認する必要がある。

  1. クリック前の選択状態
  2. クリック後の選択状態

1. クリック前の選択状態をテストする

ラジオボタンで選択状態をコントロールする属性はchecked1属性である。この属性がtrueかfalseかはマッチャーのtoBeChecked()2でテストできる。

よって、テストは次のように実装する。

  it("最初は「宿泊なし」が選択されている", () => {
    const content = render(<StayExtensionOptionsRadio />);
    const radio = content.getByRole("radio", { name: "宿泊なし" });
    expect(radio).toBeChecked();
  });

このとき、最初に選択されている値だけでなく他の選択肢が未選択であることもテストすると良い。もし最初から別の選択肢も「選択済み」状態だと、次に記載する「クリックしたとき状態が変わる」ことのテストにならないためである。

初期状態は変わる可能性があるため、選択されているものとそれ以外で分けておくと良い。すると仕様変更時に一部の値を入れ替えるだけで済む。仕様がそのまま表現でき、後から見ても意図がわかりやすい。

not3はJestのマッチャーに対する修飾子である。マッチャーの「反対の内容であること」をテストできる。つまり、.not.toBeChecked()としてやれば「チェックされているの反対」=「チェックされていない」ことをテストできる。言い換えると、指定の要素は選択されていないことをテストできる。

コードにすると、次のようになる。

  it("最初は「宿泊なし」以外は選択されていない", () => {
    const content = render(<StayExtensionOptionsRadio />);
    // 未選択であるラジオボタングループをまとめてテストする
    expect(content.getByRole("radio", { name: "前泊のみ" })).not.toBeChecked();
    expect(content.getByRole("radio", { name: "後泊のみ" })).not.toBeChecked();
    expect(
      content.getByRole("radio", { name: "前泊と後泊" })
    ).not.toBeChecked();
  });

2. クリック後の選択状態をテストする

クリックイベントはuserEvent4clickで発火できる。userEvent.setup()5を用いてイベント検知のセットアップを行い、ラジオボタンをクリックした状態を再現すれば良い。クリック操作は非同期処理となるため、async awaitを用いてテストを書く。

選択後に初期状態で選択されていた要素が未選択になったことも確かめる。ラジオボタンなので選択肢が複数になってはいけない。目視で確認するのは大変なので、テストケースに含めて正確性を高めておく。

  it("別の選択肢をクリックすると選択状態が切り替わる", async () => {
    // イベント検知のセットアップ
    const event = userEvent.setup();
    const content = render(<StayExtensionOptionsRadio />);

    // 「前泊のみ」をクリック
    await event.click(content.getByRole("radio", { name: "前泊のみ" }));
    // 「前泊のみ」が選択されている
    expect(content.getByRole("radio", { name: "前泊のみ" })).toBeChecked();

    // 「宿泊なし」は選択されていない
    expect(content.getByRole("radio", { name: "宿泊なし" })).not.toBeChecked();
  });

UIコンポーネントテストでは、DRY原則6よりも「冗長でもいいから変化前と後の状態を再現する」ことに重点を置いたほうが良い。下手に省略すると実際の操作と離れてしまい、テストの意味が薄れてしまうからである。