Skip to content

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

Fixtures 與 Hooks

@playwright/test 內建的 Fixture 系統,是它與其他測試框架最大的差異之一。理解 Fixture 能大幅減少重複程式碼,讓測試專案更容易維護。

什麼是 Fixture?

Fixture 是測試執行前自動準備好、測試結束後自動清理的資源。前面範例一直用到的 page 就是最常見的內建 Fixture:

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

test('範例', async ({ page, context, browser }) => {
  // page:已開好的瀏覽器分頁
  // context:獨立的瀏覽器內容(cookies、storage 互不干擾)
  // browser:整個瀏覽器實例
});

每個測試都會拿到全新的 pagecontext,測試之間完全隔離,這也是 Playwright 測試可以安心平行執行的原因(見 平行執行與 CI/CD 整合)。

自訂 Fixture

當多個測試都需要「已登入的頁面」時,與其在每個測試重複寫登入步驟,可以封裝成自訂 Fixture:

// fixtures.ts
import { test as base, expect } from '@playwright/test';

type MyFixtures = {
  loggedInPage: import('@playwright/test').Page;
};

export const test = base.extend<MyFixtures>({
  loggedInPage: async ({ page }, use) => {
    await page.goto('/login');
    await page.getByLabel('帳號').fill('demo@vcdemy.com');
    await page.getByLabel('密碼').fill('password123');
    await page.getByRole('button', { name: '登入' }).click();
    await expect(page.getByText('歡迎回來')).toBeVisible();

    await use(page); // 交還給測試使用

    // use() 之後的程式碼會在測試結束後執行,適合放清理邏輯
  },
});

export { expect };
// dashboard.spec.ts
import { test, expect } from './fixtures';

test('已登入使用者可以看到儀表板', async ({ loggedInPage }) => {
  await expect(loggedInPage.getByRole('heading', { name: '儀表板' })).toBeVisible();
});

use() 前的程式碼是「準備」,use() 後的程式碼是「清理」,寫法類似 try...finally,即使測試失敗也會執行清理。

Hooks:測試前後的共用邏輯

若不需要回傳資源、只是想在測試前後執行共用步驟,可以用 test.beforeEach() / test.afterEach()

test.beforeEach(async ({ page }) => {
  await page.goto('/');
});

test.afterEach(async ({ page }, testInfo) => {
  if (testInfo.status !== testInfo.expectedStatus) {
    console.log(`測試失敗:${testInfo.title}`);
  }
});

beforeEach / afterEach 適合簡單的共用步驟;需要「回傳一個物件給測試使用」時,優先用 Fixture,這樣可以透過 TypeScript 型別檢查,也方便在不同測試檔案間重複使用。

用 test.describe 分組

test.describe('購物車功能', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/cart');
  });

  test('可以新增商品', async ({ page }) => { /* ... */ });
  test('可以移除商品', async ({ page }) => { /* ... */ });
});

test.describe 讓相關測試分組管理,搭配 beforeEach 可以只在這個群組套用共用的前置作業,不影響其他測試檔案。

下一步

Fixture 也是實作 Page Object Model 的重要工具,接下來看如何把頁面操作封裝成更易讀的物件。