2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【GitHub Actions】ビジュアルリグレッションテストを実装してみた

Posted at

はじめに

Playwrightを用いてVRTをGitHub Actionsで動く過程を小さく実装したので、メモとして残します。

開発環境

  • VS Code
  • node:v22.9.0
  • npm: v10.8.3
  • playwright:v1.17.134
  • reg-actions

ビジュアルリグレッションテストについて

アプリケーションのユーザーインターフェース(UI)が意図した通りに表示されているかを以下の3つのフェーズを経て見た目のリグレッション(後退)が発生していないかを検証するテスト手法

  • スナップショットの取得
    変更前のUIのスクリーンショットを取得
  • 比較
    コードに変更を加えた後、再度UIのスクリーンショットを取得
  • 差分の確認
    取得した変更後の画像と基準画像を比較し、UIに予期しない変更がないかをチェック

前提条件

  • node/npmインストール済み
  • GitHubアカウントあり
  • VS Code設定済み

実装

VS Code設定

  • 以下に沿って、設定する

  • Getting started - VS Code

  • VS Code の拡張機能タブからVS Code 拡張機能をインストール

スクリーンショット 2024-10-27 18.49.00.png

  • インストールしたら、コマンドパネルを開いてInstall Playwrightと入力する

スクリーンショット 2024-10-27 18.50.57.png

  • okをクリック

スクリーンショット 2024-10-27 18.54.36.png

node環境でindex.htmlを表示する

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TOP</title>
</head>
<body>
    <header>
        <h1>TOP</h1>
    </header>

    <main>
        <div>Top画像</div>
        <img src="images/top2.jpg" alt="TOP画像" width="300" height="200">
    </main>

    <footer>
        <p>フッター</p>
    </footer>
</body>
</html>
server.js
const http = require("node:http");
const fs = require("fs");
const path = require("path");

const hostname = "127.0.0.1";
const port = 3001;

const server = http.createServer((req, res) => {
  // リクエストされたファイルのパスを取得
  let filePath = req.url === '/' ? 'index.html' : `public${req.url}`;

  // ファイルのフルパスを作成
  filePath = path.join(__dirname, filePath);

  // ファイルを読み込む
  fs.readFile(filePath, (err, data) => {
    if (err) {
      res.statusCode = 404;
      res.setHeader("Content-Type", "text/plain");
      res.end("Not Found\n");
    } else {
      // コンテンツタイプを判別
      const extname = path.extname(filePath);
      let contentType = 'text/html';
      if (extname === '.js') {
        contentType = 'text/javascript';
      } else if (extname === '.css') {
        contentType = 'text/css';
      } else if (extname === '.png') {
        contentType = 'images/png';
      } else if (extname === '.jpg') {
        contentType = 'images/jpeg';
      }

      res.statusCode = 200;
      res.setHeader("Content-Type", contentType);
      res.end(data);
    }
  });
});

// サーバーの起動
server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

  • サーバー実行しweb上で確認
node server.js 
  • 表示されている
    スクリーンショット 2024-11-04 18.51.02.png

Playwrightインストール

  • Playwrightをインストール
npm init playwright@latest
  • 自分の環境に合ったものを選択してインストール

・TypeScript または JavaScript を選択します (デフォルトは TypeScript)
・テスト フォルダの名前 (プロジェクトに既にテスト フォルダがある場合は、デフォルトは tests または e2e です)
・GitHub Actionsワークフローを追加してCIで簡単にテストを実行
・Playwright ブラウザをインストールする (デフォルトは true)

スクリーンショット 2024-11-02 17.43.16.png

  • ファイル構成
playwright.config.ts
package.json
package-lock.json
tests/
  example.spec.ts
tests-examples/
  demo-todo-app.spec.ts

スクリーンショット 2024-11-02 17.44.55.png

  • サンプルでテスト実行してみる
npx playwright test

スクリーンショット 2024-11-02 17.45.29.png

  • HTMLテストを実行してみる
npx playwright show-report

スクリーンショット 2024-11-02 17.47.00.png

  • UIでも動作している
npx playwright test --ui

スクリーンショット 2024-11-02 17.48.23.png

  • Chromiumブラウザーでのみテストを実行するには、--projectオプションを使用する見たい。
npx playwright test --project chromium

VS Codeで実行してみる

  • デバッグの場合は、Show trace Viewer オプションに入れておくとわかりやすい。

スクリーンショット 2024-11-03 10.53.26.png

  • 視覚的にわかりやすい。

