DEV Community

Cover image for PlaywrightテストでAPIレスポンスを検証する方法
Akira
Akira

Posted on • Originally published at apidog.com

PlaywrightテストでAPIレスポンスを検証する方法

PlaywrightのE2Eテストは「ログインボタンをクリックできる」「ダッシュボードが表示される」「チャートが描画される」ことを確認できます。しかし、APIが200 OKを返していても、レスポンスの数値やスキーマが壊れていれば、UIテストだけでは見逃すことがあります。たとえばチャートが表示されても、集計値が間違っていればプロダクト上はバグです。このギャップを埋めるには、Playwrightのブラウザテストに加えて、APIコントラクト、スキーマ、レスポンスの意味まで検証する必要があります。Apidogのようなツールを併用すると、UIフローとAPIシナリオを同じCIで実行できます。

今すぐApidogを試す

要約

Playwrightのrequestフィクスチャとpage.routeを使うと、E2Eテスト内でAPIレスポンスを検証できます。

ただし、Playwrightだけで大規模なAPI検証を管理するのは難しくなります。実装では次の構成が扱いやすいです。

  • openapi.yamlをAPIコントラクトの唯一の情報源にする
  • PlaywrightではUIフローと薄いAPIスモークチェックを実行する
  • Apidogではスキーマ検証、連鎖APIシナリオ、エラーパスを検証する
  • PlaywrightとApidogで同じフィクスチャとサンプルペイロードを共有する
  • CIで両方のスイートを並列実行する

はじめに

Playwrightはブラウザ自動化に強く、PlaywrightのAPIテストドキュメントにもあるように、request.get()expect(response.status()).toBe(200)でAPIを直接叩けます。

ただし、実運用では次の問題が起きます。

  • ステータスコードだけを見て、レスポンススキーマを検証していない
  • UIテストとAPIテストで別々のフィクスチャを持っている
  • API仕様の変更にテストが追従できない
  • バックエンドが壊れているとフロントエンド開発が止まる
  • エラーパスや連鎖リクエストを十分に検証できない

解決策は、OpenAPI仕様を契約として扱うことです。

openapi.yamlを中心にして、Playwrightのrequest呼び出し、page.routeによるモック、Apidogシナリオを同じ仕様から駆動します。Apidogをローカルで使う場合は、先にApidogをダウンロードしておくと進めやすくなります。

テストツール選定の背景を知りたい場合は、QAエンジニア向けのAPIテストツールも参考になります。

PlaywrightテストとAPIアサーションのギャップ

典型的なPlaywrightテストは、次のような流れになります。

  1. ログインする
  2. ページへ移動する
  3. UI要素が表示されることを確認する
  4. ボタンやフォーム操作が成功することを確認する

これはユーザー視点の検証として有効です。しかし、APIの中身までは十分に保証できません。

見逃しやすい障害は主に3つあります。

1. ペイロード形状の退行

APIは200を返しているが、レスポンスのフィールド名が変わっているケースです。

例:

{
  "total_count": 120
}
Enter fullscreen mode Exit fullscreen mode

が次のように変わる。

{
  "totalCount": 120
}
Enter fullscreen mode Exit fullscreen mode

UI側がフォールバックしてゼロを表示したり、型変換で表面上動いてしまったりすると、Playwrightの画面確認だけでは検出しにくくなります。

2. ビジネスロジックのずれ

たとえば、割引APIが契約上は15%割引を返すべきなのに、実際には10%を返しているケースです。

UIはAPIの値をそのまま表示するため、「画面に割引額が表示されている」ことだけを検証していると、誤った金額でもテストが通ります。

3. エラーパスの不足

PlaywrightのE2Eテストはハッピーパスに偏りがちです。

一方、APIには次のようなエラーパスがあります。

  • レート制限
  • 期限切れトークン
  • 権限不足
  • 部分的失敗
  • 冪等性キーの衝突
  • Webhook署名エラー
  • 外部サービスのタイムアウト

これらは専用のAPIテストシナリオで検証する方が管理しやすくなります。

