Next.jsのキャッチコピーは本番環境のための React フレームワーク。 React.js 開発ですぐに使えるルーティング、コード分割、バンドル分割、Typescript、組み込みの CSS サポートなどの機能が揃っており、本番環境レベルのアプリケーションを開発できます。 こうした機能は、本番アプリケーションの開発には必須です。 このチュートリアルでは、Next.js アプリケーションに継続的インテグレーション (CI) を実装する方法について解説します。具体的には、アプリケーションに追加した機能を自動でテストするテストフレームワークを準備し、プロセスの中断をなくします。
目次
Next.js とは?
Next.js (ネクストジェイエス) とは、Reactのフレームワークです。Next.js のフレームワークを使用すれば、Reactとは違い、プリレンダリングが可能になり、Webクローラーなどのクローリング対策にも好評であり、SEOなどにも最適な効果があるフレームワークとしても知られています。また、Next.jsでは SSR や SPA も可能になるので多様なメリットが存在します。
前提条件
このチュートリアルを進めるには、いくつかの準備が必要です。
- JavaScript の基礎を理解する
- Node.js (バージョン 10.13 以上) をローカルシステムにインストールする
- CircleCI アカウントを用意する
- GitHub アカウントを用意する
これらのインストールとセットアップが済んだら、チュートリアルを始めましょう。
新しい Next.js プロジェクトを作成する
まず、次のコマンドを実行して新しい Next.js プロジェクトを作成します。
npx create-next-app next-testing
注: Node.js バージョン 13 を使用している場合、上記コマンドを実行するには 13.7 以上のバージョンが必要です。
これで、next-testing
フォルダー (フォルダーの名前は自由に付けられます) 内に Next.js アプリケーションが作成されます。 この自動生成プロセスが完了したら、プロジェクトのルートに移動してアプリケーションを実行します。
cd next-testing
npm run dev
これで、アプリケーションをホストする開発サーバーが http://localhost:3000
で立ち上がります。 ブラウザーでこの URL にアクセスします。
Jest をインストールしてテストの準備をする
次に、テストフレームワークと、テストの実行に必要なユーティリティを準備します。 今回は、テストフレームワークに Jest を使用し、テストをスムーズに実行するための各種ユーティリティをインストールします。 インストールするパッケージの一覧を以下に示します。
jest
:テストフレームワーク@testing-library/jest-dom
: DOM の状態をテストする Jest 用のカスタムマッチャー@testing-library/react
: シンプルな React DOM テストユーティリティ一式を備えた React テストライブラリ@testing-library/dom
: DOM ノードのテストに使用するベーステストライブラリbabel-jest
: テストスイートにある Javascript のトランスパイル用
以下のコマンドを実行して、これらのパッケージをまとめてインストールします。
npm install -D jest @testing-library/react @testing-library/jest-dom @testing-library/dom babel-jest
インストールが完了したら、次は .babelrc
設定ファイルを作成し、Next.js のカスタムプリセットを使うように babel-jest
を設定しましょう。 プロジェクトのルートに .babelrc
という名前のファイルを作成して、以下の設定を入力します。
{
"presets": ["next/babel"]
}
次に、Jest を以下のように設定します。
.next
ビルドフォルダーとnode_modules
フォルダーを対象外にする- テストの Javascript のトランスパイルに
babel-jest
を使用する - テストの静的ファイル (CSS インポートおよびファイル) をモックする
package.json
ファイルに、以下の Jest 用セクションを追加します。
...
"jest": {
"testPathIgnorePatterns": [
"<rootDir>/.next/",
"<rootDir>/node_modules/"
],
"transform": {
"^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest"
},
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js"
}
}
...
続けて、package.json
ファイルの scripts
セクションに test
スクリプトを追加します。
...
"scripts": {
...
"test": "jest"
},
...
Jest テスト用に静的アセットをモックする
前のセクションでは、Jest
設定ファイルを作成し、テストでインポートした CSS ファイルや静的ファイルをモックするように Jest
を設定しました。 その理由は、こうした種類のファイルはテストで役に立たないので、安全にモック化しておくためです。 この設定を記述する際に、fileMock.js
と styleMock.js
という 2 つのモックファイルを参照していたことに気づいたと思います。これらは、それぞれ静的ファイルと CSS ファイルのモックに使用するものです。
それでは、これらのモックファイルを作成しましょう。 プロジェクトのルートに、__mocks__
フォルダーを作成します。 このフォルダー内に fileMock.js
ファイルを作成して、以下のコードを入力します。
module.exports = "placeholder-file";
__mocks__
フォルダー内に styleMock.js
ファイルを作成して、以下のコードを入力します。
module.exports = {};
これらのファイルを作成したことで、静的アセットとインポートした CSS を安全にモック化できるようになりました。
React.js コンポーネントをレンダリングする
これで、テストを作成する準備が整いました。 プロジェクトには、テストで実行すべきものがすべて揃っています。 プロジェクトのルートに __tests__
フォルダー (Jest
のテストファイルの検索先となる特別なフォルダー) を作成して、HomeTest.js
という名前のテストファイルを追加します。 テストファイルに以下のコードを入力します。
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import Home from "../pages/index";
test("Check for Getting Started Text", () => {
const { getByText } = render(<Home />);
expect(getByText("Get started by editing")).toBeInTheDocument();
});
上記のコードでは、まず React.js をレンダリングするために、React テストライブラリから render
オブジェクトをインポートします。 同時に、ページドキュメントにアクセスするための screen
オブジェクトもインポートします。 次に、アサーション用に @testing-library/jest-dom
から extend-expect
モジュールをインポートします。 その後、テスト対象のコンポーネント (/pages/index.js
にあるインデックスページのコンポーネント) をインポートします。
最後に、テストを記述しています。このテストでは、/pages/index.js
ファイルにエクスポートしたホームページコンポーネント (<Home />
) をレンダリングしてから、ページに表示する Get started by editing
というテキストがこのコンポーネントに表示されているかどうかをチェックします。
以下のコマンドを実行して、作成したテストを実行します。
npm run test
次のテストを作成しましょう。__tests__/HomeTest.js
に、以下のコードを追加します。
...
it("Renders appropriately", () => {
render(<Home />);
expect(
screen.getByRole("heading", { name: "Welcome to Next.js!" })
).toBeInTheDocument();
});
今度のテストでは、screen
オブジェクトを使用して React.js DOM にアクセスし、heading
にテキスト Welcome to Next.js!
が含まれるかどうかを検証しています。 このテキストは、ホームページ上の先頭の項目です。
テストスイートをもう一度実行します。
npm run test
継続的インテグレーションでテストを自動化する
テストの実行も無事に完了し、良い調子です。 とは言え、”テストの実行” が今回のゴールではありません。 継続的インテグレーションを実装して、テストの実行を自動化しましょう。 自動化によって、リポジトリに更新をプッシュするたびにテストが実行されるようになります。
初めに、プロジェクトを GitHub にプッシュします。
次に、CircleCI ダッシュボードの Add Projects (プロジェクトの追加) ページにアクセスします。
Set Up Project (プロジェクトをセットアップ) をクリックします。
セットアップページで、Use Existing Config (既存の設定ファイルを使用する) をクリックします。 CI パイプラインの設定ファイルをダウンロードするのか、ビルドを開始するのかを確認するメッセージが表示されます。
Start Building (ビルドを開始) をクリックして、ビルドを開始します。 設定ファイルのセットアップがまだのため、このビルドは失敗します。 というわけで、セットアップを行います。
プロジェクトのルートに .circleci
という名前のフォルダーを作成し、config.yml
という名前の設定ファイルを追加します。 このファイルに、以下のコードを貼り付けます。
version: 2.1
jobs:
build:
working_directory: ~/repo
docker:
- image: circleci/node:10.16.3
steps:
- checkout
- run:
name: Update NPM
command: "sudo npm install -g npm@5"
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Install Dependencies
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: Run tests
command: npm run test
上記のパイプライン設定ファイルでは、まず、Next.js アプリケーションの実行に必要なバージョンの Node.js がインストールされた Docker イメージをインポートしています。 次に、npm
を更新して依存関係をインストールしてから、後のビルドを高速化するためにキャッシュします。
最後に、npm run test
コマンドで、プロジェクト内にあるすべてのテストを実行します。
設定ファイルを保存して、リモートリポジトリにすべての変更をコミットしましょう。 これで、パイプラインがもう一度トリガーされ、作成したビルドスクリプトが実行されます。
build (ビルド) をクリックして、テストの詳細を確認します。
完璧です。
まとめ: ボイラープレートコードによって生じる負担をなくす
今回のプロジェクトは、GitHub のこちらのリポジトリにあります。
Next.js は、本番用アプリケーションの開発に適した素晴らしいフレームワークです。その理由は、ボイラープレートコードによって生じる負担をなくす機能が用意されていることにあります。 本番環境において、壊れたコードには遭遇したくないものです。 このチュートリアルでは、機能のテスト方法、そして新しいコードをプッシュするたびにテストを自動で実行する方法について学びました。 これらの手法を活用すれば、問題のあるコードがデプロイ環境にプッシュされてしまう事態を防止できるでしょう。
Happy coding!