React Testing LibraryのgetBy, queryBy, findByの違い!

React Testing Libraryには、DOM要素を取得するためのさまざまなメソッドがあります。

その中でも、getByqueryByfindByはDOM要素を取得する際に頻繁に使用されますが、これらのメソッドの使い分けに迷うことがあるかもしれません。

この記事では、それぞれのメソッドの「違い」や「使い分け」をシンプルなサンプルコードとともに解説します。

getBy, queryBy, findByの違い

まず最初にgetByqueryByfindByの「違い」と「使い分け」を以下にまとめます。

getByqueryByfindBy
特徴・指定した条件に一致する要素を返す・指定した条件に一致する要素を返す
・条件に一致する要素が見つからない場合にはnull を返す
・指定した条件に一致する要素をPromiseで返すメソッド
エラーの
発生条件
・条件に一致する要素が見つからなかった場合
・条件に一致する要素が複数ある場合
・条件に一致する要素が複数ある場合・条件に一致する要素が指定時間内(デフォルト1000ms)に見つからない場合
・条件に一致する要素が複数ある場合
使い分け条件に一致する要素を取得する時に使用する条件に一致する要素が存在しないことを確認する時に使用する条件に一致する要素が非同期にDOMに追加される場合に使用する

ではこれから、以下のサンプルコードに示しているMyComponentのテストをgetByqueryByfindByを用いて行ってみましょう。

import React, { useState, useEffect } from 'react';

function MyComponent() {
  const [showLoadMore, setShowLoadMore] = useState(false);

  // 500ms後に「Load More」ボタンを表示
  useEffect(() => {
    const timer = setTimeout(() => {
      setShowLoadMore(true);
    }, 500);
    return () => clearTimeout(timer);
  }, []);

  return (
    <div>
      <button>Submit</button>
      {/* 500ms後に表示される「Load More」ボタン */}
      {showLoadMore && <button>Load More</button>}
    </div>
  );
}

export default MyComponent;

getByの使い方

getByは、指定した条件に一致する要素を返すメソッドです。条件に一致する要素が見つからなかった場合や、条件に一致する要素が複数ある場合にはエラーが発生します。条件に一致する要素が1つだけであることが前提の場合に使用しましょう。複数の要素が存在する場合には、getAllByメソッドを使用します。

getByを用いたサンプルコードを以下に示します。

import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import MyComponent from './MyComponent';

test('Submitボタンが表示されているか', () => {
  render(<MyComponent />);
  const submitButton = screen.getByRole('button', { name: 'Submit' });
  expect(submitButton).toBeInTheDocument();
});

上記のサンプルコードでは、getByRoleを使用して「Submit」ボタンが画面に表示されているかを確認しています。今回は、"Submit" というラベルを持つボタンが1つだけ存在するため、テストが成功しています。

queryByの使い方

queryByは、getByと同様に指定した条件に一致する要素を返しますが、要素が見つからなかった場合にはエラーではなくnullを返す点が異なります。そのため、queryByは条件に一致する要素が存在しないことを確認する時に使用します。また、条件に一致する要素が複数ある場合には、queryAllByメソッドを使用します。

queryByを用いたサンプルコードを以下に示します。

import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import MyComponent from './MyComponent';

test('Load Moreボタンが初期状態では表示されていないか', () => {
  render(<MyComponent />);
  const loadMoreButton = screen.queryByRole('button', { name: 'Load More' });
  expect(loadMoreButton).toBeNull();
});

上記のサンプルコードでは、queryByRoleを使用して、「Load More」ボタンが初期状態では表示されていないことを確認しています。queryByは、条件に一致する要素が見つからなかった場合にnullを返すため、expect(loadMoreButton).toBeNull()でボタンが表示されていないことを確認できます。

findByの使い方

findByは、指定された条件に一致する要素が非同期でDOMに追加される場合に使用するメソッドです。このメソッドはPromiseを返すため、async/awaitthen()を使用して、要素が見つかるまで待つ処理が必要になります。条件に一致する要素が指定時間内(デフォルト1000ms)に見つからない場合や条件に一致する要素が複数ある場合にはエラーが発生します。また、条件に一致する要素が複数ある場合には、findAllByメソッドを用います。

findByを用いたサンプルコードを以下に示します。

import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import MyComponent from './MyComponent';

test('Load Moreボタンが0.5秒後には表示されているか', async () => {
  render(<MyComponent />);
  const loadMoreButton = await screen.findByRole('button', { name: 'Load More' });
  expect(loadMoreButton).toBeInTheDocument();
});

上記のサンプルコードでは、findByRoleを使用して、500ms後にDOMに追加される「Load More」ボタンが正しく表示されているかを確認しています。awaitを使って指定された時間内にボタンが表示されるのを待機し、expect(loadMoreButton).toBeInTheDocument()でボタンが画面に正しく表示されているかを確認しています。

本記事のまとめ

この記事ではReact Testing LibraryのgetByqueryByfindByメソッドについて、以下の内容を説明しました。

  • getBy
    • 要素が必ず存在する場合に使用し、要素が見つからなかった場合にはエラーが発生します。
  • queryBy
    • 要素が存在しないことを確認したい場合に使用し、見つからなければnullを返します。
  • findBy
    • 非同期にDOMに追加される要素を取得する場合に使用し、Promiseを返します。

お読み頂きありがとうございました。