役割分担は次のようにします。

  • Playwright: UIフロー、ブラウザ操作、ネットワークインターセプション、主要APIの薄いスモークチェック
  • Apidog: スキーマ準拠、連鎖APIワークフロー、コントラクト遵守、エラーパス検証

両方のスイートが同じOpenAPI仕様を参照すれば、API契約の情報源を1つにできます。設計優先の進め方については、設計優先APIワークフローも参考になります。

PlaywrightとApidogでフィクスチャを共有する

まず、リポジトリのルートにOpenAPI仕様を置きます。

.
├── openapi.yaml
├── fixtures/
│   └── order.json
├── tests/
│   ├── fixtures/
│   │   └── api.ts
│   └── orders.spec.ts
└── playwright.config.ts
Enter fullscreen mode Exit fullscreen mode

openapi.yamlを唯一の契約として扱い、PlaywrightとApidogの両方から参照します。

Playwright用のAPIフィクスチャを作る

// tests/fixtures/api.ts
import { test as base, APIRequestContext, expect } from '@playwright/test';
import { readFileSync } from 'fs';
import path from 'path';

type ApiFixtures = {
  apiRequest: APIRequestContext;
  authToken: string;
  sampleOrder: Record<string, unknown>;
};

export const test = base.extend<ApiFixtures>({
  apiRequest: async ({ playwright }, use) => {
    const ctx = await playwright.request.newContext({
      baseURL: process.env.API_BASE_URL ?? 'https://api.staging.example.com',
      extraHTTPHeaders: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
    });

    await use(ctx);
    await ctx.dispose();
  },

  authToken: async ({ apiRequest }, use) => {
    const res = await apiRequest.post('/auth/token', {
      data: {
        email: 'qa@example.com',
        password: process.env.QA_PASSWORD,
      },
    });

    expect(res.status()).toBe(200);

    const body = await res.json();
    await use(body.access_token);
  },

  sampleOrder: async ({}, use) => {
    const raw = readFileSync(
      path.join(__dirname, '..', '..', 'fixtures', 'order.json'),
      'utf8',
    );

    await use(JSON.parse(raw));
  },
});

export { expect };
Enter fullscreen mode Exit fullscreen mode

これで各テストでは、@playwright/testではなく、このフィクスチャファイルからtestexpectをインポートします。

// tests/orders.spec.ts
import { test, expect } from './fixtures/api';

test('POST /orders returns a valid order with 15 percent discount', async ({
  apiRequest,
  authToken,
  sampleOrder,
}) => {
  const res = await apiRequest.post('/orders', {
    headers: {
      Authorization: `Bearer ${authToken}`,
    },
    data: {
      ...sampleOrder,
      coupon: 'SAVE15',
    },
  });

  expect(res.status()).toBe(201);

  const body = await res.json();

  expect(body).toMatchObject({
    id: expect.any(String),
    status: 'pending',
    discount_pct: 15,
    total_cents: expect.any(Number),
  });

  expect(body.total_cents).toBeLessThan(sampleOrder.subtotal_cents);
});
Enter fullscreen mode Exit fullscreen mode

このテストでは、単に201を確認するだけではなく、ビジネス上重要なdiscount_pct: 15も検証しています。

Apidog側で同じ仕様とフィクスチャを使う

Apidogでは次の流れで設定します。

  1. Apidogプロジェクトを開く
  2. openapi.yamlをインポートする
  3. エンドポイント、リクエスト例、パラメータースキーマを生成する
  4. fixtures/order.jsonと同じ内容を環境変数またはデータセットとして登録する
  5. POST /ordersのシナリオを作成する
  6. レスポンスをOrderスキーマに対して検証する

Playwrightでは重要なセマンティックアサーションを行い、ApidogではOpenAPIスキーマに基づく深い検証を実行します。

Postmanからの移行を検討している場合は、セルフホスト型Postman代替も参考になります。

Apidog + Playwrightワークフローのセットアップ

ここでは、実装手順をCIまで含めて整理します。

ステップ1:OpenAPI仕様をリポジトリに置く

