Skip to content

建立 2026-09-15 更新 2026-09-15

API 測試與請求攔截

Playwright 不只能操作瀏覽器畫面,內建的 APIRequestContext 也能直接發送 HTTP 請求,適合測試後端 API,或在 UI 測試中攔截、模擬網路請求,兩者是完全不同但互補的用法。

純 API 測試

不需要開啟瀏覽器,直接對 API 發送請求並驗證回應,執行速度比操作畫面快很多:

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

test('建立訂單 API 應回傳 201', async ({ request }) => {
  const response = await request.post('/api/orders', {
    data: { productId: 'sku-001', quantity: 2 },
  });

  expect(response.status()).toBe(201);
  const body = await response.json();
  expect(body).toMatchObject({ productId: 'sku-001', quantity: 2 });
});

request 是內建 Fixture,等同於一個 API Client;也可以在 playwright.config.tsuse.baseURL 設定共用的 API 網域,讓 API 測試與 UI 測試共用同一份設定。

結合 UI 測試:用 API 準備測試資料

實務上很常見的模式,是用 API 快速建立測試需要的前置資料,再切換到畫面驗證,避免每個測試都要重複走完整的 UI 操作流程:

test('已存在訂單可以在畫面上查到', async ({ page, request }) => {
  const created = await request.post('/api/orders', {
    data: { productId: 'sku-001', quantity: 1 },
  });
  const { id } = await created.json();

  await page.goto(`/orders/${id}`);
  await expect(page.getByText('sku-001')).toBeVisible();
});

攔截與模擬前端網路請求

page.route() 可以攔截頁面發出的網路請求,用來模擬後端還沒開發完成的 API、測試錯誤情境,或加速測試(略過真正的網路延遲):

test('API 回傳錯誤時應顯示錯誤訊息', async ({ page }) => {
  await page.route('**/api/orders', (route) =>
    route.fulfill({
      status: 500,
      contentType: 'application/json',
      body: JSON.stringify({ message: '伺服器忙碌中' }),
    })
  );

  await page.goto('/checkout');
  await page.getByRole('button', { name: '送出訂單' }).click();
  await expect(page.getByText('伺服器忙碌中')).toBeVisible();
});

route.fulfill() 直接回傳自訂內容,不會真正打到後端;也可以用 route.continue() 讓請求正常送出,但修改 Header 或參數,或用 route.abort() 模擬網路中斷、離線情境。這種手法讓「後端錯誤」「網路異常」這類原本難以穩定重現的情境,變得容易寫成測試。

API 測試 vs. UI 測試

面向 API 測試 UI 測試
執行速度 快,不需渲染畫面 較慢,需要瀏覽器渲染
驗證範圍 後端邏輯、資料正確性 使用者實際看到與操作的畫面
適合情境 準備測試資料、驗證 API 合約 驗證關鍵使用者流程、畫面互動

實務上建議依「測試金字塔」概念分配:大量的商業邏輯用 API 測試或單元測試快速覆蓋,畫面層級的 Playwright UI 測試則聚焦在少數關鍵使用者流程(如登入、結帳),避免所有情境都堆疊成又慢又多的 UI 測試。

下一步

接著看 身份驗證狀態與視覺比對,學習如何讓多個測試重複使用同一個登入狀態,以及用截圖比對偵測未預期的畫面變化。