😇

【Next.js14】Jestを使ってnext/linkのテストを作成する

2024/05/21に公開

はじめに

next/linkのテストを作成するのが難しかったのでまとめます。
サンプルコードを使ってJestの導入からnext/linkのテスト作成まで解説していくので、興味があれば読んでいってください。

Jestを使ってnext/linkのテストを作成する

プロジェクトを作成する

まずはプロジェクトを作成します。
アプリ名などはお好きにどうぞ。今回はすべて誘導されるがままに選択していきました。

$ npx create-next-app@latest
✔ What is your project named? … my-app
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
Creating a new Next.js app in /Users/tsukadaryou/my-app.

Using npm.

Initializing project with template: app-tw


Installing dependencies:
- react
- react-dom
- next

Installing devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom
- postcss
- tailwindcss
- eslint
- eslint-config-next


added 360 packages, and audited 361 packages in 28s

134 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Initialized a git repository.

Success! Created my-app at /Users/tsukadaryou/my-app

Success!の文字が確認できたら起動してみましょう。

$ yarn dev

画像のような画面が表示されれば成功です。


※上記の画像ではダークモードが適用されています

Next.jsのデフォルトの表示はとてもかっこいいのですが、分かりにくいので余分な要素は削除していきます。

app/page.tsx
export default function Home() {
  return (
    <main className="flex flex-col items-center justify-between p-24">
      <h1 className="text-4xl font-bold">Jestでnext/linkをテストする</h1>
      <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold mt-5 py-2 px-4 rounded">
        Button
      </button>
    </main>
  );
}

テストに必要な準備をする

最初に必要なパッケージをインストールしていきましょう。

$ yarn add --dev jest @testing-library/react @testing-library/jest-dom next-router-mock ts-node @types/jest @testing-library/user-event

インストールしたパッケージのリストは以下のテーブルにまとめておきます。

package 概要 URL
@testing-library/react Reactコンポーネントを扱うテストライブラリ https://testing-library.com/docs/react-testing-library/intro/
@testing-library/jest-dom DOM要素をマッチングするためにライブラリ https://testing-library.com/docs/ecosystem-jest-dom/
next-router-mock URLの状態をメモリに保存できる(パスに書き込むことは不可) https://www.npmjs.com/package/next-router-mock
ts-node Node.js上でTypeScriptを実行するためのライブラリ https://www.npmjs.com/package/ts-node
@types/jest Jestで型定義をできる https://www.npmjs.com/package/@types/jest
@testing-library/user-event ブラウザ上のイベントを趣味レーションする https://testing-library.com/docs/user-event/v13/

次はJestに必要なファイルを作成して、設定を書いていきます。

$ touch jest.config.ts jest.setup.ts
jest.config.ts
import type { Config } from 'jest'
import nextJest from 'next/jest'

const createJestConfig = nextJest({
  dir: './',
})

const config: Config = {
  coverageProvider: 'v8',
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['./jest.setup.ts']
}

export default createJestConfig(config)
jest.setup.ts
import '@testing-library/jest-dom'

これで準備は完了です!

Linkと遷移先のページを作成

まずはHomeLinkを追加して、これから作成するsampleに遷移できるようにします。

page.tsx
+ import Link from "next/link";

export default function Home() {
  return (
    <main className="flex flex-col items-center justify-between p-24">
      <h1 className="text-4xl font-bold">Jestでnext/linkをテストする</h1>
+      <Link href="/sample">
        <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold mt-5 py-2 px-4 rounded">
          Button
        </button>
+     </Link>
    </main>
  );
}

次に`sample`を作っていきます。

```bash
$ mkdir sample
$ cd sample
$ touch page.tsx
app/sample/page.tsx
export default function sample() {
  return (
    <>
      <h2 className="text-center text-4xl font-bold">Sample</h2>
    </>
  )
}

これでLinkを使ったページ遷移の機能は実装できました。
それではこのページ遷移機能が正しく動いているのかを確認するためのテストを作成していきます。

テスト実装

まずはテストが正しく動くかを確認します。
./page.tsxをレンダリングするところから確認していきます。

page.test.tsx
import Page from './page';
import { render } from '@testing-library/react';

describe('Page', () => {
  test ('should render without crashing', () => {
    render(<Page />);
  });
})

問題なければ以下のようにパスするはずです。

$ yarn test
yarn run v1.22.22
$ jest
 PASS  app/page.test.tsx
  Page
    ✓ should render without crashing (20 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.817 s
Ran all test suites.
✨  Done in 4.32s.

次にLinkを使ったページ遷移の機能をテストしていきます。
コード内に解説も記載していくので併せて読んでみてください。

page.test.tsx
import Page from './page';
+ import { render, screen, waitFor } from '@testing-library/react';
+ import mockRouter from 'next-router-mock';
+ import userEvent from '@testing-library/user-event';
+ import { ReactNode } from 'react';

// テスト環境でのルーティング機能を生成するためにモックを作成する
+ jest.mock('next/router', () => require('next-router-mock'));

// Linkのモックを生成するための型定義
+ jest.mock('next/link', () => {
+  interface MockLinkProps {
+    children: ReactNode;
+    href: string;
+  }

// Linkに入っている要素を取得する。
// mockRouter.push(href)によって現在のパスがhrefに変更されてルーティングがシュミレートされる
+   const MockLink = ({ children, href }: MockLinkProps) => {
+     return <a href={href} onClick={() => mockRouter.push(href)}>{children}</a>;
+   };
+   MockLink.displayName = 'Link';

// MockLinkがレンダリングされると`onClick`イベントハンドラが設定された<a>要素が表示される
+   return MockLink;
+ });

describe('Page', () => {
  test ('should render without crashing', () => {
    render(<Page />);
  });

+ test('navigates to /sample when get started button is clicked', async () => {
+   render(<Page />);
+   mockRouter.setCurrentUrl('/');
+   const getStartedButton = screen.getByRole('button', { name: /Button/i });
+   userEvent.click(getStartedButton);

+   await waitFor(() => expect(mockRouter.asPath).toEqual('/sample'));
+  });
})

おわりに

Jestを使ったnext/linkのテストを作成する方法を解説していきました。
もし間違っているところや、もっといいやり方があったらコメント等で教えてもらえると嬉しいです。

最後まで読んでくださりありがとうございました!

Discussion