はじめに
「食べログ ラーメン TOKYO 百名店」の全店舗訪問を目指してラーメン巡りを続けているフロントエンドエンジニアの kenshin です。
フロントエンド開発者の皆さん、新機能を追加したり、ライブラリをアップデートした後に UI が予期せず変更されてしまった経験はありませんか?このような問題を素早く検知し、未然に防ぐ方法として、ビジュアルリグレッションテスト(以下、VRT)があります。 この記事では、Nx と Playwright を用いて VRT を効率的に行う方法をご紹介します!
なぜ VRT が必要なのか?
フロントエンド開発では、新機能の追加やライブラリのアップデートにより、予期せぬ UI 変更が発生することがあります。 これらの変更を見逃してしまうと、最悪のケースでは本番環境に公開されてしまい、ユーザーエクスペリエンスの低下につながる可能性があります。 しかし手動でのチェックやコードレビューでは、時間とコストがかかる上、細かな変更を見逃すリスクが伴います。 そこで VRT を導入することで、UI の変更を自動的に検知し、問題を未然に防ぐことが可能になります。
VRTとは?
VRT は、コードの変更によってアプリケーションのUIに影響が出ていないかを視覚的に評価する手法です。このテストを実施することで、UI の崩れを早期に発見し、ユーザーエクスペリエンスの低下を防ぐことができます。
Playwright には VRT を実施するための API が標準装備されており、実際のブラウザで UI を視覚的に比較することが可能です。
Playwright を使用した VRT を実際に見てみましょう。
ここでは、ユーザー登録フォームの UI コンポーネントを例に取ります。このコンポーネントには、「SIGN UP」というボタンが含まれています。
まず、ボタンが存在する状態でコンポーネントのスクリーンショットを撮影します。
次に、「SIGN UP」ボタンをコンポーネントから削除し、再度スクリーンショットを撮影します。
この 2 つのコンポーネントを Playwright の toHaveScreenshot を使って比較します。
以下のコードは、Playwright を使用してコンポーネントのスクリーンショットを撮影し、前回のスクリーンショットと比較する方法を示しています。
import { test, expect } from '@playwright/experimental-ct-react' import SignUp from './SignUp' test('example test', async ({ page, mount }) => { await mount(<SignUp />) // コンポーネントをマウントします await expect(page).toHaveScreenshot() // 前回撮影したスクリーンショットの結果と比較します })
Playwright はこの 2 つのスクリーンショットを比較し、ボタンが削除されたことを赤色で示す差分画像を生成します。この差分画像により、テストは「SIGN UP」ボタンの削除を検知して失敗します。
この例では、「SIGN UP」ボタンを削除することで変更を示しましたが、Playwright の VRT は、より微細な変更も検知できます。たとえば、数ピクセルレベルのズレや、色の微妙な変更など、目に見えにくい変更も捉えることが可能です。
ただし、Playwright の VRT を導入する際には、以下のような課題がありました。
- テストの実行時間が長い。
- Jest のスナップショットテストと比較すると、実行時間が長くなる。
- 実行コストが高い。
- 弊社では、撮影したスクリーンショットを argos CI という、スクリーンショットの差分比較を行うサービスにアップロードしている。差分比較を行うサービスの多くは、アップロード枚数に対して従量課金されるため、スクリーンショットの撮影枚数に比例して、コストが膨らむ。
- また、CI の実行時間が長いことも相まって、コストが高くなる。
しかし、Nx の差分実行機能を活用し、変更があるテストのみテストを実行させることで、これらの問題を解決しました。
Nx と Playwright で賢く VRT を実施する
どう賢く実施したか
- Nx の差分実行機能を活用する。
- プロジェクト内のコードの依存関係を分析し、変更の影響を受ける部分だけをテストし、変更のない部分のテストをスキップする。
- 影響のない箇所に対してテストが実行されないので、撮影枚数と撮影時間を減らすことができる。
簡単に Nx の差分実行について説明します。 リポジトリが以下の依存関係で構成されているとき、特定のプロジェクトに変更を加えた状態で Nx の affected コマンドを使うと、それに依存しているプロジェクト(黄色)のみ変更が入ったものと計算してテストを実行し、それ以外のプロジェクト(白色)は影響がないものとしてテストをスキップすることができます。
実際の流れは以下の通りです。
- Pull Request の作成: 新しい機能や修正をコードに加えた後、Pull Request を作成する。
- スクリーンショットの撮影: CI の中で、Nx の affected コマンドを使用して、変更があったプロジェクトのみを特定し、それらに対してスクリーンショット撮影を実行する。
- スクリーンショットのアップロード: 撮影されたスクリーンショットを、argos CI にアップロードする。argos CI は、これらのスクリーンショットをデフォルトブランチの結果と比較し、視覚的な差分を検出する。
- 差分のレビュー: argos CI は、検出された差分を Pull Request にコメントとして追加し、どの部分に変更が発生したかを簡単に確認できるようにする。差分が発生した場合、ブランチ保護ルールにより、変更が argos CI 上で承認されるまでマージがブロックされる。
VRT のレビュープロセスを Pull Request に組み込むことで、品質を維持しながら迅速に開発を進めることができます。
結果
Nx の差分実行機能と Playwright を組み合わせることで、以下のメリットがありました。
- Nx の差分実行によって変更されたプロジェクトだけをテストすればよいため、テスト実行時間と撮影枚数が大幅に削減された。
- 変更による UI のデグレードに早い段階で気づけるようになった。
- 実際のブラウザを使ってテストし、成果物がスクリーンショットなので、jest のスナップショットテストと比較してコードレビューが非常に楽になった。
まとめ
フロントエンド開発において、Nx と Playwright を使った賢い VRT は、UI のリグレッションを早期に検知し、素早く対応できるようになります。 皆さんも、ぜひ Nx と Playwright を使った賢い VRT を試してみてはいかがでしょうか。