Playwrightを触ってみて、これはかなり使えるのではないかと思いました。

UIテストの道具として便利なのはもちろんですが、AIにコードを書かせる機会が増えるほど、意図していない場所が壊れていないかを機械的に確認する仕組みが欲しくなります。

特に個人開発では、リリース前に毎回ブラウザを開いて、

  • トップページが開くか
  • フォームを送信できるか
  • 検索やフィルタが動くか
  • 登録、編集、削除の主要な流れが壊れていないか
  • AIに直してもらった場所以外が壊れていないか

といった確認を手でやりがちです。最初は数分でも、画面や機能が増えると抜け漏れが出ます。

Playwrightは、この「毎回ブラウザでやっている確認」をコードにして、同じ条件で繰り返し実行できるE2Eテストの道具です。スクリーンショットや動画も残せるので、テストだけでなく、YouTubeや記事用に動作説明の素材を作る用途にも使えそうです。

この記事では、React + Viteで作った問い合わせフォーム を例に、Playwrightを入れてフォーム操作を自動確認するところまでを書きます。

全体像は、手動確認をテストコードに置き換え、ブラウザで自動実行し、失敗時はレポートやtraceで原因を追う流れです。

Playwrightで手動UI確認を自動化する流れ

Playwrightとは

Playwrightは、ブラウザを自動操作してWebアプリの動きを確認できるE2Eテストフレームワークです。

E2EはEnd to Endの略で、ユーザーが実際に画面を開いて操作する流れに近い形でテストします。たとえば、次のような操作をコードで書けます。

  • ページを開く
  • 入力欄に文字を入れる
  • ボタンを押す
  • 検索結果が表示されることを確認する
  • フォーム送信後のメッセージを確認する

単体テストが関数や部品単位の確認に向いているのに対して、Playwrightは「画面上で主要な操作が最後まで通るか」を確認する用途に向いています。

PlaywrightはChromium、Firefox、WebKitを扱えます。ただし、初めて導入する段階では、いきなり全ブラウザを対象にしなくても大丈夫です。まずはChromiumだけで、リリース前に毎回手で確認している重要な操作を1つ自動化するところから始めると進めやすいです。

触って便利だと感じたところ

まだ深く使い込んでいるわけではありませんが、触ってすぐ便利だと感じたのは次のあたりです。

  • クリックや入力の前に、要素が操作可能になるまで待ってくれる
  • expect を使って画面上の見出し、ボタン、メッセージを確認できる
  • 失敗時のスクリーンショット、動画、trace、HTMLレポートを残せる
  • UI Modeで、ブラウザの動きを見ながらテストを書ける
  • 開発サーバーの起動を webServer でまとめられる
  • Chromium、Firefox、WebKitを同じテストで確認できる

AIにコードを直してもらったあと、「指示した箇所は直ったが、別のフォームが壊れた」ということは普通に起きます。Playwrightで主要フローだけでも自動確認しておけば、その手戻りに気づきやすくなります。

最初はフォーム送信だけでもよい

Playwrightを入れると、つい全画面を自動化したくなります。ただ、最初から広げるとテストを書くこと自体が重くなります。

まずは、今回の問い合わせフォームのように、壊れると困る操作を1つだけ選ぶくらいでよさそうです。

  • ページが開ける
  • フォームへ入力できる
  • 送信後の結果が表示される

これだけでも、リリース前に毎回手で確認していた作業を1つ減らせます。慣れてきたら、検索、登録、編集などに広げれば十分だと思います。

React + ViteフォームにPlaywrightを入れる

今回は、React + Viteで作った小さな問い合わせフォームを例にします。

以降のコマンドは、React + Viteフォームアプリのプロジェクト直下で実行する前提です。

React + ViteフォームをPlaywrightで確認する流れ

まず、Playwright Testを開発依存として追加します。

npm install -D @playwright/test

初回はブラウザも入れます。まずはChromiumだけで十分です。

npx playwright install chromium

新規プロジェクトでひな形ごと作りたい場合は、公式の npm init playwright@latest から始めてもよいです。この記事では、既存のReact + Viteアプリへ手で追加する流れにします。

npm scriptsを追加する

package.json に、E2Eテスト用のscriptsを追加します。

{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "test:e2e": "playwright test",
    "test:e2e:ui": "playwright test --ui",
    "test:e2e:report": "playwright show-report"
  }
}

通常実行は次のコマンドです。

npm run test:e2e

画面を見ながら確認したいときはUI Modeを使います。

npm run test:e2e:ui

HTMLレポートを開くときは次のコマンドです。

npm run test:e2e:report

playwright.config.tsを書く

Viteの開発サーバーをPlaywright側から起動する設定にします。

playwright.config.ts を作成します。

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: 'tests/e2e',
  reporter: 'html',
  use: {
    baseURL: 'http://127.0.0.1:4175',
    screenshot: 'only-on-failure',
    trace: 'on-first-retry',
    video: 'retain-on-failure',
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
  ],
  webServer: {
    command: 'npm run dev -- --host 127.0.0.1 --port 4175',
    url: 'http://127.0.0.1:4175',
    reuseExistingServer: !process.env.CI,
  },
});

ポイントは webServer です。

  • testDir: E2Eテストを置く場所
  • reporter: HTMLレポートを使えるようにする
  • use.baseURL: page.goto('/') のように相対パスで書けるようにする
  • screenshot: 失敗時だけスクリーンショットを残す
  • trace: 失敗調査に使うtraceを残す
  • video: 失敗時の動画を残す
  • projects: 最初はChromiumだけにする
  • webServer: テスト実行前にVite開発サーバーを起動する

videotrace は常に残すと容量が増えやすいので、最初は失敗時やリトライ時だけ残す設定にしておくと扱いやすいです。記事や動画素材用に成功時の動きを録画したい場合だけ、一時的に video: 'on' にするとよいです。

問い合わせフォームのテストを書く

tests/e2e/contact-form.spec.ts を作成します。

最初のテストは、フォームを入力して、送信後の結果表示が出ることだけを確認します。

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

test('問い合わせフォームの入力と送信結果を確認できる', async ({ page }) => {
  await page.goto('/');

  await expect(page.getByRole('heading', { name: '問い合わせフォーム' })).toBeVisible();

  await page.getByLabel('名前').fill('荒井');
  await page.getByLabel('メールアドレス').fill('[email protected]');
  await page.getByLabel('問い合わせ内容').fill('Playwrightでフォームを確認しています。');
  await page.getByRole('button', { name: '送信する' }).click();

  await expect(page.getByRole('heading', { name: '送信内容を受け付けました' })).toBeVisible();
  await expect(page.getByText('[email protected]')).toBeVisible();
});

実際にこのフォームで確認したところ、次の結果になりました。

1 passed (1.8s)

最初はこのくらい短いテストで十分です。Playwrightの実行、失敗、レポート確認まで一度体験してから、検索、登録、編集、削除などに広げると進めやすいです。

バリデーションも見たい場合は、空のまま送信してエラー文を確認します。

test('未入力ならエラーを表示する', async ({ page }) => {
  await page.goto('/');

  await page.getByRole('button', { name: '送信する' }).click();

  await expect(page.getByText('名前を入力してください')).toBeVisible();
  await expect(page.getByText('メールアドレスを入力してください')).toBeVisible();
  await expect(page.getByText('問い合わせ内容を入力してください')).toBeVisible();
});

こういう確認は手でやっても簡単ですが、リリース前に毎回やるなら自動化した方が確実です。

失敗時の調べ方

テストが失敗したら、まずターミナルのエラーメッセージを確認します。

どのテストの何行目で失敗したか、どの要素が見つからなかったか、どの期待値と違ったかが表示されます。

次にHTMLレポートを開きます。

npm run test:e2e:report

HTMLレポートでは、成功、失敗、スキップされたテストを一覧できます。失敗したテストを開くと、エラー内容、添付されたスクリーンショット、動画、traceへの導線を確認できます。

スクリーンショットは、失敗した瞬間の画面を見るのに役立ちます。動画は、失敗直前までの操作の流れを確認するのに向いています。traceはさらに詳しく、各ステップのDOM、アクション、ネットワーク、コンソール情報を追えます。

手元で詳しく追いたいときは、traceを明示的に有効にして実行します。