スクリーンショット 2024-11-03 10.54.56.png

  • 以下から色々触ってみる。Chrome以外はコメントアウト
src/playwright.config.ts

  /* Configure projects for major browsers */
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },

    // {
    //   name: 'firefox',
    //   use: { ...devices['Desktop Firefox'] },
    // },
    //
    // {
    //   name: 'webkit',
    //   use: { ...devices['Desktop Safari'] },
    // },

    /* Test against mobile viewports. */
    // {
    //   name: 'Mobile Chrome',
    //   use: { ...devices['Pixel 5'] },
    // },
    // {
    //   name: 'Mobile Safari',
    //   use: { ...devices['iPhone 12'] },
    // },

    /* Test against branded browsers. */
    // {
    //   name: 'Microsoft Edge',
    //   use: { ...devices['Desktop Edge'], channel: 'msedge' },
    // },
    // {
    //   name: 'Google Chrome',
    //   use: { ...devices['Desktop Chrome'], channel: 'chrome' },
    // },
  ],

  • TOP画面の画像をスクショ撮るテストを追加
src/e2e/top.spec.ts
import { test, expect } from '@playwright/test';

test('top', async ({ page }) => {
    // トップページにアクセスする
    await page.goto('/');
    // スクリーンショットを撮る
    await page.screenshot({ path: `screenshots/top.jpg`, fullPage: true });
});

エラー①

  • npx playwright test実行すると下記のエラーになる

スクリーンショット 2024-11-03 12.29.46.png

  • 公式通り、useにスキップするように設定を追加
  • test-use-options
src/playwright.config.ts
  use: {
    /* Base URL to use in actions like `await page.goto('/')`. */
    baseURL: 'http://127.0.0.1:3001',

    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
    trace: 'on-first-retry',

    // Whether to ignore HTTPS errors during navigation.
    ignoreHTTPSErrors: true,
  },
  • 実行し保存されていることを確認
    スクリーンショット 2024-11-04 18.51.02.png

CI環境で動かしてみる

  • GitHub Actionsでも確認できるように設定をしてみる
  • 以下公式に沿って、設定
