【Next.js和訳】Testing
この記事について
この記事は、Testingの記事を和訳したものです。
記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。
Testing
Next.js を、一般的に使用されている 3 つのテストツールでセットアップする方法をご紹介します。Cypress、Jest、そしてReact Testing Libraryです。
Cypress
Cypress は、E2E(End-to-End)テストや統合テストに使用されるテストランナーです。
クイックスタート
create-next-app
は、with-cypress の例ですぐに始めることができます。
npx create-next-app --example with-cypress with-cypress-app
手動セットアップ
Cypress を使い始めるには、cypress
パッケージをインストールします。
npm install --save-dev cypress
package.json
の scripts フィールドに Cypress を追加します。
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"cypress": "cypress open",
}
Cypress を初めて起動し、Cypress が推奨するフォルダ構造を使ったサンプルを生成する。
npm run cypress
生成されたサンプルと、Cypress ドキュメントのWriting Your First Testセクションを見て、Cypress に慣れるようにしてください。
初めての Cypress 統合テストを作成する
次の 2 つの Next.js ページを想定します。
import Link from 'next/link'
export default function Home() {
return (
<nav>
<Link href="/about">
<a>About</a>
</Link>
</nav>
)
}
export default function About() {
return (
<div>
<h1>About Page</h1>
</div>
)
}
ナビゲーションが正しく動作していることを確認するために、テストを追加します。
describe('Navigation', () => {
it('should navigate to the about page', () => {
// インデックスページからスタートします
cy.visit('http://localhost:3000/')
// href属性に "about "が含まれているリンクを探し、クリックします
cy.get('a[href*="about"]').click()
// 新しいURLには"/about "が含まれているはずです
cy.url().should('include', '/about')
// 新しいページには、"About page "と書かれたh1が含まれているはずです
cy.get('h1').contains('About Page')
})
})
cypress.json
の設定ファイルに "baseUrl":"http://localhost:3000"
を追加すると、cy.visit("/")
の代わりにcy.visit("http://localhost:3000/")
を使うことができます。
Cypress のテストを実行する
Cypress は実際の Next.js アプリケーションをテストしているため、Cypress を起動する前に Next.js サーバーが起動している必要があります。アプリケーションの動作をより忠実に再現するために、本番コードに対してテストを実行することをお勧めします。
npm run build
とnpm run start
を実行した後、別のターミナルウィンドウでnpm run cypress
を実行して Cypress を起動します。
継続的インテグレーション(CI)の準備
これまで Cypress を起動すると、インタラクティブなブラウザが表示され、CI 環境には適していないことに気づかれたでしょう。cypress run
コマンドを使って、ヘッドレスで Cypress を実行することもできます。
"scripts": {
//...
"cypress": "cypress open",
"cypress:headless": "cypress run",
"e2e": "start-server-and-test start http://localhost:3000 cypress",
"e2e:headless": "start-server-and-test start http://localhost:3000 cypress:headless"
}
Cypress と継続的インテグレーションについては、以下のリソースから詳しく知ることができます。
Jest と React テスティングライブラリ
Jest と React Testing Library は、ユニットテストでよく一緒に使われます。
クイックスタート
Jest と React Testing Library を素早く使い始めるために、with-jest の例でcreate-next-app
を使用することができます。
npx create-next-app --example with-jest with-jest-app
手動セットアップ
Jest と React テスティングライブラリを手動でセットアップするには、jest
、@testing-library/react
、@testing-library/jest-dom
のほか、いくつかのサポートパッケージをインストールします。
npm install --save-dev jest babel-jest @testing-library/react @testing-library/jest-dom identity-obj-proxy react-test-renderer
Jest の設定
プロジェクトのルートディレクトリにjave.config.js
ファイルを作成し、以下の設定オプションを追加します。
module.exports = {
collectCoverageFrom: [
'**/*.{js,jsx,ts,tsx}',
'!**/*.d.ts',
'!**/node_modules/**',
],
moduleNameMapper: {
/* (CSSモジュールを使った)CSSインポートの処理
https://jestjs.io/docs/webpack#mocking-css-modules */
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
// CSSインポートを扱う(CSSモジュールなし)
'^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',
/* 画像の取り込みを扱います
https://jestjs.io/docs/webpack#handling-static-assets */
'^.+\\.(jpg|jpeg|png|gif|webp|svg)$': '<rootDir>/__mocks__/fileMock.js',
},
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/'],
testEnvironment: 'jsdom',
transform: {
/* babel-jestを使って、next/babelプリセットでテストをトランスパイルする
https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object */
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
},
transformIgnorePatterns: [
'/node_modules/',
'^.+\\.module\\.(css|sass|scss)$',
],
}
上記の各オプションについては、Jest のドキュメントで詳しく説明されています。
スタイルシートと画像のインポートの扱い
これらのファイルはテストでは役に立ちませんが、インポートするとエラーになる可能性があるので、モックファイルが必要です。上記の設定で参照したモックファイル(fileMock.js
とstyleMock.js
)を__mocks__
ディレクトリの中に作成します。
(module.exports = "test-file-stub")
module.exports = {};
スタティック・アセットの扱いについては、Jest Docsを参照してください。
カスタムマッチャーで Jest を拡張する
@testing-library/jest-dom
には、.toBeInTheDocument()
などの便利なカスタムマッチャーのセットが含まれており、テストを簡単に書くことができます。Jest の設定ファイルに以下のオプションを追加することで、テストごとにカスタムマッチャーをインポートすることができます。
setupFilesAfterEnv: ['<rootDir>/jest.setup.js']
次に、jest.setup.js
の中に、次のような import を追加します。
import '@testing-library/jest-dom/extend-expect'
各テストの前にさらにセットアップオプションを追加する必要がある場合は、上記の jest.setup.js
ファイルに追加するのが一般的です。
絶対インポートと Module Path Aliases
Module Path Aliasesを使用しているプロジェクトでは、jsconfig.json
ファイルの paths オプションと jest.config.js
ファイルの moduleNameMapper
オプションをマッチングさせてインポートを解決するように Jest を設定する必要があります。例えば、以下のようになります。
{
"compilerOptions": {
"baseUrl": ".",
"path": {
"@/components/*": ["components/*"]
}
}
}
moduleNameMapper: {
'^@/components/(.*)$': '<rootDir>/components/$1',
}
package.json にテストスクリプトを追加する
watch モードの Jest 実行ファイルをpackage.json
の scripts に追加します。
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "jest --watch"
}
jest --watch
は、ファイルが変更されたときにテストを再実行します。その他の Jest CLI オプションについては、Jest Docsを参照してください。
最初のテストを作成する
あなたのプロジェクトはテストを実行する準備ができました。Jests の慣習に従って、プロジェクトのルートディレクトリにある__tests__
フォルダにテストを追加してください。
例えば、<Index />
コンポーネントが見出しのレンダリングに成功したかどうかをチェックするテストを追加することができます。
/**
* @jest-environment jsdom
*/
import React from 'react'
import { render, screen } from '@testing-library/react'
import Home from '../pages/index'
describe('Home', () => {
it('renders a heading', () => {
render(<Home />)
const heading = screen.getByRole('heading', {
name: /welcome to next\.js!/i,
})
expect(heading).toBeInTheDocument()
})
})
オプションで、スナップショットテストを追加して、<Index />
コンポーネントへの予期せぬ変更を追跡します。
import React from 'react'
import renderer from 'react-test-renderer'
import Index from '../pages/index'
it('renders homepage unchanged', () => {
const tree = renderer.create(<Index />).toJSON()
expect(tree).toMatchSnapshot()
})
テストスイートの実行
npm run jest
を実行して、テストスイートを実行します。テストの合否が決まると、テストを追加する際に役立つインタラクティブな Jest コマンドのリストが表示されます。
さらに読みたい場合は、以下のリソースが役に立つでしょう。
- Jest Docs
- React Testing Library Docs
- Testing Playground - 優れたテスト手法を使って要素をマッチさせましょう。
コミュニティのパッケージとサンプル
Next.js のコミュニティでは、パッケージや記事が作成されていますので、参考にしてみてください。
- next-page-tester DOM 統合テスト用
- next-router-mock - Storybook のためのパッケージです。
- Test Preview Vercel Deploys with Cypress by Gleb Bahmutov.
読むべき更なる情報をいかに示しています。
Discussion