UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【Testing Library】JestとTesting Library

Reactコンポーネントのテストを何を使ってやるかの話で、これまでCypressを導入してテストをしてきたが実行時間が長いのでテストが増えてきて億劫になってきた

画面のキャプチャを保存する機能は重宝しているのでCypressを使い続けるにしても、Cypressの頻度を少なくして、ユーザアクションとAPIリクエストの結果に応じた画面表示パターンなどはもっと軽量化した手法を使いたいと考えていた

そんなとき、また@takepepeさんの記事がどんぴしゃで参考になった

zenn.dev

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))
  ...

これでユーザアクションとAPIリクエストの結果に応じた画面表示パターンのテストが一通りできるようになった