言語を切り替える
テーマを切り替える

Next.js ユニットテスト実践:Jest + React Testing Library 完全設定ガイド

月曜の朝10時、コーヒーも飲み終わらないうちに、テックリーダーがチャットでこう言いました。「今週からプロジェクトにユニットテストを追加する。Next.js だから Jest で頼む。」私は画面を見つめ、指をキーボードの上に置いたまま固まりました——正直に言うと、頭の中は真っ白でした。React のテストは書いたことがありましたが、Next.js の App Router や Server Components をどうテストすればいいのか、全く見当もつきませんでした。

プロジェクトを開き、npm install jest を叩いて、自信満々に npm test を実行しました。すると、画面には赤いエラーの山が:

Error: Cannot use import statement outside a module
SyntaxError: Unexpected token 'export'
Cannot find module 'next/navigation'

まるまる2日間、私は設定ファイルと Stack Overflow と GitHub Issues の間を行ったり来たりしました。十数種類の設定を試し、jest.config.js を数え切れないほど修正し、ようやくテストが通った瞬間、祝杯をあげてキーボードを投げ捨てそうになりました。

正直なところ、Next.js のテスト環境構築は想像以上に複雑です。しかし、ネットで言われているほど不可解なものでもありません——いくつかの核心的な設定を理解し、よくある落とし穴を避ければ、実は10分で動かせるようになります。この記事では、Next.js 15 + Jest + React Testing Library の環境をゼロから構築する方法を案内し、私が踏んだ落とし穴や、Client Components、Server Components、Hooks、API Mock のテスト方法も共有します。

もしあなたもテスト設定に頭を抱えているなら、この先を読み進めてください。

テスト環境構築(ゼロからスタート)

四の五の言わず、まずは環境を動かしましょう。退屈に見えるかもしれませんが、各設定項目の必要性を説明しますので、コピペして終わりにならないようにしましょう。

依存関係のインストール

ターミナルを開き、以下のパッケージを一気にインストールします:

npm install -D jest jest-environment-jsdom @testing-library/react @testing-library/dom @testing-library/jest-dom ts-node @types/jest

各パッケージの役割を簡単に説明します:

  • jest:テストフレームワーク本体
  • jest-environment-jsdom:ブラウザ環境をシミュレート(React コンポーネントには DOM が必要)
  • @testing-library/react:React コンポーネントテストツール
  • @testing-library/jest-dom:追加のアサーションメソッド(toBeInTheDocument() など)
  • ts-node@types/jest:TypeScript サポート(JS ならスキップ可)

インストールが終わっても、まだテストは走らせないでください。設定ファイルがまだです。

jest.config.ts の作成

これが最も重要な設定ファイルです。プロジェクトルートに jest.config.ts を新規作成します(JS なら .js 拡張子):

import type { Config } from 'jest'
import nextJest from 'next/jest'

// この関数が Next.js の設定を自動的にロードします
const createJestConfig = nextJest({
  dir: './', // Next.js プロジェクトルートディレクトリ
})

const config: Config = {
  coverageProvider: 'v8', // コードカバレッジツール
  testEnvironment: 'jsdom', // ブラウザ環境をシミュレート
  setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'], // テスト起動前の設定ファイル
}

// createJestConfig で設定をラップし、Next.js の各種変換を自動処理させる
export default createJestConfig(config)

ここが重要:なぜ next/jest で設定をラップするのか?

next/jest は以下のことを自動でやってくれます:

  • .css.module.css ファイルの処理(自動 Mock。これがないとテストがエラーになる)
  • 画像、フォントなどの静的リソースの処理
  • .env 環境変数のロード
  • TypeScript と JSX の変換
  • node_modules.next ディレクトリの除外

これを使わないと、これら全てを手動で設定することになります。信じてください、それは苦行です。

jest.setup.ts の作成

ルートディレクトリにもう一つ jest.setup.ts ファイルを作成します。中身は超シンプルです:

import '@testing-library/jest-dom'

この1行が Jest DOM のカスタムマッチャーをインポートし、以下のような断言を使えるようにします:

  • expect(element).toBeInTheDocument()
  • expect(element).toHaveClass('active')
  • expect(element).toBeVisible()

このファイルがないと、上記のようなメソッドは認識されません。

パスエイリアスの設定(@/ を使用している場合)

