💯

Testing Library で Next.js のサーバサイドのテストを実装する

2024/06/14に公開

背景

Next.js でのサーバサイドのテストの実装例があまり出てこなかったの備忘録としてまとめておきます。同じように困ってる方の助けになれば幸いです。

ソフトウェアのバージョン

$ npm ls | grep next
├── next@13.5.6
$ npm ls | grep testing
├── @storybook/testing-library@0.2.2
├── @testing-library/jest-dom@6.1.4
├── @testing-library/react@14.1.0
├── @testing-library/user-event@14.5.1

方法

例えば、以下のようなサーバーサイドのログインページがあったとします。

import { getServerSession } from 'next-auth/next'
import LoginButton from '@/app/components/LoginButton'
import LogoutButton from '@/app/components/LogoutButton'
import { options } from '@/app/options'
import { User as NextAuthUser } from 'next-auth'
import styles from '@/app/components/Login.module.css'
import ErrorComponent from '../components/ErrorComponent'

export default async function Login() {
  const session = await getServerSession(options)
  const user: NextAuthUser | undefined = session?.user as
    | NextAuthUser
    | undefined

  return (
    <main>
      <div className={styles.userInfoCard}>
        <h1 className={styles.title}>ログインページ</h1>
        {user && (
          <>
            <div className={styles.userDetail}>
              <ul>
                <li>
                  <span>ログインID</span>
                  {user.id}
                </li>
                <li>
                  <span>名前</span>
                  {user.name}
                </li>
              </ul>
            </div>
            <LogoutButton />
          </>
        )}
        {!user && <LoginButton />}
      </div>
    </main>
  )
}
export default async function Login() {

async がついているためサーバサイドのページとなっています。

クライアントサイドのテスト

こちらのユニットテストを Testing Library で実装していきます。
たまたまかもですが書籍などではクライアントサイドのテストの書き方しか記載されていませんでした。
もし、こちらのページがクライアントサイドならテストは以下のようになるかと思います。

describe('🚪 Login Page', () => {
  it('should show LoginButton when no user session', async () => {
    const result = Login()
    render(result)
    expect(screen.queryByText('Login')).toBeInTheDocument()
    expect(screen.queryByText('Logout')).not.toBeInTheDocument()
  })
})

サーバサイドのテスト

サーバサイドでは以下のようになります。タネを明かせば簡単で await をコンポーネントにつければ OK です。 (async なので await すると考えれば合理的ですね)

describe('🚪 Login Page', () => {
  it('should show LoginButton when no user session', async () => {
-   const result = Login()
+   const result = await Login()
    render(result)
    expect(screen.queryByText('Login')).toBeInTheDocument()
    expect(screen.queryByText('Logout')).not.toBeInTheDocument()
  })
})

💡 まとめ

Testing Library でサーバサイドのページをテストする方法をまとめました。
わかってしまうと簡単ですがテストを書こうとした時に書き方がわからず、色々調べた結果ようやく以下の issue を見つけて理解したという経緯がありました。

https://github.com/testing-library/react-testing-library/issues/1209

この記事が同じ悩みを持っている方の目にとまれば幸いです。

Cykinso's Tech Blog

Discussion