hacomono TECH BLOG

フィットネスクラブ・スクールなど施設・店舗のための会員管理・予約・決済システム「hacomono」 開発チームの技術ブログ

Nuxt3 モックサーバモードで Playwright を使った Visual Regression Test

どうも、フロントエンドの開発基盤を担当している、みゅーとん(@_mew_ton)です

前回 (Nuxt3 でモックサーバ作ってみる) では Nuxt3 でモックサーバモードの実装について紹介しました。
今回は、これを使って E2E テストを実装する体制を整えたので、紹介します!

ビジュアルリグレッションテストとは?

ざっくりいうと、変更前と後での見た目を画像差分で比較し、変化がないかどうかをテストする方法です。
スナップショットテストなどと表記される場合もありますが、スナップショットテストでは DOM 構造を文字列としてスナップショットするケースが有り、厳密には一致しません。

ページのビジュアルリグレッションテストには、 Playwright や reg-suit などの専用のライブラリがあり、弊社では主に Playwright を使用しています。

Playwright

Playwright とは?

Playwright とは、 Cromium, Firefox などの WEB ブラウザを使ってテストができる Nodeライブラリです。
github.com

Microsoft が作成した E2E テスト用のライブラリです。
似たようなものに Puppeteer がありますが、こちらはスクレイピングや WEBの操作の自動化が主で、テストには jest などのテスト用ライブラリを別途導入する必要があるようです。

インストール方法

以下のコマンドを実行してインストールします (弊社では yarn を使用していますが、 npm, yarn のどちらを使うかは適宜プロジェクトに合わせて読み替えてください)

yarn create playwright

※ playwright は導入時に初期化処理などが必要です. 初期化については公式のドキュメントを参照してください. playwright.dev
次に、テストを導入したいプロジェクトのルートに playwright.config.ts を作成し、内容を以下のようにします.

import { PlaywrightTestConfig, devices } from '@playwright/test'

const config: PlaywrightTestConfig = {
  snapshotDir: './test/e2e/snapshots',
  testDir: './test/e2e',
  webServer: {
    command: 'PORT=4000 node ./.output/server/index.mjs',
    port: 4000,
  },
  projects: [
    {
      name: 'ipad pro 11',
      use: devices['iPad Pro 11 landscape']
    },
    {
      name: 'ipad mini',
      use: devices['iPad Mini landscape']
    }
  ]
}

export default config

各種設定値について解説します

snapshotDir

ビジュアルリグレッションテストをする際に教師となるスナップショットの置き場所を設定します

testDir

テストコードの置き場です

webServer

playwright では、起動時にサーバサイドの起動方法をここでコマンドとして設定することが出来ます。
今回は、nuxt3 を使用しているので、その起動コマンド (PORT=4000 node ./.output/server/index.mjs ) を設定します。

projects

テスト実行環境を定義します。ここで実行環境となるブラウザの指定などができます。
今回は iPad pro, iPad mini で safari を開いた時をテスト対象とするため、 @playwright/test からインポートした devices の 'iPad Pro 11 landscape' 'iPad Mini landscape' を使用します。
これの他に、プリセットで 'Desktop Chrome' 'Galaxy Tab S4' などもあります。

テストの実装方法

例えば、今回はログイン画面を表示する際のテストを実装してみます
tests/e2e/pages/login.spec.ts を作成し、以下のコードを記述します

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

test.describe('/login', () => {
  test('[SSR] 画面表示', async ({ page }) => {
    await page.goto('./login')
    await page.waitForLoadState('domcontentloaded')
    await expect(page).toHaveScreenshot()
  })
})

test.afterEach(async ({ page }) => {
  await page.close()
})

実装する内容はシンプルで、

  1. ログインページに遷移する
  2. 描画完了まで待つ
  3. スナップショットテストを実行する
  4. ページを閉じる

この4ステップのみを実装しています。

テストの実行

前回(Nuxt3 でモックサーバ作ってみる)の記事では、 TEST=true yarn run nuxt dev でモックサーバモードで Nuxt サーバが立ち上がる実装をしています。
そのため、Playwright を使ってテストする際は、以下のようにコマンドを実行しま す

TEST=true yarn run nuxt build
yarn run playwright test

しかし、このままでは比較対象となるスナップショットが存在しないためエラーとなります。
スナップショットを作成するには、以下のコマンドを実行します

yarn run playwright test --update-snapshots

スナップショットをどう管理するか

前述するコマンドで作成されたスナップショットは、GitHubで管理し、GitHub Actions でテストを実行する再に参照します。
それほど大きい画像ではないため、Git LFS を利用する必要はなさそうかなと思います。

運用しているテスト実装のルール

このE2Eテストを導入しているプロジェクトでは、以下のルールに従ってE2Eテストを実装しています

  1. (最優先) すべてのページについて、描画直後の状態をビジュアルリグレッションテストする
  2. (必要に応じて) さまざまな条件で異なる描画結果について、ビジュアルリグレッションテストする
  3. (優先度低) 条件や操作結果に応じた画面の状態を expect する

描画直後の状態をスナップショットテストするだけで、細かいコンポーネントやスタイルの変更を検知し、影響のあったページの大部分を検知することができます。
「ページを開いて描画を待つだけ」をテストするため、テスト導入における工数の増加はそれほど高くない認識でいます。

条件別の描画のテストについては、できれば / 時間がアレばやる というゆるいルールにしていますが、ゆくゆくは優先度を上げていきたい部分でもあります。
逆に、条件や操作に応じての画面の状態 (ラベルやボタンの状態など) を個別にテストするのは、ビジュアルリグレッションテスト側がほぼやってくれているため、ほぼ無意味と捉えています。

まとめ

Nuxt3 モックサーバモードを使用して、 Playwright で E2E テストをする方法を紹介しました。
また、現在運用しているテスト実装におけるルールを紹介しました。

また別の機会に、今度はGitHub Actions で実施する方法について触れていきたいと思います。


hacomonoエンジニア採用ウィッシュリスト
エンジニア求人一覧