見出し画像

PlaywrightのHTMLレポートをVercel Previewにデプロイする

こんにちは、ソフトウェアエンジニアの遠藤です。

最近、弊社ではE2Eテストの自動化ツールとしてPlaywrightの導入を決め、開発フローに組み込むための環境整備を進めています。
その過程で、CI上でPlaywrightを実施した際のレポートの取り扱いについて調べたところ、公式 *1 にはHTMLをダウンロードする方法が紹介されていました。

しかし、この方法では確認作業が手間のため、Cloudflare Pages や GitHub Pages にホスティングしている記事が見つかりました。

本記事では新たな選択肢としてVercelを採用した理由と、実際の設定手順についてご紹介します。

Vercelを選択した理由

弊社の開発では、Next.jsアプリケーションをGitHubのPull Requestごとに検証環境を構築できるVercel Previewを利用しており、開発メンバーはVercelアカウントを所有しています。そのため、Vercel Authentication機能は大きな魅力の一つで、Vercelにデプロイされた環境へのアクセスを、Vercelアカウントによる認証で制限することができます。

Vercel Authenticationは一部プランによって制限 *2 はあるものの、Vercel Previewへのアクセス制限は、すべてのプランで設定が可能です。
ちなみに、GitHub Pagesでは通常Publicにサイトが公開されてしまい、Private化するにはGitHub Enterprise Cloudを使用する必要があります。

加えて、VercelはNext.js以外にもさまざまなフレームワークに対応 *3 している他、静的なHTMLをホスティングすることもできます。

手軽にアクセス制限ができ、使い勝手を知っているサービスでもあったことから、Vercelを採用することにしました。

全体の流れ

以下は、CI上でのPlaywirght実行からVercel Previewでレポート結果が確認できるまでの大まかな流れです。なお、CIはGitHub Actionsを使用します。

  1. アプリケーションリポジトリ(以降、app-repo)で、PlaywrightによるE2Eテストを実行

  2. PlaywrightのHTMLレポートを、レポート管理用リポジトリ(以降、report-repo)へcommit & pushし、Pull Requestまで作成

  3. report-repoでPull Request作成によりVercelのデプロイが開始

  4. Vercel Preview環境でPlaywrightのHTMLレポートが閲覧可能となる

report-repoを別途作成した経緯は大きく分けて2つあります。

1つ目に、構成上E2Eテストを実行するたびにPull Requestを作成するため、app-repoで開発中のPull Requestとライフサイクルが異なるものを置くことを避けるためです。

2つ目に、同一リポジトリに複数のVercel Projectを紐づけた場合、Pull Requestごとに不必要なVercel Prview環境の構築が発生するためです。
正確には、Ignored Build Stepの設定や、CLIコマンドによるデプロイ等で回避することも可能だと思いますが、細かい設定をするよりも、リポジトリを分割するメリットのほうが大きいと判断しました。

実装手順

レポート管理用リポジトリの準備

PlaywrightのHTMLレポートをVercelへデプロイするための新しいリポジトリ(report-repo)を作成します。中身は空で問題ありません(必要に応じて README.md など自由に設置してください)。

その後、Vercelのダッシュボードから、先程作成したリポジトリをインポートします。設定は特に変更せず「Deploy」を実行してください。リポジトリ内が空でも、正常にプロジェクトが作成されるはずです。

プロジェクトが作成されたのち、「Settings > Deployment Protection」と移動し、「Vercel Authentication」の設定がPreview環境に対して有効になっていることを確認してください。

GitHub のトークン準備

今回は、app-repoからreport-appへのリポジトリをまたいだ操作を行うため、GitHub Actinos のワークフローで参照できるGITHUB_TOKENでは権限が不足しています。

そのため、マシンユーザー等によるPrivate Access Token(PAT)の発行や、GitHub Appsによるトークンの発行が可能な状態としてください。

以降ではPATを使用して説明します。

GitHub Actions の Workflow

デプロイ先の環境と必要な権限が用意できました。これらの情報を使用して、ActionsのWorkflowを作成します。

以下が全体のソースコードになります。

name: e2e_test

on:
  workflow_dispatch:
  workflow_run:
    workflows:
    - merge_staging_then_deploy_stg
    types:
    - completed