.github/workflows/playwright.yml
name: Playwright Tests
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: lts/*
    - name: Install dependencies
      run: npm ci
    - name: Install Playwright Browsers
      run: npx playwright install --with-deps
    - name: Run Playwright tests
      run: npx playwright test
    - uses: actions/upload-artifact@v4
      if: ${{ !cancelled() }}
      with:
        name: playwright-report
        path: playwright-report/
        retention-days: 30
  • GitHub Actions上でブログのローカルサーバーを起動するために以下を設定
playwright.config.ts

  webServer: {
    command: 'npm run start',
    url: 'http://127.0.0.1:3001',
    reuseExistingServer: !process.env.CI,
  },

  • GitHub actionsを修正
.github/workflows/playwright.yml
name: Playwright Tests
on:
  # mainプッシュ時に実行
  push:
    branches: [ main ]
  # mainへプルリク作成時に実行
  pull_request:
    branches: [ main ]
jobs:
  test:
    # タイムアウトを短く設定
    timeout-minutes: 5
    # ジョブを実行する環境は最新のubuntu
    runs-on: ubuntu-latest
    steps:
    # リポジトリのソースコードをチェックアウト
    - uses: actions/checkout@v4
    # nodeのバージョン
    - uses: actions/setup-node@v4
      with:
        node-version: 22.x
    # 依存関係をインストール    
    - name: Install dependencies
      run: npm ci
    # Playwrightが使用するブラウザをインストール
    - name: Install Playwright Browsers
      run: npx playwright install --with-deps
    # test実行  
    - name: Run Playwright tests
      run: npx playwright test
    # テストの結果をアップロード  
    - uses: actions/upload-artifact@v4
      if: ${{ !cancelled() }}
      with:
        name: playwright-report
        path: playwright-report/
        retention-days: 7


reg-actionsを設定

  • PlaywrightのtoMatchSnapshotを使えば、スクリーンショットの差分を確認できるみたいだけど、変更前の画像をリポジトリで管理する必要があるみたいので、今回は管理する必要のないreg-actionsを設定してみる
.github/workflows/playwright.yml
name: Playwright Tests
on:
  # mainへプルリク作成時に実行
  pull_request:
    branches: [ main ]
permissions:
  # リリースを作成するアクションを許可
  contents: write
  # ワークフローの実行をキャンセルするアクションを許可
  actions: write
  # プルリクエストにラベルを追加するアクションを許可
  pull-requests: write 

jobs:
  test:
    # タイムアウトを短く設定
    timeout-minutes: 5
    # ジョブを実行する環境は最新のubuntu
    runs-on: ubuntu-latest
    steps:
    # リポジトリのソースコードをチェックアウト
    - uses: actions/checkout@v4
    # nodeのバージョン
    - uses: actions/setup-node@v4
      with:
        node-version: 22.x
    # 依存関係をインストール    
    - name: Install dependencies
      run: npm ci
    # フォントのキャッシュ
    - name: Cache fonts
      uses: actions/cache@v3
      id: fonts-cache
      with:
        path: ~/.fonts
        key: ${{ runner.OS }}-fonts

    # 日本語フォントのインストール
    - name: Install Japanese font
      if: steps.fonts-cache.outputs.cache-hit != 'true'
      run: sudo apt install fonts-noto-cjk

    # Playwrightが使用するブラウザをインストール
    - name: Install Playwright Browsers
      run: npx playwright install --with-deps
    # test実行  
    - name: Run Playwright tests
      run: npx playwright test
    # テストの結果をアップロード  
    - uses: actions/upload-artifact@v4
      if: ${{ !cancelled() }}
      with:
        name: playwright-report
        path: playwright-report/
        retention-days: 7
    # スクリーンショットを保存
    - uses: reg-viz/reg-actions@v2
      with:
        github-token: "${{ secrets.GITHUB_TOKEN }}"
        image-directory-path: "./screenshots"
  • プルリクするといい感じにできている。すごい。

スクリーンショット 2024-11-03 13.28.16.png

エラー①

  • 画像がないってなってしまい、画像の差分が表示されない。

スクリーンショット 2024-11-03 15.13.32.png

  • スナップショットの保存が上手くいっていないのか?と思いnpx playwright test --update-snapshotsでupdateすることにした。
.github/workflows/playwright.yml
name: Playwright Tests
on:
  # mainへプルリク作成時に実行
  pull_request:
    branches: [ main ]
permissions:
  # リリースを作成するアクションを許可
  contents: write
  # ワークフローの実行をキャンセルするアクションを許可
  actions: write
  # プルリクエストにラベルを追加するアクションを許可
  pull-requests: write 

jobs:
  test:
    # タイムアウトを短く設定
    timeout-minutes: 5
    # ジョブを実行する環境は最新のubuntu
    runs-on: ubuntu-latest
    steps:
    # リポジトリのソースコードをチェックアウト
    - uses: actions/checkout@v4
    # nodeのバージョン
    - uses: actions/setup-node@v4
      with:
        node-version: 22.x
    # 依存関係をインストール    
    - name: Install dependencies
      run: npm ci
    # フォントのキャッシュ
    - name: Cache fonts
      uses: actions/cache@v3
      id: fonts-cache
      with:
        path: ~/.fonts
        key: ${{ runner.OS }}-fonts

    # 日本語フォントのインストール
    - name: Install Japanese font
      if: steps.fonts-cache.outputs.cache-hit != 'true'
      run: sudo apt install fonts-noto-cjk

    # Playwrightが使用するブラウザをインストール
    - name: Install Playwright Browsers
      run: npx playwright install --with-deps
    # test実行  
    - name: Run Playwright tests
      run: npx playwright test --update-snapshots
    # テストの結果をアップロード  
    - uses: actions/upload-artifact@v4
      if: ${{ !cancelled() }}
      with:
        name: playwright-report
        path: playwright-report/
        retention-days: 7

    # スクリーンショットを保存
    - uses: reg-viz/reg-actions@v2
      with:
        github-token: "${{ secrets.GITHUB_TOKEN }}"
        image-directory-path: screenshots/
        artifact-name: 'test'
  • レポートが出るようになりました!PR上でTOPの変更がわかるので便利!
    スクリーンショット 2024-11-03 15.16.05.png

  • レポートが表示が安定しなかったので、ここはdocker使用したりして、画像の差分を安定して表示できるように工夫が必要かと思いました。今回は小さく実装が目的だったので、その目的はクリアかなと。

まとめ

実際のプロジェクトでは、S3へ保存した画像と比べたり、テスト/本番環境の差分を比較してどうUIが変更されたのかなど、応用として色々便利に使えそうと思いました。
今回は、差分があったとしてもreg-actionsのワークフローは失敗しないので、要注意なところだな・・と、Playwrightを使ったことなかったので勉強になりました!

参考

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?