🚀

Next.jsプロジェクトにCypressを導入してGitHub ActionsでE2Eテストをする

2021/07/11に公開

はじめに

※この記事は下記記事の延長です。下記記事を読まなくても問題ないように書いていますが、ご興味ありましたらご一読ください。
https://zenn.dev/a_da_chi/articles/181ea4ccc39580#スナップショットテスト導入

今回はNext.jsプロジェクトにCypressを導入してGitHub ActionsでVercelのPreview環境のE2Eテストをするまでの手順を書いていきたい思います。

前提

  • Next.jsでsrcディレクトリ配下にアプリケーションコードを配置していること
  • Vercelを使用しており、PRごとにPreview環境がデプロイされること

導入手順

  1. 必要なパッケージをインストール
  2. npm scriptsをpackage.jsonに追加
  3. yarn cy:openを実行し雛形を作成
  4. 設定ファイルを修正し初めてのテストを実行
  5. TypeScript対応
  6. @testing-library/cypressの設定
  7. GitHub Actionsの設定

必要なパッケージをインストール

yarn add cypress @testing-library/cypress --dev

@testing-library/cypressはCypressのテストコードで使える便利コマンドを提供してくれます。

npm scriptsをpackage.jsonに追加

package.json
"scripts": {
  "cy:open": "cypress open",
  "cy:run": "cypress run"
}

これでyarn cy:openでテストのGUI実行などができるCypressアプリが起動し、yarn cy:runでCypressによるテストのCLI実行が可能になります。

yarn cy:openを実行し雛形を作成

yarn cy:open

初めてyarn cy:openを実行すると、以下のような設定ファイルやサンプルのテストコードなどがcypressディレクトリの配下に作成されます。

  • cypress.json: Cypressの設定ファイル
  • cypress/fixtures: Cypressのテストコードで使えるテストデータを配置するディレクトリ
  • cypress/integration: Cypressのテストコードを配置するディレクトリ
  • cypress/plugins: Cypressのプラグイン用設定ファイルを配置するディレクトリ
  • cypress/support: Cypressにカスタムコマンドを追加するための設定ファイルなどを配置するディレクトリ

設定ファイルを修正し、初めてのテスト実行

以下のようにcypress.jsonbaseUrlを追加します。

cypress.json
{
  "baseUrl": "http://localhost:3000"
}

次にcypress/integration配下のファイルを全て削除し、以下のテストファイルを追加します。このテストはルートパスに訪問できるかを検証しています。

cypress/integration/example.spec.js
it('ルートパスに訪問できるか', () => {
  cy.visit('/')
})

この状態でターミナルで以下のコマンドを入力して、テストを実行します。

yarn cy:run

するとCypressによるテストが実行されます。
ここでcypress/videosを確認するとテストが実行されている様子を動画で確認できます。
またテストが失敗した場合はcypress/screenshotsにテストが失敗した時点のスクリーンショットを確認できます。

以下のように.gitignoreを修正してこれらのディレクトリがリポジトリに含まれないようにしておきましょう。

.gitignore
# cypress
cypress/screenshots
cypress/videos

またcypress.jsonに設定を追加することで動画やスクリーンショットを保存しないようにすることも可能です。

TypeScript対応

以下のようにcypress配下にtsconfig.jsonを追加します。

cypress/tsconfig.json
// @see https://docs.cypress.io/guides/tooling/typescript-support#Clashing-types-with-Jest
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "types": ["cypress"],
    "isolatedModules": false
  },
  "include": ["../node_modules/cypress", "./**/*.ts"],
  "exclude": []
}

Jestを導入しているプロジェクトも多いと思うので、今回はCypressの型とJestの型が衝突してしまう問題を解消するための設定を紹介しています。

次にcypress配下のファイルの拡張子を.tsに変更します。
この時cypress/plugins/index.tsの型エラーの解消とcypress.jsonに設定の追加を行います。

cypress/plugins/index.ts
-  module.exports = (on, config) => {
+  module.exports = (_on: Cypress.PluginEvents, _config: Cypress.PluginConfig) => {
cypress.json
"baseUrl": "http://localhost:3000",
+ "pluginsFile": "cypress/plugins/index.ts",
+ "supportFile": "cypress/support/index.ts"

@testing-library/cypressの設定

以下のように@testing-library/cypressの設定をすることでCypressで使える便利コマンドを追加することができます。

cypress/support/commands.ts
+ import '@testing-library/cypress/add-commands'
cypress/tsconfig.json
"compilerOptions": {
+  "types": ["cypress", "@testing-library/cypress"],

例えば、CypressのBest Practicesでも紹介されている、data属性を使用した要素の取得を便利にするコマンドを使用できます。
以下のような設定をすることでcy.findByTestIdに取得したい要素のdate-test-id属性の値を渡すことで要素を取得できます。

cypress/support/index.ts
+ // @see https://github.com/testing-library/cypress-testing-library#config-testidattribute
+ import { configure } from '@testing-library/cypress'
+ configure({ testIdAttribute: 'data-test-id' })
対象の要素
<button data-test-id="hoge-button">hoge</button>
Cypressのテストファイル
cy.findByTestId("hoge-button").click()

ちなみにfindByTestIdを使用せずに要素を取得する場合は以下のようになります。

cy.get("[data-test=hoge-button]").click()

GitHub Actionsの設定

ここまででローカル環境ではテストを実行するところまで完了したので、GitHub Actionsでも実行できるようにしましょう。

以下の設定ファイルを追加してください。

.github/workflows/cypress.yml
name: Cypress

on: deployment_status

jobs:
  cypress:
    if: |
      github.event.deployment_status.state == 'success' && 
      github.event.deployment_status.environment == 'Preview'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: 14.x
      - uses: actions/cache@v2
        with:
          path: ~/.cache/yarn
          key: ${{ runner.os }}-yarn-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }}
          restore-keys: ${{ runner.os }}-yarn-
      - name: Install dependencies
        run: yarn install --frozen-lockfile --prefer-offline
      - name: Run cypress
        uses: cypress-io/github-action@v2
        with:
          install: false
          config: baseUrl=${{ github.event.deployment_status.target_url }}

on: deployment_statusを指定することで、VercelがPreview環境へのデプロイを開始した時とデプロイを完了した時の2回、このワークフローが実行されます。
今回はVercelのPreview環境のE2Eテストをしたいので、デプロイを完了した時のみこのワークフローが実行されるようにifに条件を指定しています。
Cypressの実行にはcypress-io/github-action@v2を使用し、実行対象のURLにPreview環境のURLを指定しています。

この状態でGitHubでPRを作成すると、VercelがPreview環境へのデプロイを完了した時にCypressが実行されると思います。

おわりに

いかがでしたか。
これでNext.jsプロジェクトにCypreesを導入してGitHub ActionsでVercelのPreview環境のE2Eテストをすることができました。
ここまでしておけば機能追加や修正時の手動テストの削減につながると思うのでぜひ導入してみてください。
それではよいNext.jsライフを!

Discussion