目次

はじめに

Cypressは、Node.js製のE2Eテストフレームワークです。E2Eテストの環境を簡単に構築でき、デフォルトでスクリーンショットやテスト動画の撮影ができたり、プラグインも豊富でとても高機能です。

このブログでもCypressで簡単なE2Eテストを行っており、GitHub Actionsと併用して継続的にテスト動画をGitHub Actionsにアップロードするようにしています。とても便利...!

そこで今回は、Cypressの環境構築からE2Eテスト動画をGitHub Actionsへアップロードするまでの手順を紹介します。CypressのAPIには深く触れないので、必要に応じて公式のドキュメントを合わせて見てください。

また、今回のサンプルファイル一式をGitHubリポジトリで公開しています。気になる方はkimulaco/cypress-exampleを参照してください。

Cypressの環境構築

まずは、次のようにnpmやyarnでCypressをインストールし、Cypressのアプリを起動します。

# Cypressをインストール
npm install --save-dev cypress

# Cypressのアプリを起動
npx cypress open

Cypressにはデスクトップアプリも付属しており、E2Eテストの実行やプレビューができます。

また、cypress open実行時に、テストに必要なファイルを自動で作成してくれます。初回実行時は、次のようなファイルが生成されます。

├── /cypress/
│   ├── fixtures/
│   │   ├── example.json
│   │   ├── profile.json
│   │   └── users.json
│   ├── integration/
│   │   └── examples/
│   │       └── *.spec.js
│   ├── plugins/
│   │   └── index.js
│   ├── screenshots/
│   │   └── examples/
│   │       └── misc.spec.js
│   │           └── my-image.png
│   ├── support/
│   │   ├── commands.js
│   │   └── index.js
│   └── videos/
│       └── examples/
│           └── *.spec.js.mp4
└── cypress.json

/cypress/fixtures/cypress/integrationには、Cypressの公式サイトのE2Eテストを行うサンプルファイルが生成されていますが、不要なので消してしまっても大丈夫です。また、/cypress/videos/cypress/screenshotsはテストのスクリーンショットや動画が出力されるフォルダなので、特に理由がなければ.gitignoreでignoreしてしまうのが良いと思います。

E2Eテストを実行するには、ターミナルでnpx cypress runを実行するか、Cypressのアプリで可能です。

ローカルサーバーでE2Eテストをする

デフォルトで生成されたサンプルファイルは、公開されているURLのE2Eテストです。今回は作業中のページでE2Eテストを行うケースを想定して、ローカルサーバー上のページをE2Eテストできるようにします。ローカルサーバーでのテストが必要ない方は、適時読み飛ばしてもらって大丈夫です。

テストをするページの準備

簡単なE2Eテストを実施するために、/docs/index.htmlに次のようなHTMLファイルを用意しました。ユーザーエージェントのスタイルだと味気ないので、Classless CSSフレームワークのWater.cssを読み込んでいます。実際のページはこちら

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <title>Cypress Example</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kognise/water.css/dist/light.min.css">
</head>
<body>
  <main>
    <h1 id="title">Cypress Example</h1>
    <p>This page is for trying Cypress.</p>
    <p>See <a href="https://github.com/kimulaco/cypress-example">here</a> for the full source code.</p>
  </main>
</body>
</html>

次に、/docs/index.htmlをlocalhostで表示させます。今回はserveというnpmを使いますが、静的なHTMLをlocalhostで表示できれば何でも大丈夫です。次のコマンドで、サンプルページがhttp://localhost:3000で見れるようになります。

# serveをインストール
npm install --save-dev serve

# /docsでポート3000のローカルサーバーを起動
npx serve docs -p 3000

テストコードの作成

ページの準備ができたらテストコードを書きましょう。h1#titleCypress Exampleと表示されているか確認するためだけのE2Eテストを準備します。/cypress/integration/examples/index.spec.jsに次のテストコードを作成します。わずかなコードでとても直感的に書けますね。

// /cypress/integration/examples/index.spec.js
it('Page title', () => {
  cy.visit('http://localhost:3000/')
  cy.get('h1#title').should('be.text', 'Cypress Example')
})

テストの実行

テストに必要なファイルが揃いました。npx serve docs -p 3000でローカルサーバーを起動した状態で、npx cypress runまたはCypressアプリからE2Eテストを実行できます。