openapi.yamlをリポジトリルートに配置します。

openapi.yaml
Enter fullscreen mode Exit fullscreen mode

運用ルールは次のようにします。

  • PRレビュー必須にする
  • 破壊的変更は明示する
  • API実装より先に仕様を更新する
  • PlaywrightとApidogの両方が同じ仕様を使う

既存APIから始める場合は、FastAPIやNestJSなどのOpenAPI出力を使ってドラフトを生成し、手動で整理します。ApidogではHARファイルから仕様を作成する運用も可能です。

ステップ2:Playwrightを構成する

Playwrightを追加します。

npm init playwright@latest
Enter fullscreen mode Exit fullscreen mode

package.jsonにスクリプトを追加します。

{
  "scripts": {
    "test:e2e": "playwright test"
  }
}
Enter fullscreen mode Exit fullscreen mode

playwright.config.tsではステージング環境を向けます。

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

export default defineConfig({
  use: {
    baseURL: process.env.WEB_BASE_URL ?? 'https://staging.example.com',
    trace: 'on-first-retry',
  },
  retries: 2,
});
Enter fullscreen mode Exit fullscreen mode

ステップ3:Apidogでシナリオを作る

Apidogでは、重要なユーザージャーニーごとにシナリオを作ります。

例:

  • サインアップ
  • ログイン
  • チェックアウト
  • 注文作成
  • 返金
  • Webhook配信
  • トークン期限切れ
  • レート制限

各シナリオでは、API呼び出しを連鎖させ、レスポンスの値を次のステップに渡します。

Apidog CLIで実行できるように、シナリオをJSONとして管理します。

apidog-cli run ./apidog/scenarios/checkout.json
Enter fullscreen mode Exit fullscreen mode

ステップ4:PlaywrightでAPIをスタブする

バックエンドに依存せずUIを確認したい場合は、page.routeを使います。

test('dashboard renders cached order list when offline', async ({
  page,
  sampleOrder,
}) => {
  await page.route('**/api/orders', async (route) => {
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify({
        orders: [sampleOrder],
      }),
    });
  });

  await page.goto('/dashboard');

  await expect(page.getByTestId('order-row')).toHaveCount(1);
});
Enter fullscreen mode Exit fullscreen mode

ポイントは、スタブ用のレスポンスもfixtures/order.jsonから作ることです。

これにより、PlaywrightのUIテストとApidogのAPIシナリオで同じデータを使えます。

ステップ5:CIで両方のスイートを実行する

GitHub Actionsでは、PlaywrightとApidogを別ジョブで並列実行します。

name: tests

on: [push, pull_request]

jobs:
  playwright:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci

      - run: npx playwright install --with-deps

      - run: npx playwright test

  apidog:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm i -g apidog-cli

      - run: apidog-cli run ./apidog/scenarios/checkout.json --reporters cli,junit
Enter fullscreen mode Exit fullscreen mode

どちらかが失敗したらマージを止めます。

--reporters junitを使うと、CI上で失敗したアサーションを確認しやすくなります。GitHub Actionsのドキュメントには、マトリックスビルドやキャッシュの設定も載っています。

専任QAがいないチームでは、QAエンジニア向けのAPIテストツールのように、責務をUIとAPIで分けると運用しやすくなります。

ステップ6:仕様ドリフトを検出する

API仕様が実装とずれると、テストが通っていても本番で壊れる可能性があります。

次のようなチェックを追加します。

  • 最新のopenapi.yamlをCIで検証する
  • 前回リリースとの差分を確認する
  • フィールド削除や型変更を破壊的変更として扱う
  • 破壊的変更があればビルドを失敗させる

これにより、「200 OKだがペイロードが間違っている」タイプのバグを早期に捕捉できます。

高度なテクニックと実装上のヒント

Playwright Trace Viewerを有効にする

playwright.config.tsで次を設定します。

export default defineConfig({
  use: {
    trace: 'on-first-retry',
  },
});
Enter fullscreen mode Exit fullscreen mode

不安定なテストが失敗したときに、次を確認できます。

  • ネットワーク呼び出し
  • DOMスナップショット
  • コンソールログ
  • ユーザー操作のタイムライン

API側では、Apidog CLIのHTMLレポートと組み合わせると、UIが壊れたのかAPIが壊れたのかを切り分けやすくなります。

Apidogモックサーバーを使う

バックエンドが未完成、デプロイ中、またはステージングDBが不安定な場合は、Apidogのモックサーバーを使います。

実装例:

  1. OpenAPI仕様をApidogにインポートする
  2. モックサーバーを起動する
  3. PlaywrightのAPI_BASE_URLをモックサーバーに向ける
  4. UIテストはモックに対して実行する
  5. Apidogシナリオは実バックエンドに対して実行する

モックを使ったテスト生成については、AI支援APIテスト生成も参考になります。

リトライを増やしすぎない

Playwrightでは次の程度に抑えます。

export default defineConfig({
  retries: 2,
});
Enter fullscreen mode Exit fullscreen mode

3回以上リトライしないと通らないテストは、テストまたは環境に問題があります。

Apidogシナリオでも、リクエスト単位のリトライは最小限にします。

スキーマ不一致は失敗として扱う

スキーマの不一致を警告で済ませると、API契約の価値が下がります。

どうしても一時的に許容する場合は、環境変数で明示します。

ALLOW_SCHEMA_DRIFT=true
Enter fullscreen mode Exit fullscreen mode

ただし、その理由をPR上で説明する運用にします。

テストを優先度で分ける

全テストを毎回実行するとCIが遅くなります。

おすすめは次の分け方です。

  • @smoke: すべてのpushで実行
  • @regression: mainブランチへのPRで実行
  • @nightly: 夜間に全件実行

Playwrightではタグやgrepを使えます。

npx playwright test --grep @smoke
Enter fullscreen mode Exit fullscreen mode

状態を共有するフローは、必要に応じて直列実行にします。

test.describe.configure({ mode: 'serial' });
Enter fullscreen mode Exit fullscreen mode

避けるべきミス

  • status === 200だけを検証する
  • ベアラートークンをフィクスチャにハードコードする
  • PlaywrightとApidogで別々のサンプルJSONを持つ
  • Apidog CLIをCIから外す
  • page.routeのスタブを本物のAPIテストの代替にする
  • OpenAPI仕様を更新せずに実装だけ変える

AI関連APIを検証する場合は、非決定的なレスポンスも考慮する必要があります。AIエージェントAPIのテスト方法が参考になります。

代替ツールと比較

ブラウザテストとAPIテストを組み合わせる方法はいくつかあります。

スタック 強み 弱み 最適な用途
Playwright単体(requestフィクスチャ) 単一ツール、高速、Playwrightに統合しやすい スキーマ検証が浅い、連鎖シナリオが弱い、エラーパスを網羅しにくい 小規模チーム、シンプルなAPI
Playwright + Postman Postmanエコシステム、Newman CLI OpenAPIとコレクションが乖離しやすい、情報源が分かれやすい すでにPostmanを深く使っているチーム
Playwright + Apidog OpenAPIを単一ソースにできる、スキーマ検証、モック、CI用CLI、設計優先ワークフロー PlaywrightとApidogの両方を覚える必要がある 仕様駆動でAPIとUIの両方を検証したいチーム
Cypress + cy-apiプラグイン Cypressユーザーには導入しやすい APIテストの表現力が限定される場合がある 既存Cypressコードベース
Pact サービス間契約に強い 学習コストが高い、ブローカーが必要、UIテストではない 多数の内部APIコンシューマーを持つマイクロサービス組織

SOAPや古いAPIテスト基盤から移行する場合は、SoapUI Groovyスクリプトの代替ReadyAPIの代替も参考になります。

ローカル中心の開発フローでは、RESTクライアントVSCode拡張機能も選択肢になります。

実世界のユースケース

Eコマースのチェックアウト

小売チームでは、Playwrightでカートから注文完了までのUIフローを検証します。

一方、Apidogでは次のAPIチェーンを検証します。

  • 支払い意図の作成
  • 不正チェック
  • 在庫減算
  • 注文作成
  • 決済失敗時のロールバック

支払いゲートウェイがレスポンスフィールドをerror_codeからerrorCodeに変えた場合、スキーマ検証で早期に検出できます。

チャートデータを含むSaaSダッシュボード

B2B分析サービスでは、Playwrightでダッシュボードの描画を確認します。

Apidogでは、集計APIが次を正しく返すか検証します。

  • 合計値
  • パーセンタイル
  • 時間バケット
  • フィルター条件
  • 外れ値処理

チャートが見た目上は正常でも、APIの集計ロジックが間違っていれば、API層で検出できます。

Webhook駆動型ワークフロー

フィンテック系のチームでは、Playwrightでユーザーポータルを検証し、ApidogでWebhookを検証します。

検証対象は次のようなものです。

  • Webhook署名
  • リトライロジック
  • 重複Webhook IDの拒否
  • 冪等性
  • 最終的整合性の時間制限

結論

Playwrightはブラウザフローの検証に優れています。しかし、深いAPIテストをすべてPlaywrightだけで管理するのは効率的ではありません。

PlaywrightとApidogを組み合わせると、次の構成を作れます。

  • OpenAPI仕様を1つの契約として共有する
  • PlaywrightでUIフローと薄いAPIチェックを行う
  • Apidogでスキーマ、連鎖シナリオ、エラーパスを検証する
  • 同じフィクスチャを両方のスイートで使う
  • モックサーバーでフロントエンド開発を止めない
  • CIでUI退行とAPI退行の両方を検出する

最初は、チェックアウトやサインアップのような重要フローを1つ選んでください。

  1. openapi.yamlを用意する
  2. PlaywrightのAPIフィクスチャを作る
  3. 対応するApidogシナリオを作る
  4. 同じフィクスチャJSONを共有する
  5. CIで両方を実行する

この小さな構成から始めれば、UIテストだけでは見逃すAPIバグを段階的に減らせます。

FAQ

ApidogなしでPlaywrightテストだけでAPIを検証できますか?

はい。Playwrightのrequestフィクスチャとexpectを使えば、ステータスコードや一部のボディフィールドは検証できます。

ただし、スキーマ検証、連鎖シナリオ、モック、エラーパスの網羅性を考えると、Apidogのような専用ツールを併用する方が管理しやすくなります。比較はQAエンジニア向けAPIテストツールも参考になります。

このセットアップにはOpenAPI仕様が必要ですか?

最大の効果を得るには必要です。

OpenAPI仕様がない場合でもPlaywrightとApidogを並行実行できますが、共通の情報源がなくなり、サンプルペイロードを複数箇所で管理することになります。

認証はどう扱えばよいですか?

テスト実行時に認証APIから新しいトークンを取得します。

Playwrightではフィクスチャに保存し、Apidogでは環境変数に保存します。固定トークンをハードコードすると、期限切れや権限変更で不安定になります。

ApidogはPlaywrightを置き換えられますか?

いいえ。

ApidogはAPIワークフローの検証に向いていますが、ブラウザをレンダリングしません。表示テキスト、レイアウト、クリックフロー、アクセシビリティなどのUI検証にはPlaywrightが必要です。

ステージング環境が安定していない場合はどうすればよいですか?

Apidogのモックサーバーを使います。

OpenAPI仕様からモックを起動し、Playwrightの接続先をモックサーバーに向けます。ステージングが復旧したら、Apidogシナリオを実バックエンドに対して実行します。

CIを高速に保つにはどうすればよいですか?

テストを優先度で分けます。

  • push時: @smoke
  • mainへのPR: 回帰テスト
  • 夜間: 全Apidogシナリオ

Playwrightはworkersで並列化し、ApidogシナリオもCLIの並列実行を使います。

CIで有料のApidogプランが必要ですか?

利用条件はプランによって変わる可能性があります。導入前に現在の料金ページを確認してください。小規模チームでは無料枠で検証を始められる場合があります。

Top comments (0)