Cypressを使ったE2Eテストの環境構築から、テスト動画を継続的にGitHub Actionsへアップロードするまで
目次
はじめに
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#title
がCypress 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 run
やnpx 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 start
でhttp://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-action@v1.16.1
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-action@v1.16.1
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にアップロードするかどうかは、プロダクトの性質などを元に慎重に検討しましょう。