もしプロジェクトで import Button from '@/components/Button' のようなパスエイリアスを使用している場合、Jest にパスの解決方法を教える必要があります。

まず tsconfig.json(または jsconfig.json)に以下のような設定があるか確認してください:

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@/components/*": ["components/*"],
      "@/lib/*": ["lib/*"]
    }
  }
}

その場合、jest.config.tsmoduleNameMapper を追加します:

const config: Config = {
  coverageProvider: 'v8',
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
  // この部分を追加
  moduleNameMapper: {
    '^@/components/(.*)$': '<rootDir>/components/$1',
    '^@/lib/(.*)$': '<rootDir>/lib/$1',
  },
}

なぜこれが必要か? Jest はデフォルトでは @/ というパスを認識せず、相対パスか絶対パスしか理解しません。「@/components/Button を見たら <rootDir>/components/Button を探しに行け」と教えてあげる必要があります。

テストスクリプトの追加

最後に、package.json に2つのスクリプトを追加します:

{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch"
  }
}
  • npm test:全テストを一度実行
  • npm test:watch:監視モード。ファイル変更時に自動で再テスト

設定の検証

さあ、簡単なテストを走らせて設定がOKか確認しましょう。プロジェクト内に __tests__/example.test.ts を作成します:

describe('Example Test', () => {
  it('should pass', () => {
    expect(1 + 1).toBe(2)
  })
})

npm test を実行します。緑色の PASS1 passed が表示されれば、おめでとうございます、設定成功です。

もしエラーが出ても慌てないでください。第5章のトラブルシューティングを見てください。エラーの 90% はそこに解決策があります。

コンポーネントテスト実践

設定ができたら、本物のテストを書きましょう。コンポーネントテストは Next.js テストの核心ですが、Client Components と Server Components ではテスト方法が全く異なります。

Client Components テスト(標準フロー)

Client Components は、おなじみの 'use client' がついたコンポーネントです。テスト方法は非常に直感的です。

ログインフォームコンポーネント LoginForm.tsx があるとします:

'use client'

import { useState } from 'react'

export default function LoginForm() {
  const [email, setEmail] = useState('')
  const [error, setError] = useState('')

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    if (!email.includes('@')) {
      setError('有効なメールアドレスを入力してください')
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="メールアドレス"
      />
      {error && <span role="alert">{error}</span>}
      <button type="submit">ログイン</button>
    </form>
  )
}

テストファイル LoginForm.test.tsx

import { render, screen, fireEvent } from '@testing-library/react'
import LoginForm from '@/components/LoginForm'

describe('LoginForm', () => {
  it('should render input and button', () => {
    render(<LoginForm />)

    // 入力欄の存在確認
    const emailInput = screen.getByPlaceholderText('メールアドレス')
    expect(emailInput).toBeInTheDocument()

    // ボタンの存在確認
    const submitButton = screen.getByRole('button', { name: 'ログイン' })
    expect(submitButton).toBeInTheDocument()
  })

  it('should show error for invalid email', () => {
    render(<LoginForm />)

    const emailInput = screen.getByPlaceholderText('メールアドレス')
    const submitButton = screen.getByRole('button', { name: 'ログイン' })

    // ユーザー入力をシミュレート
    fireEvent.change(emailInput, { target: { value: 'invalid-email' } })
    fireEvent.click(submitButton)

    // エラーメッセージを確認
    const errorMessage = screen.getByRole('alert')
    expect(errorMessage).toHaveTextContent('有効なメールアドレスを入力してください')
  })
})

テストの考え方

  1. render() でコンポーネントを描画
  2. screen.getByXxx() で要素を見つける(ロール、テキスト、プレースホルダーなどで)
  3. fireEvent でユーザー操作をシミュレート
  4. expect() で結果を断言

ちょっとしたコツ:getByTestId ではなく、できるだけ getByRole を使いましょう。role(buttonalert など)を使う方が、ユーザーが実際に見るものに近く、テストも壊れにくくなります。

Server Components テスト(ちょっと厄介)

Server Components は Next.js 15 の核心機能ですが、正直なところ Jest のサポートはあまり優しくありません。

核心的な問題:Jest は async Server Components をサポートしていません。

例えば、データベースからデータを取得するコンポーネントがあるとします:

// app/posts/page.tsx (Server Component)
async function getPosts() {
  const res = await fetch('https://api.example.com/posts')
  return res.json()
}

export default async function PostsPage() {
  const posts = await getPosts()

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

このコンポーネントを直接テストすると、Jest はエラーを吐きます:Objects are not valid as a React child

どうすればいいか?

3つのアプローチがあります:

案1:ビジネスロジックを切り出して純粋関数としてテスト

// lib/posts.ts
export async function getPosts() {
  const res = await fetch('https://api.example.com/posts')
  if (!res.ok) throw new Error('Failed to fetch')
  return res.json()
}

// lib/posts.test.ts
import { getPosts } from './posts'

describe('getPosts', () => {
  it('should fetch posts successfully', async () => {
    global.fetch = jest.fn(() =>
      Promise.resolve({
        ok: true,
        json: () => Promise.resolve([{ id: 1, title: 'Test Post' }]),
      })
    ) as jest.Mock

    const posts = await getPosts()
    expect(posts).toHaveLength(1)
    expect(posts[0].title).toBe('Test Post')
  })
})

こうすれば、コンポーネント自体ではなくデータ取得ロジックをテストすることになります。要するに、複雑な非同期ロジックを抜き出して単体テストし、コンポーネントには単純な描画だけを残すのです。

案2:同期的な Server Components をテスト

Server Component が非同期処理を含まないなら、普通にテストできます:

// components/Title.tsx (Server Component, asyncなし)
export default function Title({ text }: { text: string }) {
  return <h1 className="title">{text}</h1>
}

// components/Title.test.tsx
import { render, screen } from '@testing-library/react'
import Title from './Title'

describe('Title', () => {
  it('should render title', () => {
    render(<Title text="Hello World" />)
    const heading = screen.getByRole('heading', { level: 1 })
    expect(heading).toHaveTextContent('Hello World')
  })
})

案3:E2E テストで補完

複雑な Server Components については、正直なところ Playwright や Cypress で E2E テストをする方が確実です。Jest 単体テストはフロントエンドロジックを担当し、E2E テストは全体フローを担当する、というふうに役割分担します。

私のやり方はこうです:核心的なビジネスロジックは純粋関数として切り出してテストし、Server Components は単純な描画のみにして、E2E テストでカバーする。

インタラクションテストのテクニック

ユーザー操作をテストする際、@testing-library/react は多くのメソッドを提供しています:

import { render, screen, fireEvent, waitFor } from '@testing-library/react'

// クリック
fireEvent.click(button)

// 入力
fireEvent.change(input, { target: { value: 'test' } })

// 非同期更新を待つ
await waitFor(() => {
  expect(screen.getByText('Success')).toBeInTheDocument()
})

// 要素が表示されているか
expect(element).toBeVisible()

// クラスを持っているか
expect(element).toHaveClass('active')

完全な非同期インタラクションテストの例

it('should submit form successfully', async () => {
  // API を Mock
  global.fetch = jest.fn(() =>
    Promise.resolve({
      ok: true,
      json: () => Promise.resolve({ success: true }),
    })
  ) as jest.Mock

  render(<LoginForm />)

  const emailInput = screen.getByPlaceholderText('メールアドレス')
  const submitButton = screen.getByRole('button', { name: 'ログイン' })

  fireEvent.change(emailInput, { target: { value: 'test@example.com' } })
  fireEvent.click(submitButton)

  // 成功メッセージが出るのを待つ
  await waitFor(() => {
    expect(screen.getByText('ログイン成功')).toBeInTheDocument()
  })
})

waitFor に注目してください。これは非同期操作が完了するのを待ってからチェックを行います。もしコンポーネントに useEffect や非同期の状態更新がある場合、これを使わないと、状態が更新される前に断言が実行されてしまい、テストが失敗します。

Hook テスト戦略

カスタム Hook は React の精髄ですが、どうテストすればいいでしょうか? コンポーネント内で使ってテストするという人もいますが、それだと Hook のロジックとコンポーネントのロジックが混ざってしまいます。より良い方法は renderHook を使うことです。

単純な Hook のテスト

カウンター Hook を書いたとします:

// hooks/useCounter.ts
import { useState } from 'react'

export function useCounter(initialValue = 0) {
  const [count, setCount] = useState(initialValue)

  const increment = () => setCount(c => c + 1)
  const decrement = () => setCount(c => c - 1)
  const reset = () => setCount(initialValue)

  return { count, increment, decrement, reset }
}

テストコード:

// hooks/useCounter.test.ts
import { renderHook, act } from '@testing-library/react'
import { useCounter } from './useCounter'

describe('useCounter', () => {
  it('should initialize with default value', () => {
    const { result } = renderHook(() => useCounter())
    expect(result.current.count).toBe(0)
  })

  it('should initialize with custom value', () => {
    const { result } = renderHook(() => useCounter(10))
    expect(result.current.count).toBe(10)
  })

  it('should increment count', () => {
    const { result } = renderHook(() => useCounter())

    act(() => {
      result.current.increment()
    })

    expect(result.current.count).toBe(1)
  })

  it('should reset count', () => {
    const { result } = renderHook(() => useCounter(5))

    act(() => {
      result.current.increment()
      result.current.increment()
    })

    expect(result.current.count).toBe(7)

    act(() => {
      result.current.reset()
    })

    expect(result.current.count).toBe(5)
  })
})

重要ポイント

  • renderHook で Hook をレンダリング
  • act で状態更新操作をラップする(React のルール。状態更新完了を保証する)
  • result.current で Hook の戻り値を取得

Context に依存する Hook のテスト

Hook が Context(例えば Auth Context)に依存している場合、Provider を提供する必要があります。

// hooks/useAuth.ts
import { useContext } from 'react'
import { AuthContext } from '@/contexts/AuthContext'

export function useAuth() {
  const context = useContext(AuthContext)
  if (!context) {
    throw new Error('useAuth must be used within AuthProvider')
  }
  return context
}

テスト時に Mock Provider を提供します:

// hooks/useAuth.test.tsx
import { renderHook } from '@testing-library/react'
import { useAuth } from './useAuth'
import { AuthContext } from '@/contexts/AuthContext'

describe('useAuth', () => {
  it('should return auth context value', () => {
    const mockAuthValue = {
      user: { id: 1, name: 'Test User' },
      login: jest.fn(),
      logout: jest.fn(),
    }

    const wrapper = ({ children }: { children: React.ReactNode }) => (
      <AuthContext.Provider value={mockAuthValue}>
        {children}
      </AuthContext.Provider>
    )

    const { result } = renderHook(() => useAuth(), { wrapper })

    expect(result.current.user).toEqual({ id: 1, name: 'Test User' })
    expect(result.current.login).toBeDefined()
  })

  it('should throw error when used outside provider', () => {
    // エラーをキャッチ
    const { result } = renderHook(() => useAuth())
    expect(result.error).toEqual(
      Error('useAuth must be used within AuthProvider')
    )
  })
})

テクニックwrapper パラメータで Provider をラップすることで、Hook が Context にアクセスできるようになります。

非同期 Hook(データ取得)のテスト

データ取得用の Hook はよくあります:

// hooks/useFetch.ts
import { useState, useEffect } from 'react'

export function useFetch<T>(url: string) {
  const [data, setData] = useState<T | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<Error | null>(null)

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true)
        const response = await fetch(url)
        if (!response.ok) throw new Error('Network error')
        const json = await response.json()
        setData(json)
      } catch (err) {
        setError(err as Error)
      } finally {
        setLoading(false)
      }
    }

    fetchData()
  }, [url])

  return { data, loading, error }
}

非同期 Hook のテストには、fetch の Mock と状態更新の待機が必要です:

// hooks/useFetch.test.ts
import { renderHook, waitFor } from '@testing-library/react'
import { useFetch } from './useFetch'

describe('useFetch', () => {
  beforeEach(() => {
    // 各テスト前に fetch Mock をリセット
    jest.resetAllMocks()
  })

  it('should fetch data successfully', async () => {
    const mockData = { id: 1, title: 'Test' }

    global.fetch = jest.fn(() =>
      Promise.resolve({
        ok: true,
        json: () => Promise.resolve(mockData),
      })
    ) as jest.Mock

    const { result } = renderHook(() => useFetch('/api/data'))

    // 初期状態:loading = true
    expect(result.current.loading).toBe(true)
    expect(result.current.data).toBeNull()

    // データロード完了を待つ
    await waitFor(() => {
      expect(result.current.loading).toBe(false)
    })

    expect(result.current.data).toEqual(mockData)
    expect(result.current.error).toBeNull()
  })

  it('should handle fetch error', async () => {
    global.fetch = jest.fn(() =>
      Promise.resolve({
        ok: false,
      })
    ) as jest.Mock

    const { result } = renderHook(() => useFetch('/api/data'))

    await waitFor(() => {
      expect(result.current.loading).toBe(false)
    })

    expect(result.current.error).toBeTruthy()
    expect(result.current.error?.message).toBe('Network error')
    expect(result.current.data).toBeNull()
  })
})

注意点

  • waitFor で非同期操作完了を待つ
  • beforeEach で Mock をリセットし、テスト間の干渉を防ぐ
  • 成功と失敗の両方のケースをテストする

Hook テストの極意は、依存関係のシミュレート、状態変更のトリガー、結果の断言です。この3ステップをマスターすれば、どんな Hook でもテストできます。

Mock テクニック大全

Mock はテストの魂です。Mock なしでは、テストは実際の API やデータベース、外部サービスに依存することになり、遅くて不安定になります。Next.js には Mock が必要な特別なものがいくつかあります。ここではそれらを攻略します。

Next.js ルーティングの Mock(一番よく使う)

Next.js のルーティング Hooks(useRouter, usePathname, useSearchParams)は、テスト環境ではデフォルトで利用できないため、Mock が必須です。

useRouter(App Router)の Mock

// __mocks__/next/navigation.ts
export const useRouter = jest.fn()
export const usePathname = jest.fn()
export const useSearchParams = jest.fn()

テストファイルでの使用:

import { useRouter } from 'next/navigation'

// ルーティングの振る舞いを Mock
jest.mock('next/navigation', () => ({
  useRouter: jest.fn(),
  usePathname: jest.fn(),
  useSearchParams: jest.fn(),
}))

describe('NavigationComponent', () => {
  it('should navigate to home on button click', () => {
    const pushMock = jest.fn()
    ;(useRouter as jest.Mock).mockReturnValue({
      push: pushMock,
      back: jest.fn(),
      forward: jest.fn(),
    })

    render(<NavigationComponent />)

    const button = screen.getByRole('button', { name: 'ホームへ戻る' })
    fireEvent.click(button)

    expect(pushMock).toHaveBeenCalledWith('/')
  })
})

usePathname(現在のパス取得)の Mock

import { usePathname } from 'next/navigation'

jest.mock('next/navigation', () => ({
  usePathname: jest.fn(),
}))

describe('HeaderComponent', () => {
  it('should highlight active nav item', () => {
    ;(usePathname as jest.Mock).mockReturnValue('/about')

    render(<Header />)

    const aboutLink = screen.getByRole('link', { name: '阿部について' })
    expect(aboutLink).toHaveClass('active')
  })
})

Next.js Image コンポーネントの Mock

next/image は Next.js の画像最適化サービスに依存しているため、テスト環境ではエラーになります。

案1:普通の img タグとして Mock

// __mocks__/next/image.tsx
const Image = ({ src, alt }: { src: string; alt: string }) => {
  return <img src={src} alt={alt} />
}

export default Image

案2:jest.config.ts でグローバルに Mock

const config: Config = {
  // ... 他の設定
  moduleNameMapper: {
    '^next/image$': '<rootDir>/__mocks__/next/image.tsx',
  },
}

こうすれば、next/image を使っているすべての場所で自動的に Mock 版に置き換わります。

API リクエストの Mock(3つの方法)

方法1:グローバル fetch の Mock(一番簡単):

global.fetch = jest.fn(() =>
  Promise.resolve({
    ok: true,
    json: () => Promise.resolve({ data: 'mock data' }),
  })
) as jest.Mock

方法2:MSW(Mock Service Worker)の使用(より強力):

npm install -D msw
// mocks/handlers.ts
import { http, HttpResponse } from 'msw'

export const handlers = [
  http.get('/api/posts', () => {
    return HttpResponse.json([
      { id: 1, title: 'Test Post' },
    ])
  }),

  http.post('/api/login', async ({ request }) => {
    const { email } = await request.json()
    if (email === 'test@example.com') {
      return HttpResponse.json({ success: true })
    }
    return HttpResponse.json({ error: 'Invalid email' }, { status: 400 })
  }),
]
// mocks/server.ts
import { setupServer } from 'msw/node'
import { handlers } from './handlers'

export const server = setupServer(...handlers)

テストセットアップで MSW を起動:

// jest.setup.ts
import { server } from './mocks/server'

beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

MSW のメリットは、ネットワークレベルでリクエストを傍受するため、fetch を書き換える必要がなく、よりリアルに近いテストができる点です。

よくあるエラーとトラブルシューティング

最後に、私がテスト設定で遭遇したエラートップ3を紹介します。

エラー1:Cannot find module ’@/components/Button’

  • 原因:Jest がパスエイリアスを認識していない。
  • 解決策jest.config.tsmoduleNameMapper にエイリアス設定を追加する。

エラー2:SyntaxError: Unexpected token ‘export’

  • 原因node_modules 内のライブラリがトランスパイルされていない。
  • 解決策next/jest を使っているか確認。それでもだめなら transformIgnorePatterns でそのライブラリを除外リストから外す。

エラー3:act(…) warning

  • 原因:状態更新が act 内で行われていない、または非同期操作を waitFor で待っていない。
  • 解決策:非同期操作の後に await waitFor(...) を追加するか、状態更新操作を act(...) でラップする。

まとめ

Next.js プロジェクトでのテスト環境構築は、最初は設定ファイルや Mock に圧倒されるかもしれませんが、一度セットアップしてしまえば、開発の信頼性を大きく高めてくれます。特にリファクタリング時には、テストがあるのとないのとでは安心感が段違いです。

まずは jest.config.ts を設定し、小さなコンポーネントからテストを書き始めてみてください。テストを書く習慣がつくと、コードの設計自体も自然ときれいになっていくはずです。

Next.js Jest テスト環境構築ステップ

Next.js 15 プロジェクトに Jest と React Testing Library をセットアップし、コンポーネントテストを実行するまでの完全ガイド

⏱️ Estimated time: 15 min

  1. 1

    Step1: 依存関係のインストール

    npm install -D jest jest-environment-jsdom @testing-library/react @testing-library/dom @testing-library/jest-dom ts-node @types/jest コマンドを実行し、必要なテストライブラリをインストールします。
  2. 2

    Step2: jest.config.ts の作成

    プロジェクトルートに設定ファイルを作成し、next/jest を使用して Next.js の特有の設定(CSS、画像処理、TypeScript変換など)を自動処理するように構成します。
  3. 3

    Step3: jest.setup.ts の作成

    ルートディレクトリに jest.setup.ts を作成し、import '@testing-library/jest-dom' を追加して、toBeInTheDocument などの便利な断言メソッドを使用可能にします。
  4. 4

    Step4: パスエイリアスの設定

    jest.config.ts の moduleNameMapper セクションで、@/components/* などのパスエイリアスを実際のディレクトリパス <rootDir>/components/* にマッピングします。
  5. 5

    Step5: テストスクリプトの追加

    package.json に "test": "jest" と "test:watch": "jest --watch" スクリプトを追加し、npm test でテストを実行できるようにします。

FAQ

Server Components を Jest でテストするとエラーになるのはなぜですか?
Jest(および React Testing Library)は現在、非同期(async)コンポーネントのテストを完全にはサポートしていません。Server Components は Promise を返す関数であるため、直接 render しようとするとエラーになります。解決策として、ビジネスロジックを純粋な関数として切り出してテストするか、E2E テストを使用することを推奨します。
useRouter や usePathname をテストで使うとエラーになります。
Next.js のルーティング Hooks は、実行時に Next.js のコンテキストを必要としますが、Jest 環境にはそれが存在しません。jest.mock('next/navigation', ...) を使用してこれらの Hooks を Mock し、push や back などのメソッドが呼び出されたかをテストする必要があります。
Jest と Vitest、Next.js にはどちらがいいですか?
Vitest は設定が簡単で Vite との相性が抜群ですが、Next.js は独自のビルドシステム(Webpack/Turbo)を使用しているため、公式がサポートしている Jest(next/jest)の方が互換性が高く、トラブルが少ないです。現時点では Jest を推奨します。

5 min read · 公開日: 2026年1月7日 · 更新日: 2026年1月22日

コメント

GitHubアカウントでログインしてコメントできます

関連記事