jobs:
  e2e_test:
    timeout-minutes: 60 # 1時間
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: ['18.20.4']
    if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
    steps:
    - name: Checkout
      uses: actions/checkout@v4

    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
        cache: yarn

    - name: Install deps
      run: yarn install --frozen-lockfile --ignore-scripts

    - name: Install Playwright Browsers
      run: yarn playwright install --with-deps

    - name: Set Envs
      run: |
        echo "github_run_url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" >> $GITHUB_ENV
        destination_branch="report-${GITHUB_RUN_ID}"
        echo "destination_branch=${destination_branch}" >> $GITHUB_ENV
        echo "report_url=https://report-repo-git-${destination_branch}-<チーム名>.vercel.app/" >> $GITHUB_ENV

    - name: Run Playwright tests
      continue-on-error: true
      env:
        GH_RUN_URL: ${{ env.github_run_url }}
        E2E_TEST_REPORT_URL: ${{ env.report_url }}
      run: yarn run test:e2e # Playwright の実行

    - name: Push commit to <organization>/report-repo
      shell: bash
      env:
        GH_TOKEN: ${{ secrets.PAT }}
        GH_REPOSITORY: ${{ github.repository }}
        GH_RUN_URL: ${{ env.github_run_url }}
        SOURCE_DIR: playwright-report/.
        DESTINATION_REPO: <organization>/report-repo
        DESTINATION_BRANCH: ${{ env.destination_branch }}
        DESTINATION_DIR: ''
      run: |
        set -euo pipefail

        git config --global user.email "github-actions[bot]@users.noreply.github.com"
        git config --global user.name "github-actions[bot]"

        # レポート管理用リポジトリをClone
        clone_dir=$(mktemp -d)
        git clone "https://x-access-token:${GH_TOKEN}@github.com/${DESTINATION_REPO}.git" "${clone_dir}" && cd $_

        # 同期対象のディレクトリ・ファイルを clone 先のリポジトリ配下に複製
        cp --recursive "${GITHUB_WORKSPACE}/${SOURCE_DIR}" "${clone_dir}/${DESTINATION_DIR}"

        # 変更内容を commit / push
        git switch "${DESTINATION_BRANCH}" 2>/dev/null || git switch --create "${DESTINATION_BRANCH}"
        git add .
        if git status | grep -q "Changes to be committed"
        then
          git commit --message "Run: ${GH_RUN_URL}"
          git push --set-upstream origin HEAD:"${DESTINATION_BRANCH}"
        else
          echo "No changes detected"
          exit 0
        fi

        # Pull Request を作成
        pr_title="E2E Test from ${GH_REPOSITORY}"
        pr_body="Run URL: ${GH_RUN_URL}"
        gh pr create \
          --title "${pr_title}" \
          --body "${pr_body}"
          --repo "${DESTINATION_REPO}" \
          --base main \
          --head "${DESTINATION_BRANCH}" \
          || echo "Pull request already exists or no changes detected"

    - name: Report URL
      run: echo "${{ env.report_url }}"

ポイントに絞って解説していきます。

弊社では、stagingブランチに変更内容をpushすることで、ステージング環境へのデプロイが行われるWorkflowが存在しています(name = merge_staging_then_deploy_stg)。

