Slide 1

Slide 1 text

Playwright で一番小さく始める VRT と、次のステップの選択肢 Hirotaka Miyagi / @MH4GF 2024/02/21 #VRT4 選 1

Slide 2

Slide 2 text

自己紹介 Hirotaka Miyagi / @MH4GF 最近はフロントエンド多め GraphQL, GitHub Actions, 静的解析が好き ROUTE06, inc. フルリモートワークの会社で北海道から沖縄まで メンバーが在籍しています! 2

Slide 3

Slide 3 text

アジェンダ Playwright が提供する VRT の機能紹介 一番小さく運用を始めるための指針 次のステップの選択肢 3

Slide 4

Slide 4 text

VRT の基本 3 フェーズ 4

Slide 5

Slide 5 text

VRT を始める上で考えなければならないこと 5

Slide 6

Slide 6 text

ちゃんと VRT をやろうとすると大変... 6

Slide 7

Slide 7 text

Playwright で小さく始めよう! 7

Slide 8

Slide 8 text

Playwright とは Microsoft 製の E2E テストツール Cross-Browser ... Chromium, Webkit, Firefox, Mobile Chrome, Mobile Safari などを サポート Auto-wait ... 操作する前に、要素が操作可能になるまで待機してくれる Codegen ... ブラウザでの操作をコードに変換してくれる VSCode 拡張がめっちゃ便利 8

Slide 9

Slide 9 text

Playwright での VRT 撮影・比較・差分確認 の全フェーズを Playwright で行うことができる 撮影時の柔軟なカスタマイズが可能 9

Slide 10

Slide 10 text

撮影フェーズ 以下のように簡単にスクリーンショットを撮ることが可能 import { test, expect } from "@playwright/test"; test("example test", async ({ page }) => { await page.goto("http://localhost:3000"); await page.screenshot(); }); 10

Slide 11

Slide 11 text

