Next.jsのキャッチコピーは本番環境のための React フレームワーク。 React.js 開発ですぐに使えるルーティング、コード分割、バンドル分割、Typescript、組み込みの CSS サポートなどの機能が揃っており、本番環境レベルのアプリケーションを開発できます。 こうした機能は、本番アプリケーションの開発には必須です。 このチュートリアルでは、Next.js アプリケーションに継続的インテグレーション (CI) を実装する方法について解説します。具体的には、アプリケーションに追加した機能を自動でテストするテストフレームワークを準備し、プロセスの中断をなくします。

Next.js とは?

Next.js (ネクストジェイエス) とは、Reactのフレームワークです。Next.js のフレームワークを使用すれば、Reactとは違い、プリレンダリングが可能になり、Webクローラーなどのクローリング対策にも好評であり、SEOなどにも最適な効果があるフレームワークとしても知られています。また、Next.jsでは SSR や SPA も可能になるので多様なメリットが存在します。

前提条件

このチュートリアルを進めるには、いくつかの準備が必要です。

  1. JavaScript の基礎を理解する
  2. Node.js (バージョン 10.13 以上) をローカルシステムにインストールする
  3. CircleCI アカウントを用意する
  4. 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 にアクセスします。

新規ローカルアプリ - Next.js

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.jsstyleMock.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

2回目のローカルテスト

継続的インテグレーションでテストを自動化する

テストの実行も無事に完了し、良い調子です。 とは言え、”テストの実行” が今回のゴールではありません。 継続的インテグレーションを実装して、テストの実行を自動化しましょう。 自動化によって、リポジトリに更新をプッシュするたびにテストが実行されるようになります。

初めに、プロジェクトを GitHub にプッシュします。

次に、CircleCI ダッシュボードの Add Projects (プロジェクトの追加) ページにアクセスします。

CircleCI にプロジェクトを追加

Set Up Project (プロジェクトをセットアップ) をクリックします。

CircleCI コンフィグ追加

セットアップページで、Use Existing Config (既存の設定ファイルを使用する) をクリックします。 CI パイプラインの設定ファイルをダウンロードするのか、ビルドを開始するのかを確認するメッセージが表示されます。

Build Prompt - CircleCI

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 コマンドで、プロジェクト内にあるすべてのテストを実行します。

設定ファイルを保存して、リモートリポジトリにすべての変更をコミットしましょう。 これで、パイプラインがもう一度トリガーされ、作成したビルドスクリプトが実行されます。

CircleCI ビルド成功

build (ビルド) をクリックして、テストの詳細を確認します。

ビルドの結果

完璧です。

まとめ: ボイラープレートコードによって生じる負担をなくす

今回のプロジェクトは、GitHub のこちらのリポジトリにあります。

Next.js は、本番用アプリケーションの開発に適した素晴らしいフレームワークです。その理由は、ボイラープレートコードによって生じる負担をなくす機能が用意されていることにあります。 本番環境において、壊れたコードには遭遇したくないものです。 このチュートリアルでは、機能のテスト方法、そして新しいコードをプッシュするたびにテストを自動で実行する方法について学びました。 これらの手法を活用すれば、問題のあるコードがデプロイ環境にプッシュされてしまう事態を防止できるでしょう。

Happy coding!


Fikayo Adepoju は、Web とモバイル テクノロジー、DevOps に精通した LinkedIn Learning (Lynda.com) 講師、フルスタック開発者、テクニカル ライター、テクニカル コンテンツ クリエイターです。スケーラブルな分散アプリケーション開発については 10 年以上の経験を持っています。 CircleCI、Twilio、Auth0、The New Stack のブログで 40 以上の記事を執筆するほか、個人の Medium ページでも情報を発信しており、役立つ知識を多くの開発者に広めることに専心しています。 また、Udemy で動画形式のコース (英語) も開講しています。ぜひご覧ください。

さんの他の投稿を読む Fikayo Adepoju