GitHub Actions で Cypress の end-to-end test を実行する

LitElement を利用した Custom Element の開発をしていて、 enzyme や vue-test-utils のようなコンポーネントのテストを記述したい。

ただ Custom Element 開発はブラウザの文脈に依存するものが非常に多く、Open WC などがツールを出しているみたいだけれど、ちょっとしたコードを書くには1からキャッチアップするのも大変。ということで、 Cypress で End-to-End でテスティングすることにした。

Jest + Puppeteer で自作しても良かったけれど、Shadow DOM にうまくアクセスする方法を持ち合わせていなかったので、試しも兼ねてというところ。

ローカルで一通り動いたので、CI に載せたくなったのは良いものの setup が少しクセがあったのでまとめておく。

GitHub Actions で動作させるために必要なコード

Cypress を CI 上で動作させるにあたって、ネックになってくるのはアクセス先のサーバーが立ち上がるまで待つ部分。

色々方法はあるみたいだけど、オフィシャルのドキュメントの Issue トラッカーをみていたら start-server-and-test を利用する方法が見つかったので、これを採用した。

まずは start-server-and-test と http-server をパッケージとしてインストール。

$ yarn add -D http-server start-server-and-test

その上で読みやすいようにそれぞれのタスクの script を追加し、

{
  "scripts": {
    "test": "start-server-and-test 'test:serve' 1234 'test:cypress'",
    "test:serve": "http-server ./dist/ -c-1 --silent --port 1234",
    "test:cypress": "cypress run",
  }
}

最後に yarn test で OK。

start-server-and-test を利用すると、 $1 のタスクを実行したあとに、 $2 のポートが動くまで待機。対象ポートから 200 OK が返却されたら、 $3 のタスクを実行するまでをやってくれる。

今回はビルド環境に Parcel を利用しており、そのまま parcel index.html という手段もあったかもしれないが、ビルドが増えるにあたってビルド中の画面のまま Cypress が走り出すリスクを考慮して、ビルド後に http-server で起動するようにした。

ここまででパラレルで何かを動作させる必要なく Cypress を実行する環境が整ったので、あとはこれを Workflow に適用するだけ。

こちらは特別なことはせず、以下のように設定した。parcel のビルドを NPM script に登録していないのは、 build タスク回りはライブラリとしての出力のための rollup の設定で埋まっているため。

name: test

on: [push]

jobs:
  cypress-run:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Use Node.js 14.x
        uses: actions/setup-node@v1
        with:
          node-version: 14.x
      - name: Run End-to-End Test
        run: |
          yarn
          yarn build
          yarn parcel build ./example/index.html
          yarn test

これで OK。実行すると、こんな感じでうまい具合に動いてくれる。

Image from Gyazo

正直 start-server-and-test を入れたくない気持ちがあるので、 Jest の globalSetup みたいな方法を探したいところ。なんだかんだ Jest は最悪 beforeAll でもサボれて楽で良い。