Nuxt on Dockerにて、Jest + Puppeteer でE2Eテスト環境をセットアップする

6 min読了の目安(約5600字TECH技術記事

はじめに

テスト自動化したい...テスト駆動したい...E2Eで!!
Nuxt.jsをDockerで開発するにあたって、E2Eテスト環境を用意するまでの軌跡です。
テストフレームワークにはJest、ブラウザ操作にはPuppeteerを利用します。

手順

  1. DockerでNuxtアプリをつくる
  2. Dockerコンテナ内でブラウザを起動できるようにする
  3. Jest+PuppeteerでE2Eテストできるようにする

DockerでNuxtアプリをつくる

アプリの前提の意味で、こんな感じでNuxt on Dockerを作っています紹介です。

$ docker run -it -w /app -v `pwd`:/app node yarn create nuxt-app .
...
create-nuxt-app v3.5.2
✨  Generating Nuxt.js project in .
? Project name: app
? Programming language: JavaScript
? Package manager: Yarn
? UI framework: None
? Nuxt.js modules: -
? Linting tools: -
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Server (Node.js hosting)
? Development tools: -
n)
? What is your GitHub username? -
? Version control system: None

yarn create nuxt-appはターゲットのディレクトリ(今回はカレントディレクトリ)が空でないとエラーになるので要注意。初期設定は特に何も入れてません。

これでローカルにNuxtアプリのファイルが生成されるので、このアプリを動かすためのDockerfiledocker-compose.ymlをつくっていきます。

Dockerfile
FROM node
ENV HOME=/app \
    HOST=0.0.0.0
    
WORKDIR ${HOME}

COPY package.json ${HOME}
COPY yarn.lock ${HOME}
RUN yarn install

COPY . ${HOME}
EXPOSE 3000
CMD ["yarn", "dev"]
docker-compose.yml
version: '3'

services:
  app:
    build: .
    volumes:
      - .:/app
    ports:
      - 3000:3000

これをビルドして起動してみます。

$ docker-compose build
$ docker-compose up

http://localhost:3000にアクセスできていればOKです。

Dockerコンテナ内でブラウザを起動できるようにする

PuppeteerをDockerで使う場合、コンテナ内でブラウザを起動させられるようにする必要があります。puppeteerのトラブルシューティングにやり方が載っているので、それに合わせてDockerfileを更新します。

Dockerfile
  FROM node
  ENV HOME=/app \
      HOST=0.0.0.0

  WORKDIR ${HOME}

+ RUN apt-get update \
+     && apt-get install -y wget gnupg \
+     && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
+     && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
+     && apt-get update \
+     && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
+       --no-install-recommends \
+     && rm -rf /var/lib/apt/lists/*

  COPY package.json ${HOME}
  COPY yarn.lock ${HOME}
  RUN yarn install

  COPY . ${HOME}
  EXPOSE 3000
  CMD ["yarn", "dev"]

これでHeadless Chromeを使ってPuppeteerでブラウザ操作をする環境ができます。

Jest+PuppeteerでE2Eテストできるようにする

最後にJest+Puppeteerの環境を整えていきます。
JestでPuppeteerを利用する手順は公式ドキュメントにも載っています。
まず、Jest、Puppeteer、そしてその2つの設定をいい感じにやってくれるjest-puppeteerのライブラリをインストールします。jest-puppeteerのおかげで、pagebrowserなどのPuppeteerのAPIが特に意識することなくGlobalに扱えたりします。

$ docker-compose run --rm app yarn add --dev jest puppeteer jest-puppeteer

package.jsonに追加されるのでコンテナを再ビルドしてコンテナイメージにも適用してきます。

$ docker-compose build

次にconfigファイルをつくります。まずはjestの設定から。

jest.config.js
module.exports = {
  verbose: true,
  preset: 'jest-puppeteer'
}

これでjest-puppeteerを活用できるようになります。次はjest-puppeteerの設定をします。

jest-puppeteer.config.js
module.exports = {
  launch: {
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  },
  server: {
    command: 'yarn build && yarn start --port 3000',
    port: 3000,
    launchTimeout: 50000
  }
}

Headless chromeの設定と、サーバー(アプリの起動)についての設定をします。

最後に、package.jsonでテスト実行コマンドを定義します。

package.json
  {
    ...
    "scripts": {
      "dev": "nuxt",
       "build": "nuxt build",
      "start": "nuxt start",
-     "generate": "nuxt generate"
+     "generate": "nuxt generate",
+     "test": "jest -i"
    }
    ...
  }

-iオプションは--runInBandオプションの省略形で、テストスイートを並列でテストしないオプションです。並列でテストしたときにそれぞれのテストスイートが影響しあってしまったのか、うまく行かないことがあったのでつけてます。
他のオプションはJestの公式ドキュメント参照です。

Jest CLI Options · Jest

テストしてみる

では実際にテストが動作するか確認してみます。
まずはテストファイルを格納するディレクトリを作成し、テストファイルをつくりましょう。
Jestではデフォルトでtestsディレクトリ以下のファイルを読み込みます(Jestの設定 · Jest)。

$ mkdir tests
tests/test.spec.js
describe('サンプルテストスイート', () => {
  test('トップページでアプリ名が表示されていること', async () => {
    await page.goto('http://localhost:3000')
    await expect(await page.$eval('h1.title', el => el.innerText)).toBe("app")
  })
})

トップページにアクセスして、「app」の文字列がh1.title要素に表示されていることをチェックするテストです。
では、実行。

$ docker-compose run app yarn test
Creating test_app_run ... done
yarn run v1.22.5
$ jest -i tests/test.spec.js
 PASS  tests/test.spec.js
  サンプルテストスイート
    ✓ トップページでアプリ名が表示されていること (344 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.371 s
Ran all test suites matching /tests\/test.spec.js/i.
Done in 19.83s.

パス!
コマンドの後ろにファイルパスを付けてもOKですし、つけない場合は対象のファイルを全部実行します。

テストの設定から動作確認まで、完了です!

結論

本記事では、Nuxt on DockerにおけるJest + PuppeteerのE2Eテスト環境のセットアップをしました。
Dockerコンテナ内でHeadless Chromeを操作できるようにするところがやや引っかかるかなと思いますが、公式のトラブルシューティングに載っていますし、jest-puppeteerの利用についてもJestの公式サイトで言及されているので、ソースをたどればそんなに難しくないかもです。

参考