ただし、毎回ローカルサーバーを手動で起動したり、テストに合わせてローカルサーバーの起動や停止を行うように自力で工夫するのも面倒です。なので、公式でも推奨されているstart-server-and-testを使うのがおすすめです。ローカルサーバーとE2Eテストのプロセスをよしなに実行してくれます。次のコマンドでインストールできます。

npm install --save-dev start-server-and-test

そして、start-server-and-testを使うためにnpx cypress runnpx serve docs -p 3000などをnpm-scripts化しておきましょう。今回は次のようにしました。(scriptsだけ抜粋しています。)

// package.json
{
  ...
  "scripts": {
    "start": "serve docs -p 3000",
    "test": "start-server-and-test start http://localhost:3000 cy:run",
    "cy:run": "cypress run",
    "cy:open": "cypress open"
  },
  ...
}

npm run testを実行すると、npm run starthttp://localhost:3000が起動するのを待ち、起動したらnpm run cy:runでCypressのE2Eテストを実行できます。

GitHub ActionsでCypressを実行する

CypressでE2Eテストができるようになったので、GitHub Actionsで継続的にテストできるようにしましょう。今回は/.github/workflows/test.ymlに次のようなworkflowファイルを作成します。

# /.github/workflows/test.yml
name: Test
on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js 12.x
      uses: actions/setup-node@v1
      with:
        node-version: 12.x
    - run: yarn
    - name: Run Test
      uses: cypress-io/github-[email protected]
      with:
        start: yarn start # ローカルサーバーを起動するコマンド
        wait-on: 'http://localhost:3000' # 起動を待つローカルサーバーのURL
    - name: Upload E2E test videos
      uses: actions/upload-artifact@v1
      if: always()
      with:
        name: Cypress Videos
        path: cypress/videos

やっていることはシンプルです。大まかに、npmのインストール、CypressでE2Eテストの実行、生成されたテスト動画をGitHub Actionsにアップロードの3つのみです。ポイントとなる部分だけ抜粋します。

Cypressとローカルサーバーの実行

CypressをGitHub Actionsで実行するには、公式で開発されているcypress-io/github-actionというActionがあるので、それを使います。一般的に、CIでヘッドレスブラウザを使用するには、OSレベルで必要なものを別途インストールする必要があったりするため、このように実行環境を簡単にセットアップできるのはとてもありがたいです。

そして、startでローカルサーバーを起動するコマンド、wait-onで起動するローカルサーバーのURLを記述しています。

- name: Run Test
  uses: cypress-io/github-[email protected]
  with:
    start: yarn start # ローカルサーバーを起動するコマンド
    wait-on: 'http://localhost:3000' # 起動を待つローカルサーバーのURL

GitHub Actionsにファイルをアップロードする

GitHub Actionsにファイルをアップロードするには、actions/upload-artifactというGitHub公式のActionを使います。次のように、withにアップロードするファイルやディレクトリのパスと、アップロードしたファイルがzip化される際につける名前を指定します。

- name: Upload E2E test videos
  uses: actions/upload-artifact@v1
  if: always()
  with:
    name: Cypress Videos
    path: cypress/videos

また、GitHub Actionsのワークフロー構文ではifが使えます。サンプルのworkflowではテストの成否に関係なく動画をアップロードするためにif: always()としています。テストに失敗した時のみアップロードしたい場合は、if: failure()としましょう。

アップロードされた動画ファイルは、GitHub ActionsのArtifactsにnameで指定した名前で登録されており、zipファイルでダウンロードできます。

さいごに

Cypressの環境構築から、E2Eテスト動画をGitHub Actionsへアップロードするまでの手順を駆け足で解説しました。

実は過去に、実装ミスでこのブログのサイトマップにあるURLがいくつか404ページに遷移してしまうバグがあったのですが、特定ページのみだったので気づくのに時間がかかってしまいました。ですが、継続的にE2Eテストを行うことでバグを早く発見することができ、さらにテスト動画もアップロードしたことで状況の確認がスムーズになったため導入して正解でした。

Cypressは、E2Eテストの導入を検討している方にとっては、とても有力なフレームワークだと思います。

ただし、GitHub Actionsにテスト動画をアップロードするにあたって注意が必要な点もあります。GitHub ActionsのArtifactsは、GitHubユーザーであれば誰でもダウンロードできてしまうので、テストの画面やテストメッセージなどにセキュアな内容を表示してしまうと、第三者に見られてしまう可能性があります。なので、テスト動画をGitHub Actionsにアップロードするかどうかは、プロダクトの性質などを元に慎重に検討しましょう。