React testing-library で getByText, getByRole, getAllByRole を比較する
Tags: react, testing, beginners
Published: 2022-02-27 18:25:48


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

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

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

export default App;
```

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

---

## screen.getByText で取得。

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

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

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

文字列から取得。

```ts
 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
```

当然パス。

---

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

```html
    <div>
      <button>TEST_BUTTON</button>
      <p>TEST_BUTTON is over there</p>
    </div>
```

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

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

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

debug を入れてみると


```ts
 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)
```

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

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

---
---

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

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


```ts
    const appTextElement = screen.getByRole('button');
```

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

---

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

```ts
    <div>
      <button>TEST_BUTTON</button>
      <button>SUB_BUTTON</button>
      <p>TEST_BUTTON is over there</p>
    </div>
```

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

> TestingLibraryElementError: Found multiple elements with the role "button"

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

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

---

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

```ts
screen.getByRole('button', {name: 'TEST_BUTTON'});
```

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

---

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

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

```ts
    <div>
      <button role="presentation">presentation button</button>
      <button>SUB_BUTTON</button>
      <p>TEST_BUTTON is over there</p>
    </div>
```

また、使わない方のボタンを 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 でヒットする複数のエレメントの存在を確認する

```ts
    <div>
      <button role="presentation">presentation button</button>
      <button>SUB_BUTTON</button>
      <div role="button">TEST_BUTTON is over there</div>
    </div>
```

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

```ts
    const appTextElement = screen.getAllByRole('button');
```

getAllByRole で取得できる。

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

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

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

```ts
  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
```

全て見つかっている。

---

## まとめ

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

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

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

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

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

---

## 次にやること

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

toBe, toEqual, toContain

toHaveBeenLastCalledWith

などの Matcher を試す。