今回は、E2Eテストが

  • ステージング環境へのデプロイが完了した後に実行されること

    • E2Eテストの対象をステージング環境とするため

  • 手動で実行できること(workflow_dispatch

を実現するために、E2Eテスト用のWorfkowを作成し、前者についてはworkflow_runを設定することで対応します。
なお、workflow_dispatchやworkflow_runはデフォルトブランチ上でのみ実行が可能となっている点にご注意ください。

トリガーについては使いやすいように自由に変更してください。

on:
  workflow_dispatch:
  workflow_run:
    workflows:
    - merge_staging_then_deploy_stg
    types:
    - completed

レポート用のVercel PreivewはE2Eテストを実行するたび = ActionsのRunごとに異なる環境を構築します。以下では、3つの環境変数を動的に生成し、後続の処理で参照できるようにしています。

  • github_run_url:Actionsの実行(Run)URL

  • destination_branch:report-repoでPull Requestを作成するときのブランチ名

  • report_url:Vercel PreviewのURL(ブランチ名が入ります。長すぎると省略されるので注意。ご自身の環境に合わせてURLを変更してください。)

- name: Set Envs
  run: |
    echo "github_run_url=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" >> $GITHUB_ENV
    destination_branch="report-${GITHUB_RUN_ID}"
    echo "destination_branch=${destination_branch}" >> $GITHUB_ENV
    echo "report_url=https://report-repo-git-${destination_branch}-<チーム名>.vercel.app/" >> $GITHUB_ENV

playwright-slack-report を使用して、Playwrightの実行完了時にSlackへ通知する仕組みを設定しています。通知する内容の付加情報として、ActionsのRun URLとVercel PreviewのURLを環境変数によって渡せるようにしています。

- name: Run Playwright tests
  continue-on-error: true
  env:
    GH_RUN_URL: ${{ env.github_run_url }}
    E2E_TEST_REPORT_URL: ${{ env.report_url }}
  run: yarn run test:e2e # Playwright の実行
export default defineConfig({
  ...
  reporter: [
    ['html'],
    [
      '.node_modules/playwright-slack-report/dist/src/SlackReporter.js',
      {
        slackWebHookUrl: '...',
        sendResults: 'always',
        meta: [
          { key: 'GitHub Actions Run URL', value: process.env.GH_RUN_URL },
          { key: 'Report', value: process.env.E2E_TEST_REPORT_URL },
          // other meta data
        ]
      }
    ]
  ]
})

以下は、Playwrightによって出力されたHTMLレポートを、report-repoへcommit&pushし、Pull Requestを作成するShell Scriptです。
記事の構成上1ファイルに記載していますが、適宜別ファイル化などを行ってください。

トークンはPATを使用していますが、GitHub Appsを利用したい場合は、GitHub App Tokenなどを使用してトークンを取得してください。

- name: Push commit to <organization>/report-repo
  shell: bash
  env:
    GH_TOKEN: ${{ secrets.PAT }}
    GH_REPOSITORY: ${{ github.repository }}
    GH_RUN_URL: ${{ env.github_run_url }}
    SOURCE_DIR: playwright-report/.
    DESTINATION_REPO: <organization>/report-repo
    DESTINATION_BRANCH: ${{ env.destination_branch }}
    DESTINATION_DIR: ''
  run: |
    set -euo pipefail

    git config --global user.email "github-actions[bot]@users.noreply.github.com"
    git config --global user.name "github-actions[bot]"

    # レポート管理用リポジトリをClone
    clone_dir=$(mktemp -d)
    git clone "https://x-access-token:${GH_TOKEN}@github.com/${DESTINATION_REPO}.git" "${clone_dir}" && cd $_

    # 同期対象のディレクトリ・ファイルを clone 先のリポジトリ配下に複製
    cp --recursive "${GITHUB_WORKSPACE}/${SOURCE_DIR}" "${clone_dir}/${DESTINATION_DIR}"

    # 変更内容を commit / push
    git switch "${DESTINATION_BRANCH}" 2>/dev/null || git switch --create "${DESTINATION_BRANCH}"
    git add .
    if git status | grep -q "Changes to be committed"
    then
      git commit --message "Run: ${GH_RUN_URL}"
      git push --set-upstream origin HEAD:"${DESTINATION_BRANCH}"
    else
      exit 0
    fi

    # Pull Request を作成
    pr_title="E2E Test from ${GH_REPOSITORY}"
    pr_body="Run URL: ${GH_RUN_URL}"
    gh pr create \
      --title "${pr_title}" \
      --body "${pr_body}"
      --repo "${DESTINATION_REPO}" \
      --base main \
      --head "${DESTINATION_BRANCH}" \
      || echo "Pull request already exists or no changes detected"

以上の設定により、E2Eテストの実行後にPlaywrightのHTMLレポートがVercel Preview環境で確認できるようになりました。

レポートページの削除

レポート結果は一定期間が経過したものは不要と判断しました。そのため、Vercel Previewの自動削除およびPull Requestの自動Closeを設定しておきます。

Vercel Deploymentの自動削除

Deployment Retentionにより、保持期間を設定することができるそうです。
※今日現在では最短の設定値である30日間を過ぎていないため、動作は未確認です

Vercel Projectの「Settings > Security」へ進み、「Deployment Retention Policy」にある「Preview Deployments」を30 days に設定しました。

Pull Requestの自動Close 

Close Stale Issuesを使用してお掃除します。
以下の設定では、Pull Requestの最終更新日から30日間が経過したものを即時に自動CloseするWorkflowを設定し、毎日9時に実行するようにしました。

name: Close inactive prs
on:
  schedule:
  # JST で毎日 9:00 に実行
  - cron: '0 0 * * *'

jobs:
  close-issues:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/stale@v4
      with:
        repo-token: ${{ secrets.GITHUB_TOKEN }}
        # Issue は自動削除の対象外とする
        days-before-issue-stale: -1
        days-before-issue-close: -1
        # PR は 30 日経過で古い PR としてマークし、即時にクローズする
        days-before-pr-stale: 30
        days-before-pr-close: 0

注意点としては、VercelのDeployment Retentionと「30日間」という設定を同じ値にしているものの、Pull Requestの場合はコメントなどのやりとりが発生すると最終更新日が更新されることによって自動Closeの日時がVercelとはズレるため、必ずしも同日になるというわけではありません。

まとめ

PlaywrightのHTMLレポートをVercel Previewにデプロイする方法をご紹介しました。この方法には、以下のようなメリットがあります。

  • Playwrightのテスト結果をURLで簡単に共有できる

  • 認証機能により安全にアクセス制限ができる

  • Vercelは基本機能のみの利用のため、GitHub Actionsの利用料など比較的安価に実現ができる

今後の展望として、レポート環境のPull Requestを活用することで、さらなる改善が期待できます。例えばテストケースのレビューとして扱い、不足しているシナリオの追加や修正などの議論の場として扱うなど、単なるレポート共有の仕組みから、E2Eテスト運用全体を改善するための基盤として発展させることも可能だと考えています。

ぜひ、参考にしてみてください。

参考文献

*1 https://playwright.dev/docs/ci-intro#html-report
*2 https://vercel.com/docs/security/deployment-protection#understanding-deployment-protection-by-environment
*3 https://vercel.com/docs/frameworks/more-frameworks