E2EテストをCIでも気軽に利用しよう 〜 Cypress x Docker Compose


2019/11/18追記 日本語フォント表示用にDockerfileを修正しました。

はじめに : Cypressの紹介

Cypressは、無料で利用できるOSSのEnd-to-End(E2E)のテストツールです。以下のように自分のブラウザを利用してWeb UIテストを実行します。

以下のようなコードを元に、実際にブラウザで動かしながら、直感的にテストをすることができます。JavaScriptでテストコードを記述できるので、利用しているJSerも多いです。

describe('The Login Page', function () {
  beforeEach(function () {
    // reset and seed the database prior to every test
    cy.exec('npm run db:reset && npm run db:seed')
    // seed a user in the DB that we can control from our tests
    // assuming it generates a random password for us
    cy.request('POST', '/test/seed/user', { username: 'jane.lane' })
      .its('body')
      .as('currentUser')
  })

  it('sets auth cookie when logging in via form submission', function () {
    // destructuring assignment of the this.currentUser object
    const { username, password } = this.currentUser
    cy.visit('/login')
    cy.get('input[name=username]').type(username)
    // {enter} causes the form to submit
    cy.get('input[name=password]').type(`${password}{enter}`)
    // we should be redirected to /dashboard
    cy.url().should('include', '/dashboard')
    // our auth cookie should be present
    cy.getCookie('your-session-cookie').should('exist')
    // UI should reflect this user being logged in
    cy.get('h1').should('contain', 'jane.lane')
  })
})

参考URL : https://docs.cypress.io/guides/getting-started/testing-your-app.html#Logging-in

E2EテストをCIサーバで実行する

ローカルブラウザでCypressを利用すると捗るのですが、CIへの組み込みがなかなか進まず、専用のマシンを用意しておこうか、と思ったところCypressの公式コンテナがあることに気が付きました。

そして少しのコードで専用マシンなどを用意せず、以下の構成でCIのフローに乗せることができました。

追加したファイルの紹介

追加したファイルは以下の3つです。

フロントエンド用のDockerfile

全環境共通のDockerfileです。環境変数で環境ごとの情報を管理します。

# ファイルをビルド
FROM node:13.1.0-alpine as build
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY . /app
RUN npm install --silent
RUN npm run build

# nginxコンテナにビルドしたファイルをコピー
FROM nginx:1.16.0-alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Cypress用Dockerfile

FROM cypress/base:10
# 日本語フォント表示用にnoto-cjkを追加
RUN apt-get install --no-install-recommends -y fonts-noto fonts-noto-cjk
WORKDIR /app
COPY package.json .
COPY package-lock.json .
ENV CI=1
RUN npm ci
RUN npx cypress verify

docker-compose.yml

version: '3'
services:
  web:
    image: frontend:latest
    ports:
      - "8080:80"
  e2e:
    build:
      context: .
      dockerfile: ./Dockerfile
    command: npx cypress run
    depends_on:
      - web
    environment:
      - CYPRESS_baseUrl=http://web
      - CYPRESS_browser=chrome
      - CYPRESS_screenshotsFolder=/results/screenshots
      - CYPRESS_videosFolder=/results/videos
    volumes:
      - ./cypress:/app/cypress
      - ./cypress.json:/app/cypress.json
      - ./results:/results

docker-compose.yamlの解説

CYPRESS_xxxx の環境変数部分でConfigurationを設定しています。CYPRESS_browserという変数もありますが、現在選べるのは、chrome/chromium/canaryのいずれかです。それ以外のブラウザはサポートされません。

ローカルで docker-compose up を実行すれば、マウントされた results/videos 以下にスクリーンショットと、動作時の録画データが入ります。


※ /results/screenshots に出力される録画データ。 (mp4で出力されたものをgifに変換)

CI時、テストが失敗したら終了したい場合、以下のコマンドを利用します。

docker-compose up --abort-on-container-exit --exit-code-from e2e

CI上で試したいときは、Slackなどにファイルを添付して渡すと、原因究明がはかどります。

最後に : 実際の利用シーン

Google Chromeがインストールされていない環境でも、簡単にテストが行えるようになりました。

新しくテストコードを書く時は、実際にブラウザで操作しながら書く方が楽なので、ローカルでも動くようにしています。

以下のようなフローでテストを追加しているという一例です。

  1. npx cypress open を実行して、ローカルブラウザでテストを書く
  2. docker-compose upを実行すると、コンテナ内でテストが自動実行される

リクエストが多ければGitHubにひな形を作成するので、興味がある方はリクエストをください。