この記事は何か
e2eでよくある、代表的な「待つ」のうち
- サービスが実行できるのを「待つ」
- サイトのテスト部分が現れるのを「待つ」
1番目の、サービスが実行できるのを「待つ」をdocker-compose.yml
を使って管理する方法について書いていきます。
対象
- e2eテスト前に、何かしらサービスが実行できるまで「wait-on」などで、「待つ」処理を挟んでいる人
やること
-
docker-compose
でe2eテストを実行 -
docker-compose.yml
の「depends_on」で立ち上がる順番を管理 - テスト実行するコンテナは別で立ち上げる
- テスト実行するコンテナが終わり次第、すべてのコンテナを終了させる(--abort-on-container-exit)
取り扱わない事
- e2eテストフレームワークの詳細や実行内容
メリット
- wait-onや自作shellで、dockerのサービスが「port開く待ち」の記述しなくてOK
- 今ある
docker-compose.yml
を大きく変えなくてOK - テスト終わったら、テスト実行が終わったことを判定したり、テスト後の「終了」を記述するのも書かなくてOK
サンプル docker-compose.yml
よくある、dbとwebの構成です。
今回、web
はnext.js
で、テストフレームワークはplaywright
使っています
services:
db:
image: postgres:17
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: mydatabase
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d mydatabase"]
interval: 2s
timeout: 3s
retries: 5
networks:
- mynetwork
web:
build:
context: .
target: deps
ports:
- "3000:3000"
volumes:
- .:/usr/src/app
depends_on:
db:
condition: service_healthy
command: npx next dev
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
interval: 2s
timeout: 3s
retries: 10
networks:
- mynetwork
volumes:
pgdata:
サービス実行コマンド
docker-compose up
を実行すると、db
がヘルスチェック通り次第、web
が立ち上がります。
healthチェックをserviceごとに書いておくと、順番が守られて立ち上がるようになります。
参考:https://docs.docker.com/compose/how-tos/startup-order/
テスト実行コンテナを用意
services:
db:
image: postgres:17
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: mydatabase
ports:
- '5432:5432'
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U user']
interval: 2s
timeout: 3s
retries: 5
networks:
- mynetwork
web:
build:
context: .
target: deps
ports:
- '3000:3000'
volumes:
- .:/usr/src/app
depends_on:
db:
condition: service_healthy
command: npm run dev
healthcheck:
test: ['CMD-SHELL', 'curl -f http://localhost:3000 || exit 1']
interval: 2s
timeout: 3s
retries: 5
networks:
- mynetwork
+ e2e:
+ profiles:
+ - e2e-group
+ build:
+ context: .
+ target: test
+ volumes:
+ - .:/usr/src/app
+ depends_on:
+ web:
+ condition: service_healthy
+ environment:
+ - CI=true
+ command: npm run e2e
+ networks:
+ - mynetwork
volumes:
pgdata:
networks:
mynetwork:
FROM node:22 AS deps
# Set the working directory
WORKDIR /usr/src/app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm install
# HEALTHCHECK --start-period=5s CMD curl -fs localhost:3000/health || exit 1
+ FROM node:22 AS test
# Set the working directory
+ WORKDIR /usr/src/app
# Copy the node_modules from the deps stage
+ RUN npx playwright install --with-deps
# Copy the rest of the application code
+ COPY --from=deps /usr/src/app/node_modules ./node_modules
# Copy the rest of the application code
+ COPY . .
ポイント
-
docker-compose.yml
でbuildのターゲット追加のほうが、既存のイメージなどに影響を与えず追加するだけでよくなるのでおすすめです -
docker-compose.yml
でprofiles
を追加することで、既存のコマンドを変えなくて済みます
テスト実行コマンド
docker-compose.yml
にprofilesを追加したので、e2eをテストで実行するとき、下記コマンドになります。
docker compose --profile test-group up --abort-on-container-exit --exit-code-from e2e
--exit-code-from service
をe2e
に指定することで、そのサービスの終了コード(exit code)をメインプロセスの終了コードとして反映させるために使用されます。
このオプションを使用すると、テストの成功・失敗結果や、コンテナ内で実行した処理の終了コードを取得できます。
profilesの指定がないservice + profilesで指定したグループが立ち上がるようになりました。
動作の流れ
docker compose --profile test-group up --abort-on-container-exit --exit-code-from e2e
db → web → e2e の順番で立ち上がる
e2eコンテナのテストが終わり次第、e2e、web、dbのコンテナが終了
Github Actions
終了時のシグナルも流れてくるので(成功 → 0、異常 → 1)、Github Actionsでも条件わけして通知もできます
name: Test
on:
push:
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Test
run: docker compose --profile test-group up --abort-on-container-exit --exit-code-from e2e
- name: Notify Slack
if: always() # ステータスに関わらず送信
# if: success() # 成功したとき送信
# if: failure() # 失敗したとき送信
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
fields: message,eventName,ref,workflow,job,took
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}