GitLab-CIとCypressを連携してみた（公式dockerイメージ編）

# 背景

WebアプリケーションのGUI自動テストを実施することになった。
自動テストのフレームワークは[Cypress](https://www.cypress.io/)を導入する。
せっかくテストを自動化するのに、手動トリガではカッコ悪いし非効率なので、トリガも自動で発動するようにしたい。

既にオンプレミスのGitLab環境で[GitLab-CI](https://docs.gitlab.com/ce/ci/)を活用していたので、GitLab-CIからCypressによる自動試験を実行する手法を調査。

[前回の記事](https://qiita.com/itTkm/items/f81987ed27d5a5f42aa5)では自前で環境を構築したが、今回は[公式のdockerイメージ](https://github.com/cypress-io/cypress-docker-images)を使ってみた。
前回自力で頑張ったのがアホらしいくらいに簡単に導入できてしまった。

また、今回は複数テストを実行したり、実行条件を変えながら実行したりするケースも考慮して`.gitlab-ci.yml`を書いてみた。

# 環境

* CentOS 7.5.1804
* GitLab CE 11.11.3
* gitlab-runner v12.6.0
* Cypress v3.7.0

# docker版の`gitlab-runner`を起動

```bash
docker run -d \
    --name gitlab-runner-docker \
    --restart always \
    -v /srv/gitlab-runner-docker/config:/etc/gitlab-runner \
    -v /var/run/docker.sock:/var/run/docker.sock \
    gitlab/gitlab-runner:v12.6.0
```

# GitLabにrunnerを登録

```bash
docker exec gitlab-runner-docker gitlab-runner register \
    --non-interactive \
    --url {your_gitlab_url} \
    --registration-token {your_gitlab_runner_token} \
    --name "gitlab-runner-docker" \
    --tag-list "autotest-server,docker" \
    --executor "docker" \
    --docker-image "alpine:latest"
```

# `.gitlab-ci.yml`を作成

```yaml:.gitlab-ci.yml
stages:
  - cypress

variables:
  AUTO_TEST_SERVER: "192.168.1.10"
  AUTO_TEST_SERVER_PORT: "3000"
  GIT_CLEAN_FLAGS: -fdx --exclude node_modules/ --exclude build/

.gui_test:
  stage: cypress
  image:
    name: cypress/included:3.7.0
    entrypoint: [""]
  variables:
    CY_SPEC: "**/*.spec.js"
    CY_BASE_URL: https://$AUTO_TEST_SERVER:$AUTO_TEST_SERVER_PORT
    CY_VIEWPORT_HEIGHT: 1080
    CY_VIEWPORT_WIDTH: 1920
  script:
    - cypress run --spec $CY_SPEC --config baseUrl=$CY_BASE_URL,viewportHeight=$CY_VIEWPORT_HEIGHT,viewportWidth=$CY_VIEWPORT_WIDTH
  artifacts:
    # エビデンスをGitLabのGUIから参照するための設定
    expire_in: 1 week
    when: always
    paths:
    - cypress/screenshots
    - cypress/videos
  tags:
    - autotest-server
    - docker

test1:
  extends: .gui_test
  variables:
    CY_SPEC: cypress/integration/test/sample1.spec.js

test2:
  extends: .gui_test
  variables:
    CY_SPEC: cypress/integration/test/sample2.spec.js

test3:
  extends: .gui_test
  variables:
    CY_SPEC: cypress/integration/test/sample2.spec.js
    CY_VIEWPORT_HEIGHT: 1136
    CY_VIEWPORT_WIDTH: 640
```

ベースのイメージは`cypress/included`とし、エントリーポイントを上書きして使用している。

GitLab-CIとの連携方法で調べると、`cypress/base:10`を使用している例ばかりヒットする。
今回、これに従っていないのは、`cypress/base:10`を使用すると、ジョブ実行のたびにコンテナ内でCypressや関連パッケージのインストール処理が走り、これが非常に長く非効率なため。
`cypress/included`であれば、Cypressや関連パッケージがインストール済みなので、今回はこちらを採用した。

また、今回は複数のテストを実行することを考慮し`.gui_test`というテンプレートジョブを作成。
各テスト実行ジョブは`.gui_test`を継承するようにしている。
継承する場合でも、一部の定義を上書きできるので、この例のように「同じテストを画面サイズを変更しながらテストする」といった使い方が可能になる。

こうしておくと、実行対象が大量にあっても、同じような定義を書いてメンテナンスしづらくなるということはない。

なお、Cypressは複数のテストを一度の実行でまとめて実行する機能がある。
この場合は、`cypress run --spec "sample1.spec.js,sample2.spec.js"`のように指定すれば良い。

本来はこの機能を使用し、複数のテストを1つのジョブにまとめてしまいたいが、[未解決のCypress側のIssue](https://github.com/cypress-io/cypress/issues/3310)の影響で、2個目以降のテストがタイムアウトして実行されない。（現時点の最新版`3.8.1`でも未解決）
このため、今回は苦肉の策で、テストの実行ジョブを、テストファイルごとに分けた、という背景もある。

# GitLab-CIを本番実行

GitLabのGUI上からCIを手動実行する。
正常に動くことが確認できれば、あとはトリガーなどを適切に設定し、いよいよ本番運用開始！！！

# エビデンスはGitLabのGUIから参照可能

GitLabのGUIでジョブの実行結果ページを参照すると、`.gitlab-ci.yml`で`artifacts`に登録したパスのファイルが参照できるようになっている。
当然ダウンロードも可能だが、ダウンロードせずにGitLabのGUI上からスナップショットや動画を直接確認できるので、とっても便利。