Playwright進階篇(二):API 測試與攔截

testing

POM 基本概念與優勢

為什麼需要 POM?


Page Object Model 是一種測試設計模式,旨在解決自動化測試中的常見挑戰:


  1. 代碼可維護性

    • 將頁面元素和操作邏輯集中管理
    • 降低重複代碼
    • 簡化測試腳本邏輯

  2. 測試穩定性

    • 元素定位集中管理
    • 易於修改和更新
    • 降低元素變化對測試的影響

  3. 代碼複用

    • 封裝常用的頁面操作
    • 減少重複勞動
    • 提高測試開發效率

設計基本 Page Object 類別


元素封裝與操作方法示例


import { Page, Locator } from '@playwright/test';

class LoginPage {
  // 頁面元素定義
  private page: Page;
  private usernameInput: Locator;
  private passwordInput: Locator;
  private loginButton: Locator;

  // 構造函數
  constructor(page: Page) {
    this.page = page;
    this.usernameInput = page.locator('#username');
    this.passwordInput = page.locator('#password');
    this.loginButton = page.locator('button[type="submit"]');
  }

  // 登入操作方法
  async login(username: string, password: string) {
    await this.usernameInput.fill(username);
    await this.passwordInput.fill(password);
    await this.loginButton.click();
    
    // 可選:等待登入後的頁面載入
    await this.page.waitForURL('/dashboard');
  }

  // 驗證方法
  async isLoginErrorDisplayed(): Promise<boolean> {
    return this.page.locator('.error-message').isVisible();
  }
}

export default LoginPage;

簡單實例:從腳本到 POM


重構測試案例


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

test('用戶登入流程', async ({ page }) => {
  // 使用 POM
  const loginPage = new LoginPage(page);
  
  // 導航到登入頁面
  await page.goto('/login');
  
  // 使用封裝的登入方法
  await loginPage.login('testuser', 'password123');
  
  // 驗證登入結果
  expect(await loginPage.isLoginErrorDisplayed()).toBeFalsy();
});

組織複雜頁面結構

元件化與層次結構

// 複雜頁面的組件示例
class DashboardPage {
  private sideMenu: Locator;
  private userProfile: Locator;
  private mainContent: Locator;

  constructor(page: Page) {
    this.sideMenu = page.locator('.side-menu');
    this.userProfile = page.locator('.user-profile');
    this.mainContent = page.locator('.main-content');
  }

  // 組件相關方法
  async navigateToSection(section: string) {
    await this.sideMenu.getByText(section).click();
  }
}

共用元素與行為

基礎類別與繼承

// 基礎頁面類別
class BasePage {
  protected page: Page;

  constructor(page: Page) {
    this.page = page;
  }

  // 通用方法
  async waitForLoadState() {
    await this.page.waitForLoadState('networkidle');
  }

  async takeScreenshot(name: string) {
    await this.page.screenshot({ path: `screenshots/${name}.png` });
  }
}

// 繼承基礎類別
class ProductPage extends BasePage {
  private productList: Locator;

  constructor(page: Page) {
    super(page);
    this.productList = page.locator('.product-list');
  }

  // 特定頁面方法
  async getProductCount(): Promise<number> {
    return this.productList.locator('.product-item').count();
  }
}

POM 最佳實踐


避免常見陷阱


  1. 不要在 Page Object 中編寫斷言

    • 保持 Page Object 專注於操作
    • 斷言邏輯放在測試腳本中

  2. 保持方法的單一職責

    • 每個方法只做一件事
    • 避免複雜的方法邏輯

  3. 使用有意義的方法名稱

    • 描述性的方法命名
    • 提高代碼可讀性

維護技巧


  • 定期審查和重構 Page Object
  • 使用集中的元素定位策略
  • 為複雜交互創建專門的方法
  • 考慮使用工廠模式管理 Page Object
  • 保持 Page Object 輕量且專注

結論

Page Object Model 是一種強大的測試設計模式,可以顯著提高 Playwright 測試的可維護性和可讀性。通過正確實踐,您可以建立更robust、更易於維護的自動化測試套件。

分享這篇文章: