DEV Community

kaede
kaede

Posted on • Updated on

React testing-library で getByText, getByRole, getAllByRole を比較する

テストボタンのみのコンポーネントをテスト

import React from 'react';
import './App.css';

function App() {
  return (
    <div>
      <button>TEST_BUTTON</button>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

このボタンのコンポーネントをテストする。


screen.getByText で取得。

https://testing-library.com/docs/queries/about/#textmatch-examples

一番シンプル。スクリーンのテキストからエレメントを取得する

  test('renders App Text', () => {
    render(<App />);
    const appTextElement = screen.getByText('TEST_BUTTON');
    expect(appTextElement).toBeInTheDocument();
  });
Enter fullscreen mode Exit fullscreen mode

文字列から取得。

 PASS  src/App.test.tsx
  App
     renders App Text (36 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.845 s, estimated 2 s
Enter fullscreen mode Exit fullscreen mode

当然パス。


同じ文字列が複数あるコンポーネントでテストする

    <div>
      <button>TEST_BUTTON</button>
      <p>TEST_BUTTON is over there</p>
    </div>
Enter fullscreen mode Exit fullscreen mode

次は複数あるパターンでテストする

これも先ほどのコードでパスできる。

describe('App', () => {
  test('renders App Text', () => {
    render(<App />);
    const appTextElement = screen.getByText('TEST_BUTTON');
    expect(appTextElement).toBeInTheDocument();
    screen.debug(appTextElement)
  });
})
Enter fullscreen mode Exit fullscreen mode

debug を入れてみると

 renders App Text'
  console.log
    <button>
      TEST_BUTTON
    </button>

    /Users/kaede/testing/src/App.test.tsx:14:12
      12 |     const appTextElement = screen.getByText('TEST_BUTTON');
      13 |     expect(appTextElement).toBeInTheDocument();
    > 14 |     screen.debug(appTextElement)
Enter fullscreen mode Exit fullscreen mode

最初にあった button の方のみが選択されている。

複数ある場合は、最初にヒットした方がエレメントとして取得されることがわかった。



getByRole でエレメントを取得する

一つしかないロールから取得する

    const appTextElement = screen.getByRole('button');
Enter fullscreen mode Exit fullscreen mode

WAI_ARIA という基準で定められている HTML の役割、role でもエレメントを取得できる。


複数のボタンロールの要素がある場合に ボタンロールの指定だけだと失敗する

    <div>
      <button>TEST_BUTTON</button>
      <button>SUB_BUTTON</button>
      <p>TEST_BUTTON is over there</p>
    </div>
Enter fullscreen mode Exit fullscreen mode

しかし、このように button が複数ある場合に button ロールから取ろうとすると

TestingLibraryElementError: Found multiple elements with the role "button"

複数のボタンロールがあるからとエラーになる。

getByText と違って最初のものを取得したりはしない。


複数のボタンロールから name 指定で特定のロールを取得

screen.getByRole('button', {name: 'TEST_BUTTON'});
Enter fullscreen mode Exit fullscreen mode

なのでこうやってタグの中身を name として指定すれば取得することができる。


getByRole では hidden や presentation ロールの要素は除外される

https://testing-library.com/docs/queries/byrole#options

    <div>
      <button role="presentation">presentation button</button>
      <button>SUB_BUTTON</button>
      <p>TEST_BUTTON is over there</p>
    </div>
Enter fullscreen mode Exit fullscreen mode

また、使わない方のボタンを hidden や presentation のロールにしておけば、アクセスから弾いてくれる。

このコードでは SUB_BUTTON のみが getByRole('button') で選択される。

getByRole のそのほかの role の詳細要素

https://testing-library.com/docs/queries/byrole#options

aria-hidden

aria-selected

aria-checked

aria-current

aria-pressed

aria-expanded

などで指定できる。


getAllByRole と map でヒットする複数のエレメントの存在を確認する

    <div>
      <button role="presentation">presentation button</button>
      <button>SUB_BUTTON</button>
      <div role="button">TEST_BUTTON is over there</div>
    </div>
Enter fullscreen mode Exit fullscreen mode

このように複数ある場合は

    const appTextElement = screen.getAllByRole('button');
Enter fullscreen mode Exit fullscreen mode

getAllByRole で取得できる。

しかしこれは配列なので toBeInTheDocument で確認するとエラーが出る。

  test('renders App Text', () => {
    render(<App />);
    const appTextElement = screen.getAllByRole('button');
    appTextElement.map( element => {
      screen.debug(element)
      expect(element).toBeInTheDocument();
    } )
  });
Enter fullscreen mode Exit fullscreen mode

なので中身の配列に一つずつ document の中にあるか確認を取れば大丈夫。

  console.log
    <button>
      presentation button
    </button>

  console.log
    <button>
      SUB_BUTTON
    </button>


 console.log
    <div
      role="button"
    >
      TEST_BUTTON is over there
    </div>

 PASS  src/App.test.tsx
  App
     renders App Text (55 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.61 s, estimated 2 s
Enter fullscreen mode Exit fullscreen mode

全て見つかっている。


まとめ

getByText ではヒットした最初の一つが選択される

複数あってもエラーが出ない

getByRole では複数ヒットするとエラーが出る

name や aria-checked などの他の詳細で絞り込める

getAllByRole でヒットしたものを全て取り込んで、map して一つずつ document にあるかテストするのもあり。


次にやること

https://jestjs.io/ja/docs/using-matchers

toBe, toEqual, toContain

toHaveBeenLastCalledWith

などの Matcher を試す。

Top comments (0)