ゼスト Tech Blog

ゼストは「護りたい。その想いを護る。」をミッションに、在宅医療・介護業界向けのSaaSを開発しています。

PlaywrightとGitHub ActionsによるE2Eテスト自動化の実践

1. はじめに

現状の課題

これまで、回帰テストはすべて手作業で実施していました。

1回の作業時間は短いものの、継続的な運用において以下のリスクが顕在化していました。

  • 非稼働日の監視空白 休日や体調不良など、PCに触れない期間はテストができません。その間に障害や仕様変更が発生しても気づくことができず、対応が遅れるリスクがありました。

  • 実施漏れのリスク 多忙な業務の合間ではチェックを飛ばしてしまう恐れがありました。

目指すゴール

正常稼働時は監視を意識することなく、エラーが発生した際のみ詳細を確認すればよい環境の構築を目指しました。

2. 技術選定と開発手法:AIとの共存

  • 言語/フレームワーク: TypeScript / Playwright

    • 当初はPlaywright MCPでの自動化を検討していたこと、またPuppeteerの使用経験はあったので、他のツールも試したくPlaywrightを採用しました。
  • ブラウザ: Chromium (Chrome)

    • ヘッドレスモードでの実行を前提としつつ、ローカル環境ではGUIで確認できる柔軟性を重視しました。
  • CI/CD: GitHub Actions

    • 既存の運用で使用しており、新たな環境構築コストがかからないため採用しました。

3. 実装編:ローカル環境とセキュリティ

基本のテストケース設計

まずは、ログイン画面にアクセスし、認証をできるかを確認するテストを実装しました。 ここでは、以下の手順を自動化しています。

  1. ログインページへの遷移

  2. フォームへのID/パスワード入力

  3. ログインボタンのクリック

  4. ダッシュボードへのURL遷移と特定要素の表示確認

これらをPlaywrightのテストコードとして実装し、正常にログインフローが完了することを検証できるようにしました。

【実装例: tests/login.spec.ts】

import { test, expect } from '@playwright/test';

test('正常にログインでき、ダッシュボードが表示されること', async ({ page }) => {
  // 1. ログインページへ移動
  await page.goto('/login');
  
  // 2. 環境変数を使用してフォーム入力
  await page.fill('input[name="email"]', process.env.TEST_USER_ID || '');
  await page.fill('input[name="password"]', process.env.TEST_PASSWORD || '');
  
  // 3. ログイン実行
  await page.click('button[type="submit"]');

  // 4. URL遷移を検証
  await expect(page).toHaveURL(/.*\/dashboard/);
  
  // 5. 視覚的な確認
  await expect(page.locator('.user-avatar')).toBeVisible();
});

セキュリティ対策

テストコードへのIDやパスワードの直接記述(ハードコーディング)は避ける必要があります。

  • ローカル環境: 環境変数ファイル(.env)を使用し、このファイルをGitの管理対象外(.gitignore)に設定することで、機密情報の流出を防止します。

  • GitHub Actions環境: CI環境には.envファイルが存在しないため、GitHubリポジトリのSecrets機能を利用します。認証情報をSecretsに登録し、ワークフロー実行時に環境変数として安全に注入する構成としました。

4. GitHub Actionsでの定期実行と運用の工夫

スケジュール設定(処理と検証の分離)

今回手作業で実施していたテストでは、実行してから実際にデータが反映されるまでには、数十分のタイムラグがあるものがありました。このリードタイムを考慮せずに検証を行うとテストは失敗しますが、反映を待つためにCI上で長時間待機させるのはリソースの無駄です。

そこで、GitHub Actionsのワークフローを2つのジョブに分割し、スケジュール実行の時間をずらす構成を採用しました。具体的には、朝6時にデータ連携処理(Integrate)を実行し、1時間後の朝7時にデータ反映の検証(Verify)を実行します。設定ファイルでは cron 構文でスケジュールを定義し、条件分岐を使って時刻ごとに実行するジョブを切り替えています。

【実装例: .github/workflows/integration-test.yml】

name: External Integration Tests

on:
  schedule:
    # ポイント1:処理と検証の時間をずらしてスケジュール
    - cron: '0 21 * * *' # 日本時間 6:00 (連携処理を実行)
    - cron: '0 22 * * *' # 日本時間 7:00 (結果を検証)

jobs:
  integrate:
    name: データ連携実行
    # ポイント2:6:00の回だけ実行(連携処理を実行)
    if: github.event.schedule == '0 21 * * *'
    runs-on: ubuntu-latest
    steps:
      # ... (セットアップは省略) ...

      - name: Run integrate tests
        # 連携処理用のテストケースのみを実行。テストには { tag: '@integrate' } を付けている想定
        run: yarn workspace @my-project/integration-test test --grep @integrate
        env:
          TEST_USER_ID: ${{ secrets.TEST_USER_ID }}
          TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}

  verify:
    name: 結果確認
    # ポイント2:7:00の回だけ実行(データ反映待ち完了後)
    if: github.event.schedule == '0 22 * * *'
    runs-on: ubuntu-latest
    steps:
      # ... (セットアップは省略) ...

      - name: Run verify tests
        # 検証用のテストケースのみを実行。テストには { tag: '@verify' } を付けている想定
        run: yarn workspace @my-project/integration-test test --grep @verify
        env:
          TEST_USER_ID: ${{ secrets.TEST_USER_ID }}
          TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}

5. まとめ

これまで手作業で実施していたテストを自動化し、抱えていた課題を解決する環境を構築できました。

今後は、Slackへの通知機能の追加や、運用を通じたテスト内容の改善を進めていく予定です。