Reactコンポーネントのテストを何を使ってやるかの話で、これまでCypressを導入してテストをしてきたが実行時間が長いのでテストが増えてきて億劫になってきた
画面のキャプチャを保存する機能は重宝しているのでCypressを使い続けるにしても、Cypressの頻度を少なくして、ユーザアクションとAPIリクエストの結果に応じた画面表示パターンなどはもっと軽量化した手法を使いたいと考えていた
そんなとき、また@takepepeさんの記事がどんぴしゃで参考になった
Jest & React Testing Library
ReactコンポーネントのテストはJest と React Testing Library の組み合わせがよいみたい
Testing Libraryは知っていたが調べてなかったやつ testing-library.com
クエリ
主にこのような感じで使う
import {render} from '@testing-library/react' import '@testing-library/jest-dom' test('renders a message', () => { const {container, getByText} = render(<Greeting />) expect(getByText('Hello, world!')).toBeInTheDocument() expect(container.firstChild).toMatchInlineSnapshot(` <h1>Hello, World!</h1> `) })
このとき、getByText
のようなgetBy...
を使ってノードを検索する行為をクエリを呼ぶ
Testing Library ではクエリが3種類(get
, find
, query
)あって、要素が見つからない場合にエラーをスローするか、nullを返すか、Promiseを返して再試行するかなどで使い分けることができる
About Queries | Testing Library
イベントの発火
ボタンをクリックするなどのユーザーアクションにはfireEvent
を使う
使い方は以下のような感じ
import {render, screen, fireEvent} from '@testing-library/react' const Button = ({onClick, children}) => ( <button onClick={onClick}>{children}</button> ) test('calls onClick prop when clicked', () => { const handleClick = jest.fn() const { getByText } = render(<Button onClick={handleClick}>Click Me</Button>) const button = getByText(/click me/i) fireEvent.click(button) expect(handleClick).toHaveBeenCalledTimes(1) })
このときもし、ボタンクリック時の非同期リクエストで処理の結果をまって評価したい場合はwaitFor
を使う
... fireEvent.click(button) await waitFor(() => expect(mockAPI).toHaveBeenCalledTimes(1)) ...