撮影フェーズ - 柔軟なカスタマイズ 例えばここでダークモードへの切り替えを追加してみる import { test, expect } from "@playwright/test"; test("example test", async ({ page }) => { await page.goto("http://localhost:3000"); // Testing Library ライクな API で要素を取得して操作 await page.getByRole("button", { name: "Toggle dark mode" }).click(); await page.screenshot(); }); 11

Slide 12

Slide 12 text

比較フェーズ toHaveScreenshot() でスナップショットテストができる import { test, expect } from "@playwright/test"; test("example test", async ({ page }) => { await page.goto("http://localhost:3000"); await expect(page).toHaveScreenshot(); }); pixelmatch というツールを内部的に利用している 12

Slide 13

Slide 13 text

差分確認フェーズ toHaveScreenshot() で失敗した場合、Playwright の Test Result で差分を確認すること ができる 13

Slide 14

Slide 14 text

小さいデモ 14

Slide 15

Slide 15 text

詳しくは Playwright の以下のページに Visual Regression について記載されています https://playwright.dev/docs/test-snapshots 15

Slide 16

Slide 16 text

VRT を小さく始めるための指針 16

Slide 17

Slide 17 text

再掲: VRT を始める上で考えなければならないこと 17

Slide 18

Slide 18 text

VRT を小さく始めるための指針 Q: どのツールを使う?インフラは何を用意すれば良い? A: Playwright と GitHub Actions 以外のツールを使わない Q: 比較元のスクリーンショットはどのように用意する? A: 本番環境と PR 環境の両方を都度撮影する Q: 差分確認のビューワーはどのように用意する? A: GitHub の Artifacts に test-results を保存し、都度ダウンロードする 18

Slide 19

Slide 19 text

実装 詳しいコードは以下の記事に記載しているので、今回は要点だけ紹介します https://zenn.dev/mh4gf/articles/tiny-vrt-with-github-actions 19

Slide 20

Slide 20 text

Playwright のテストファイル // ./src/__test__/vrt.test.ts import type { Page } from "@playwright/test"; import { test, expect } from "@playwright/test"; type TargetPage = Record<"name" | "path", string>; // 撮影したいページのリスト const targetPages: TargetPage[] = [ { name: "home", path: "/", }, ]; for (const targetPage of targetPages) { test(targetPage.name, async ({ page }) => { await page.goto(targetPage.path); // スクリーンショットを撮る。TypeScript で書けるので、必要に応じて前処理を追加できる await expect(page).toHaveScreenshot(); }); } 20

Slide 21

Slide 21 text

package.json 2 つの script を追加 --update-snapshots はスナップショットを更新するためのオプション { "scripts": { "test:vrt:screenshots": "playwright test --update-snapshots", "test:vrt:compare": "playwright test" } } 21

Slide 22

Slide 22 text

GitHub Actions のワークフロー # .github/workflows/vrt.yml # 該当のstep だけ抜粋 # 本番環境に対してスクリーンショットを撮る。このスクリーンショットが比較元となる - run: pnpm test:vrt:screenshots env: BASE_URL: https://example.com/ # デプロイが成功した Preview 環境に対してスクリーンショットを撮り、比較する - run: pnpm test:vrt:compare env: BASE_URL: ${{ github.event.deployment_status.environment_url }} # 失敗時に理由がわかるよう、失敗したスクリーンショットをアップロードする - name: Upload failed screenshots if: failure() uses: actions/upload-artifact@v3 with: name: vrt-failed-screenshots-${{ github.sha }} path: test-results 22

Slide 23

Slide 23 text

運用 Preview 環境へのデプロイ で発火する CI として VRT を動かします 成功時 UI のデグレードはないですね!ということで、PR のレビュープロセスやマージに進みま しょう。 失敗時 UI の差分が発生しているので、以下の項目をチェックします。 UI の変更が意図したものでない: UI のデグレードが検知できましたね!開発に戻り 実装を修正しましょう。 UI の変更が意図したものである: CI は落ちたままですが、そのまま PR のレビュープ ロセスに進みましょう。 23

Slide 24

Slide 24 text

次のステップの選択肢 24

Slide 25

Slide 25 text

現状できていないこと URL ベースの撮影のため、URL 遷移が難しいコンポーネントの撮影は難しい場合が ある 本番環境との比較しかできていない 2 回テストを実行しており時間がかかる 差分確認は test-results のダウンロードとなり、時間と手間がかかる 25

Slide 26

Slide 26 text

解決の選択肢 自前実装 OSS のツールを採用しセルフホスト SaaS の採用 26

Slide 27

Slide 27 text

Story に対してスクリーンショットを撮りたい 自前実装: Story のパスを列挙する ツールの採用: 撮影フェーズを @storybook/test-runner or storycap に切り替える @storybook/test-runner は 各 Story を「レンダリング」と「Play Function の実 行」を行うテストケースに変換・実行してくれる スクリーンショットの機能をデフォルトで提供しているわけではないが、内部的 に Playwright が利用されていて自前処理を差し込めるため、スクリーンショット を撮ることができる 27

Slide 28

Slide 28 text

差分確認をより簡単にしたい 自前実装: スクリーンショットをリポジトリにコミットする ツールの採用: 比較・差分確認フェーズを reg-suit に切り替える(S3 バケットなどの ストレージが必要) SaaS の採用: 比較・差分確認フェーズを lost-pixel に切り替える ( 自分は Playwright + lost-pixel の構成をよくやります) 28

Slide 29

Slide 29 text

VRT 基盤の運用コストをできるだけ下げたい SaaS の採用: 全フェーズを Chromatic, lost-pixel に切り替える 単純な差分確認だけでなく、UI レビューや storybook のホスティングも可能 差分がある際に Pull Request の Checks で fail させるなどの細かい機能も便利 金銭的なコストがかかるのはデメリット ( 大規模プロジェクトになったときのパフォーマンスチューニングがどれだけで きるのかが気になる) 29

Slide 30

Slide 30 text

VRT 時間増加が大変になってきた 撮影フェーズがボトルネックになりがちなので並列実行させると良い GitHub Actions で実行する storycap / reg-suit の高速化 - ROUTE06 Tech Blog 30

Slide 31

Slide 31 text

Thank you for listening!! 31