react-testing-library

コードは Jest 環境のものを想定してます。

コンポーネントレンダリング

@testing-library/reactからrenderをインポートしてきて使います。大体はこの関数によりレンダリングしてから色々テストすることになります。

import {render} from '@testing-library/react';

const Button = ({children}) => (
  <button>
    <span>{children}</span>
  </button>
);

test('...', () => {
  const renderResult = render(<Button>foo</Button>);
  // ...
});

renderRenderResultを返しますが、これは色々なものが詰まったオブジェクトです。

debug

debugはどんな DOM 構造でレンダリングされたか確認したい時に便利なものです。

renderResult.debug();
// <body>
//   <div>
//     <button>
//       <span>foo</span>
//     </button>
//   </div>
// </body>

引数としてbaseElementが渡せます。これを渡すと表示する DOM の範囲を狭めれます。

renderResult.debug(renderResult.container);
// <div>
//   <button>
//     <span>foo</span>
//   </button>
// </div>

container

レンダリングする要素の入れ物となるコンポーネントです。デフォルトでは<div>で囲まれます。(つまり、div > button > spanの構造でレンダリングされる)
入れ物はrender時にオプションを指定することで変更可能です。

const article = document.createElement("article");

render(<Button>foo</Button>, {
  container: document.body.appendChild(article)
}).debug();
// <article>
//   <button>
//     <span>foo</span>
//   </button>
//</article>

Queries

要素を取得するための様々なヘルパーです。get.*find.*query.*から始まるメソッドが多数用意されてます。これらの違いはgetfindは必ず要素が無ければ駄目で、queryは無くても良い点大きく違う点です。
また、Allと付くヘルパー(例えばgetAllBy.*)は単体ではなく配列で返すようになります。

Queries はByまたはAllByの後ろに決められたサフィックス(手段名)を付けることで、その手段で要素を取得します。検索文字は絶対マッチでも良いですが、/foo/iのような正規表現でもマッチさせれます。

手段には以下のようなものがあります。
LabelTextは以下のようなケースの<label>を取得します。

  1. label > input
  2. label[aria-label]
  3. label[for] + input[id]
  4. label[id] + input[aria-labelledby]

PlaceholderTextplaceholder属性を持つ要素を取得します。

  1. [placeholder]

Textはそのテキストを持ってる要素を取得します。

  1. {text}

AltTextalt属性を持つ要素を取得します。

  1. [alt]

Titletitle属性を持つ要素か SVG のタイトルとマッチした要素を取得します。

  1. [title]
  2. svg > title

DisplayValueは入力系の要素に現在入ってる値にマッチした要素を取得します。

  1. input
  2. textarea
  3. select > option[selected]

Roleは要素の役割にマッチした要素を取得します。これは HTML によってデフォルトで割り振られた Role にもマッチします。
デフォルトロールはmomdo.github.io/html-aria/#document-conformance-requirements-for-use-of-aria-attributes-in-htmlが参考になります。

  1. [role]

TestIddata-testid属性を持つ要素を取得します。

  1. [data-testid]

rerender

rerenderはそのコンポーネントを再レンダリングできます。これは(下記の)fireEventなどでコンポーネント内部の状態が変わった時にそれを反映させれます。

以下はレンダリング後はテキスト要素があるが、再レンダリング後は無くなっている事をテストしている例です。

import React from 'react';
import {render, fireEvent} from '@testing-library/react';

const Button = ({children}) => {
  const [hide, setHide] = React.useState(false);

  return (
    <button onClick={() => setHide(true)}>
      {!hide && <span>{children}</span>}
    </button>
  );
};

test('hide text when has clicked', () => {
  const renderResult = render(<Button>foo</Button>);

  const button = renderResult.getByRole('button');

  expect(renderResult.getByText('foo')).toBeTruthy();

  fireEvent.click(button);
  renderResult.rerender();

  expect(() => renderResult.getByText('foo')).toThrow();
});

unmount

unmountはコンポーネントを JSDOM 環境から取り除きます。例えばコンポーネントが内部で外部の DOM を弄っている場合、その後処理がちゃんとできているかなどの確認に使えます。

イベント発火

fireEventでは Queries などから取得した要素を引数にイベントを Dispatch できます。

import {fireEvent} from '@testing-library/react';

// ...

fireEvent.click(getByRoke('button'));