npm run test:e2e -- --trace on

生成されたtraceは、次のように開けます。

npx playwright show-trace path/to/trace.zip

検証時には、意図的に存在しない文字列を待つテストを作り、失敗時に次のようなファイルが生成されることを確認しました。

test-results/.../test-failed-1.png
test-results/.../video.webm
test-results/.../trace.zip
test-results/.../error-context.md
playwright-report/index.html

これらが残ると、失敗した画面を再現する時間をかなり減らせます。AIに修正を頼むときも、エラー文だけでなく、スクリーンショットやtraceを一緒に見せられると状況を説明しやすくなります。

リリース前チェックに組み込む

Playwrightに慣れてきたら、リリース前チェックに組み込むと便利です。

たとえば次のような流れです。

npm run build
npm run test:e2e

ビルド後に主要なE2Eテストを通すだけでも、リリース直前の確認漏れを減らせます。

さらに進めるなら、GitHub ActionsなどのCI/CDへ組み込む方法もあります。CI/CDの考え方は GitHub CI/CD で VPS へ自動デプロイするまで にまとめています。

ただし、最初からCIまで入れようとすると確認範囲が広くなります。まずはローカルで1本通る状態を作り、そのあとリリース前チェック、CIへ広げる順番が現実的です。

YouTubeや記事素材にも使える

Playwrightはテスト用の道具ですが、ブラウザ操作を再現できるので、記事や動画用の素材作りにも使えます。

フォームに文字を入力して送信する様子を、同じ手順で何度でも再現できます。手で撮影すると、入力ミスや画面の揺れが入りがちですが、Playwrightなら操作が毎回同じになります。

Playwrightレポートでテスト手順と動画を確認している画面

テストの証跡として動画を残すだけでなく、こうしたレポート画面を記事やYouTubeの説明素材として使う、という使い方も個人開発ではかなり相性がよさそうです。

導入時の注意点

Playwrightを入れると何でも自動化したくなりますが、最初から広げすぎると不安定なテストが増えやすくなります。

まずは短く、壊れると困る重要フローに絞るのが大事です。

テストは毎回同じ初期状態から始めるようにします。localStorage を使うアプリなら、テスト開始時に固定データを入れてからページを読み込む方法があります。サーバー側のデータを使う場合は、テスト用データを用意するか、テスト前後の準備と片付けを決めておきます。

外部認証、外部API、実OSのクリップボード、ファイルダウンロードなど、環境差が出やすい部分は最初から無理に対象にしない方が安定します。必要になった段階で、モックや専用のテスト環境を検討します。

AIコーディングエージェントに実装とテスト整備を分けて頼む場合は、作業ディレクトリも分けると安全です。git worktree を使った分け方は git worktreeでAI時代の並列開発を試す。Codexに別ブランチを同時に任せるには にまとめています。

また、完全自動化だけを目指すのではなく、危険なところは人が握り、定型確認だけを機械に任せる考え方も大事です。この考え方は リモートサーバーへ root ログインしてシェルを実行するまでを半自動化する に近いです。

JavaScriptやテストの基礎を補う

Playwrightのテストコードは、JavaScriptまたはTypeScriptで書きます。

DOM操作や非同期処理に不安がある場合は、先にJavaScriptやTypeScriptの基礎を押さえておくと読みやすくなります。

ここは特定の本に絞るより、自分の前提知識に合うものを探す方がよいと思います。

まとめ

Playwrightは、毎回手で確認している重要なUI操作を自動化するための道具です。AIにコード修正を任せる場面が増えるほど、意図しない影響を検知する仕組みとして重要になりそうです。

最初はChromiumだけ、短いテスト1本、主要フロー1つから始めれば十分です。今回なら、React + Viteの問い合わせフォームで、入力して送信結果が表示されることを確認するだけでも入り口になります。

スクリーンショット、動画、trace、HTMLレポートまで確認できると、失敗時に原因を追いやすくなり、導入メリットを実感しやすくなります。

全部を一気に自動化するのではなく、リリース前に毎回触っている操作から順に増やす。これが、Playwrightを無理なく続ける一番現実的な入り方だと思います。

関連記事

参考リンク