【AI 測試 Skill 入門篇】02 | 第一個自動化測試
整理版優先睇
用 playwright-cli Skill 以 sogoodtool.com 做實戰,學寫第一個自動化測試,掌握元素定位優先級同核心 API
呢篇文章係 AI 測試 Skill 入門系列嘅第二篇,作者係一位專注推廣 Playwright 自動化測試嘅教練,目標係幫已經搭好環境但唔知點開始嘅測試新手快速上手。佢指出常見三大痛點:唔知第一行 code 寫咩、只會 copy-paste 但唔明背後原理、想測實際網站但無從入手。整體結論係:用 playwright-cli Skill 配合結構化嘅學習路徑,由分析頁面、設計測試用例到編寫 code,可以好快寫出第一個可靠嘅自動化測試。
作者以 sogoodtool.com 嘅登錄頁面做實例,逐步拆解點樣用 Playwright 嘅最佳定位方法(getByRole > getByLabel > getByPlaceholder > getByText > getByTestId > CSS/XPath),並設計咗六個測試用例覆蓋正常登錄、錯誤密碼、用戶唔存在、空郵箱、空密碼等場景。每個用例都有明確步驟同斷言,仲提供咗完整嘅 code 範例同執行指令,令讀者可以跟住做。
最後文章總結咗核心知識點:頁面導航、元素定位、元素交互、斷言驗證同等待機制,強調 networkidle 係最推薦嘅等待方式。成個流程由痛點出發,畀出解決方案,再落地到實戰,係一篇高密度、可即用嘅入門教學。
- playwright-cli Skill 涵蓋瀏覽器啟動、頁面導航、元素定位、交互、斷言、等待同調試,係寫自動化測試嘅基礎工具箱。
- 元素定位優先級:getByRole 最穩定 -> getByLabel -> getByPlaceholder -> getByText -> getByTestId -> CSS/XPath(唔推薦)。
- 用語義化定位(role、label)比傳統 CSS/XPath 更抗 UI 變更,係保持測試穩定嘅關鍵。
- 實戰案例展示咗點樣由分析頁面結構到設計六個測試用例,覆蓋正常流程同邊界情況。
- 跟住文章嘅 code 範例,任何人都可以喺 sogoodtool.com 上寫出第一個 Playwright 測試並執行。
痛點與解決方案:環境搞掂咗,但點樣開始寫測試?
你可能已經裝好 Node.js、Playwright 同 Trae CN,但打開編輯器就懵咗:第一行 code 寫咩?點樣打開瀏覽器?點樣定位元素?呢篇文章就係為咗解決呢個問題,用 playwright-cli Skill 帶你寫第一個自動化測試。
好多新手只係識得 copy-paste 網上嘅 code,但唔明 page.goto() 點解要等、getByText() 同 getByRole() 有咩分別、expect() 可以驗證啲咩。呢篇文章會逐一拆解,並以真實網站 sogoodtool.com 做實戰,令你唔再怕寫測試。
playwright-cli Skill 核心能力一覽
playwright-cli Skill 包含咗 Playwright 嘅基礎能力,以下係佢嘅核心功能分類:
- 瀏覽器啟動:支援 Chromium、Firefox、WebKit,可選無頭/有頭模式,設置窗口大小,仲可以多瀏覽器並行執行。
- 頁面導航:page.goto() 打開 URL、page.reload() 刷新、page.goBack()/goForward() 前進後退,同埋等待頁面加載(waitForLoadState)。
- 元素定位:推薦 getByRole、getByLabel、getByPlaceholder、getByText,其次 getByTestId,唔推薦 CSS 同 XPath。
- 元素交互:click、fill、selectOption、check/uncheck、press 鍵盤操作。
- 斷言驗證:URL(toHaveURL)、標題(toHaveTitle)、可見性(toBeVisible)、文本(toHaveText)、屬性(toHaveAttribute)、包含(toContainText)。
- 等待機制:waitFor 元素可見、waitForResponse 網絡請求、waitForNavigation 導航、waitForLoadState(推薦 networkidle)。
- 調試支援:截圖(screenshot)、錄屏(video)、追蹤(trace)同 Playwright Inspector。
元素定位優先級:邊種方法最穩陣?
元素定位係自動化測試嘅核心,揀啱方法可以令測試更穩定、更易維護。playwright-cli Skill 提倡嘅優先級由高到低如下:
- 1 getByRole(最推薦):語義化定位,例如 getByRole('button', { name: '登錄' }),最穩定。
- 2 getByLabel(推薦):適用於表單輸入框,例如 getByLabel('郵箱')。
- 3 getByPlaceholder(推薦):適用於有 placeholder 嘅輸入框,例如 getByPlaceholder('請輸入郵箱')。
- 4 getByText(推薦):適用於文本內容,例如 getByText('登錄成功')。
- 5 getByTestId(儘量用):需要開發配合加 data-testid。
- 6 CSS 選擇器(唔推薦):容易受 CSS 類名變化影響。
- 7 XPath(唔推薦):最唔穩定,易受 DOM 結構變化影響。
實戰案例:測試 sogoodtool.com 嘅登錄功能
作者用 sogoodtool.com 嘅登錄頁面做實例,示範由分析頁面到寫 code 嘅完整流程。首先分析頁面結構:有郵箱輸入框(placeholder「請輸入郵箱」)、密碼輸入框(placeholder「請輸入密碼」)、登錄按鈕(角色 button,名「登錄」)。然後設計咗六個測試用例:
- TC001:頁面正常加載——驗證標題同輸入框可見。
- TC002:登錄成功——輸入正確郵箱密碼,驗證跳轉到 dashboard。
- TC003:密碼錯誤——輸入錯誤密碼,驗證顯示「密碼錯誤」。
- TC004:用戶唔存在——輸入唔存在嘅郵箱,驗證顯示「用戶唔存在」。
- TC005:郵箱為空——唔入郵箱,驗證顯示「請輸入郵箱」。
- TC006:密碼為空——唔入密碼,驗證顯示「請輸入密碼」。
作者提供咗完整嘅 code 範例(tests/login.spec.ts),示範點樣用 test.beforeEach 統一導航,同埋用 getByPlaceholder、getByRole、getByText 定位元素。仲有執行測試嘅指令:
# 運行所有測試
npx playwright test
# 運行特定測試文件
npx playwright test tests/login.spec.ts
# 在 UI 模式下運行(可以看到瀏覽器操作)
npx playwright test tests/login.spec.ts --ui
# 只運行 Chromium
npx playwright test tests/login.spec.ts --project=chromium
# 生成 HTML 報告
npx playwright test tests/login.spec.ts --reporter=html
npx playwright show-report
核心知識點總結:導航、定位、交互、斷言、等待
最後作者歸納咗五大核心知識點,係每個人寫 Playwright 測試都一定要掌握嘅:
- 頁面導航:page.goto() 打開 URL,搭配 waitForLoadState('networkidle') 確保頁面完全加載。
- 元素定位:首選 getByRole 同 getByPlaceholder,其次 getByText,避免 CSS/XPath。
- 元素交互:click()、fill()、selectOption()、check()/uncheck()、press()。
- 斷言驗證:用 expect() 配合 toHaveURL、toBeVisible、toHaveText 等,檢查結果。
- 等待機制:推薦 waitForLoadState('networkidle'),避免用硬編碼 waitForTimeout。
【AI 測試 Skill 入門篇】02 | 第一個自動化測試:sogoodtool.com 實戰案例
一、難題:環境已經砌好咗,但係唔知點開始寫測試
你係咪有呢啲疑問?
1. 環境砌好咗,但係唔知由邊度入手
你可能已經搞掂咗環境設置:
✅ Node.js 安裝咗 ✅ Playwright 安裝咗 ✅ Trae CN 都安裝咗
但係一打開編輯器,就懵咗:
❌ 第一行代碼寫啲乜? ❌ 點樣打開瀏覽器? ❌ 點樣定位元素? ❌ 點樣驗證結果?
2. 淨係識得複製貼上,唔知點解要咁寫
你可能喺網上揾到咗一啲 Playwright 嘅示例代碼:
await page.goto('https://example.com');
await page.getByText('登錄').click();
await expect(page).toHaveURL('/dashboard');
但係你唔知道:
❌ page.goto()點解要等待?❌ getByText()和getByRole()有咩分別?❌ expect()可以驗證啲乜嘢?❌ 測試失敗咗點樣除錯?
3. 想測試真實嘅項目,但係唔知點樣入手
你可能想測試自己公司嘅項目,或者好似 sogoodtool.com 噉樣嘅真實網站,但係:
❌ 唔知點分析頁面結構 ❌ 唔知點設計測試用例 ❌ 唔知點處理各種互動場景
二、解決方案:用 playwright-cli Skill 寫第一個測試
今日同大家介紹 playwright-cli Skill,佢包含咗 Playwright 嘅基本能力:
playwright-cliSkill 包含咗啲乜?
┌─────────────────────────────────────────────────────────┐
│ playwright-cli Skill 核心能力 │
├─────────────────────────────────────────────────────────┤
│ │
│ 【瀏覽器啓動】 │
│ ├── 啓動 Chromium、Firefox、WebKit │
│ ├── 無頭模式 / 有頭模式 │
│ ├── 瀏覽器窗口大小設置 │
│ └── 多瀏覽器並行執行 │
│ │
│ 【頁面導航】 │
│ ├── 打開 URL(page.goto) │
│ ├── 頁面刷新(page.reload) │
│ ├── 前進後退(page.goBack / page.goForward) │
│ └── 等待頁面加載(waitForLoadState) │
│ │
│ 【元素定位】 │
│ ├── getByRole(推薦) │
│ ├── getByText │
│ ├── getByLabel │
│ ├── getByPlaceholder │
│ ├── getByTestId │
│ └── CSS / XPath(不推薦) │
│ │
│ 【元素交互】 │
│ ├── 點擊(click) │
│ ├── 輸入(fill) │
│ ├── 選擇(selectOption) │
│ ├── 勾選(check / uncheck) │
│ └── 鍵盤操作(press) │
│ │
│ 【斷言驗證】 │
│ ├── URL 驗證(toHaveURL) │
│ ├── 標題驗證(toHaveTitle) │
│ ├── 可見性驗證(toBeVisible) │
│ ├── 文本驗證(toHaveText) │
│ ├── 屬性驗證(toHaveAttribute) │
│ └── 包含驗證(toContainText) │
│ │
│ 【等待機制】 │
│ ├── 等待元素可見(waitFor) │
│ ├── 等待網絡請求(waitForResponse) │
│ └── 等待導航(waitForNavigation) │
│ │
│ 【調試支持】 │
│ ├── 截圖(screenshot) │
│ ├── 錄屏(video) │
│ ├── 追蹤(trace) │
│ └── Playwright Inspector │
│ │
└─────────────────────────────────────────────────────────┘
元素定位優先級
playwright-cli Skill 強調咗一個非常重要嘅原則:元素定位優先級
┌─────────────────────────────────────────────────────────┐
│ 元素定位優先級 │
├─────────────────────────────────────────────────────────┤
│ │
│ 推薦程度從高到低: │
│ │
│ 1. getByRole ✅ 最推薦 │
│ ├── 語義化定位,最穩定 │
│ └── 例如:getByRole('button', { name: '登錄' }) │
│ │
│ 2. getByLabel ✅ 推薦 │
│ ├── 適用於表單輸入框 │
│ └── 例如:getByLabel('郵箱') │
│ │
│ 3. getByPlaceholder ✅ 推薦 │
│ ├── 適用於有 placeholder 的輸入框 │
│ └── 例如:getByPlaceholder('請輸入郵箱') │
│ │
│ 4. getByText ✅ 推薦 │
│ ├── 適用於文本內容 │
│ └── 例如:getByText('登錄成功') │
│ │
│ 5. getByTestId ⚠️ 儘量用 │
│ ├── 需要開發配合添加 data-testid │
│ └── 例如:getByTestId('login-button') │
│ │
│ 6. CSS 選擇器 ❌ 不推薦 │
│ ├── 容易受 CSS 類名變化影響 │
│ └── 例如:page.locator('.login-btn') │
│ │
│ 7. XPath ❌ 不推薦 │
│ ├── 最不穩定,容易受 DOM 結構變化影響 │
│ └── 例如:page.locator('//button[text()="登錄"]') │
│ │
└─────────────────────────────────────────────────────────┘
三、真實案例:測試 sogoodtool.com 嘅登入功能
等我哋用 sogoodtool.com 嚟實際演練,寫一個完整嘅登入功能測試。
第一步:分析登入頁面
首先,等我哋睇嚇 sogoodtool.com 嘅登入頁面:
┌─────────────────────────────────────────────────────────┐
│ sogoodtool.com 登錄頁面 │
├─────────────────────────────────────────────────────────┤
│ │
│ [sogoodtool 標誌] │
│ │
│ 郵箱: [________________________________] │
│ 請輸入郵箱 │
│ │
│ 密碼: [________________________________] │
│ 請輸入密碼 │
│ │
│ [記住我] 忘記密碼? │
│ │
│ [ 登 錄 ] │
│ │
│ 還沒有賬號?[立即註冊] │
│ │
└─────────────────────────────────────────────────────────┘
第二步:設計測試用例
基於 playwright-cli Skill,我哋可以設計以下測試用例:
第三步:編寫測試代碼
創建 tests/login.spec.ts 文件:
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
// 測試套件:登錄功能測試
test.describe('登錄功能測試', () => {
// 每個測試用例執行前的操作
test.beforeEach(async ({ page }) => {
// 導航到登錄頁面
await page.goto('https://sogoodtool.com/#/login');
// 等待頁面加載完成
await page.waitForLoadState('networkidle');
});
// TC001: 頁面正常加載
test('頁面能夠正常加載', async ({ page }) => {
// 驗證頁面標題
await expect(page).toHaveTitle(/登錄/);
// 驗證郵箱輸入框可見(通過 placeholder)
await expect(page.getByPlaceholder('請輸入郵箱')).toBeVisible();
// 驗證密碼輸入框可見
await expect(page.getByPlaceholder('請輸入密碼')).toBeVisible();
// 驗證登錄按鈕可見(通過 role)
await expect(page.getByRole('button', { name: '登錄' })).toBeVisible();
});
// TC002: 登錄成功
test('用戶可以成功登錄', async ({ page }) => {
// 輸入郵箱(使用 getByPlaceholder)
await page.getByPlaceholder('請輸入郵箱').fill('test@sogoodtool.com');
// 輸入密碼
await page.getByPlaceholder('請輸入密碼').fill('Test1234');
// 點擊登錄按鈕(使用 getByRole)
await page.getByRole('button', { name: '登錄' }).click();
// 等待導航完成
await page.waitForLoadState('networkidle');
// 驗證跳轉到 dashboard
await expect(page).toHaveURL(/dashboard/);
});
// TC003: 登錄失敗 - 密碼錯誤
test('登錄失敗:密碼錯誤', async ({ page }) => {
// 輸入正確的郵箱
await page.getByPlaceholder('請輸入郵箱').fill('test@sogoodtool.com');
// 輸入錯誤的密碼
await page.getByPlaceholder('請輸入密碼').fill('WrongPassword');
// 點擊登錄按鈕
await page.getByRole('button', { name: '登錄' }).click();
// 驗證顯示錯誤提示
await expect(page.getByText('密碼錯誤')).toBeVisible();
// 驗證沒有跳轉(仍然在登錄頁面)
await expect(page).toHaveURL(/login/);
});
// TC004: 登錄失敗 - 用戶不存在
test('登錄失敗:用戶不存在', async ({ page }) => {
// 輸入不存在的郵箱
await page.getByPlaceholder('請輸入郵箱').fill('nonexistent@sogoodtool.com');
// 輸入任意密碼
await page.getByPlaceholder('請輸入密碼').fill('Test1234');
// 點擊登錄按鈕
await page.getByRole('button', { name: '登錄' }).click();
// 驗證顯示錯誤提示
await expect(page.getByText('用戶不存在')).toBeVisible();
});
// TC005: 登錄失敗 - 郵箱為空
test('登錄失敗:郵箱為空', async ({ page }) => {
// 不輸入郵箱,直接輸入密碼
await page.getByPlaceholder('請輸入密碼').fill('Test1234');
// 點擊登錄按鈕
await page.getByRole('button', { name: '登錄' }).click();
// 驗證顯示錯誤提示
await expect(page.getByText('請輸入郵箱')).toBeVisible();
});
// TC006: 登錄失敗 - 密碼為空
test('登錄失敗:密碼為空', async ({ page }) => {
// 輸入郵箱,不輸入密碼
await page.getByPlaceholder('請輸入郵箱').fill('test@sogoodtool.com');
// 點擊登錄按鈕
await page.getByRole('button', { name: '登錄' }).click();
// 驗證顯示錯誤提示
await expect(page.getByText('請輸入密碼')).toBeVisible();
});
});
第四步:執行測試
# 運行所有測試
npx playwright test
# 運行特定測試文件
npx playwright test tests/login.spec.ts
# 在 UI 模式下運行(可以看到瀏覽器操作)
npx playwright test tests/login.spec.ts --ui
# 只運行 Chromium
npx playwright test tests/login.spec.ts --project=chromium
第五步:睇測試報告
# 運行測試並生成 HTML 報告
npx playwright test tests/login.spec.ts --reporter=html
# 打開報告
npx playwright show-report
四、核心知識點總結
1. 頁面導航
// 基礎導航
await page.goto('https://sogoodtool.com/#/login');
// 等待頁面加載
await page.waitForLoadState('networkidle');
// 等待導航完成
await page.waitForNavigation();
// 頁面刷新
await page.reload();
// 前進後退
await page.goBack();
await page.goForward();
2. 元素定位(建議方式)
// 1. getByRole(最推薦)
await page.getByRole('button', { name: '登錄' }).click();
await page.getByRole('textbox', { name: '郵箱' }).fill('test@example.com');
// 2. getByPlaceholder(適用於輸入框)
await page.getByPlaceholder('請輸入郵箱').fill('test@example.com');
await page.getByPlaceholder('請輸入密碼').fill('Test1234');
// 3. getByText(適用於文本)
await expect(page.getByText('密碼錯誤')).toBeVisible();
await expect(page.getByText('用戶不存在')).toBeVisible();
// 4. getByLabel(適用於表單)
await page.getByLabel('郵箱').fill('test@example.com');
await page.getByLabel('記住我').check();
3. 元素互動
// 點擊
await page.getByRole('button', { name: '登錄' }).click();
// 輸入
await page.getByPlaceholder('請輸入郵箱').fill('test@example.com');
// 清空
await page.getByPlaceholder('請輸入郵箱').fill('');
// 選擇下拉框
await page.getByRole('combobox').selectOption('公開訪問');
// 勾選複選框
await page.getByLabel('記住我').check();
// 取消勾選
await page.getByLabel('記住我').uncheck();
// 鍵盤操作
await page.getByPlaceholder('請輸入密碼').press('Enter');
4. 斷言驗證
// URL 驗證
await expect(page).toHaveURL(/dashboard/);
await expect(page).toHaveURL('https://sogoodtool.com/#/dashboard');
// 標題驗證
await expect(page).toHaveTitle(/登錄/);
// 可見性驗證
await expect(page.getByText('密碼錯誤')).toBeVisible();
await expect(page.getByText('登錄成功')).toBeHidden();
// 文本驗證
await expect(page.getByRole('heading')).toHaveText('歡迎回來');
// 包含驗證
await expect(page.locator('.error-message')).toContainText('錯誤');
// 屬性驗證
await expect(page.getByRole('button', { name: '登錄' })).toBeEnabled();
await expect(page.getByRole('button', { name: '登錄' })).toBeDisabled();
5. 等待機制
// 等待元素可見
await page.getByText('登錄成功').waitFor();
// 等待指定時間(不推薦,但調試時有用)
await page.waitForTimeout(1000);
// 等待網絡請求
await page.waitForResponse('**/api/login');
// 等待導航
await page.waitForNavigation();
// 等待頁面加載狀態
await page.waitForLoadState('load'); // 等待 load 事件
await page.waitForLoadState('domcontentloaded'); // 等待 DOM 加載
await page.waitForLoadState('networkidle'); // 等待網絡空閒(推薦)
五、下一篇預告
恭喜你!而家你已經學識咗 點樣寫第一個 Playwright 自動化測試。
下一篇文章,我會帶你解決一個更實際嘅問題:
【AI 測試 Skill 進階篇】03 | 穩健元素定位:UI 變更時測試唔會崩潰嘅秘訣
喺嗰篇文章入面,你會學到:
點解 UI 一變,測試就全部死曬? 咩係多備選定位器策略? 點樣判斷元素係咪存在、係咪可見? 如何用 playwright-robust-locators點樣用 Skill 編寫穩健嘅測試?
敬請期待!
六、想更有系統咁學習?加入知識星球
你想得到啲乜?
今日同大家介紹嘅 playwright-cli Skill,只係 8 個 Playwright Skill 之中嘅一個。
如果你想:
✅ 得到 完整嘅 8 個 Playwright Skill ✅ 學習 playwright-robust-locators(穩健元素定位)✅ 得到 sogoodtool.com 完整嘅測試用例 ✅ 有問題可以隨時問 ✅ 持續學習更多測試乾貨
我推薦嘅 Skill
我整理咗 8 個完整嘅 Playwright 自動化測試 Skill:
playwright-cli | ||
playwright-robust-locators | ||
playwright-core-features-testing | ||
playwright-positive-negative-testing | ||
playwright-cli-url-docs-to-json-zh | ||
playwright-cli-execute-stop-zh | ||
json-testcase-to-excel-zh | ||
ai-testing-skill |
點樣得到?
呢啲 Skill 都已經放咗喺我嘅 「Bigtalk軟件測試進階」 知識星球入面喇。
掃瞄下面嘅QR code,加入知識星球,就可以得到:
✅ 8 個完整嘅 Playwright 自動化測試 Skill ✅ sogoodtool.com 完整嘅測試用例 ✅ 我會喺星球入面持續更新更多測試乾貨 ✅ 可以向我提問,我會喺星球入面解答

微信掃碼,加入「Bigtalk軟件測試進階」
想轉型做 AI 測試工程師?想有系統咁學習 Playwright 自動化測試?
掃瞄QR code,加入知識星球,開始你嘅進階之路! 🚀
下一篇:《【AI 測試 Skill 進階篇】03 | 穩健元素定位:UI 變更時測試唔會崩潰嘅秘訣》,敬請期待!
【AI 測試 Skill 入門篇】02 | 第一個自動化測試:sogoodtool.com 實戰案例
一、痛點:環境搭好了,但不知道怎麼開始寫測試
你是不是有這些困惑?
1. 環境搭好了,但不知道從哪下手
你可能已經完成了環境搭建:
✅ Node.js 安裝好了 ✅ Playwright 安裝好了 ✅ Trae CN 也安裝好了
但一打開編輯器,就懵了:
❌ 第一行代碼寫什麼? ❌ 怎麼打開瀏覽器? ❌ 怎麼定位元素? ❌ 怎麼驗證結果?
2. 只會複製粘貼,不知道為什麼這樣寫
你可能在網上找到了一些 Playwright 的示例代碼:
await page.goto('https://example.com');
await page.getByText('登錄').click();
await expect(page).toHaveURL('/dashboard');
但你不知道:
❌ page.goto()為什麼要等待?❌ getByText()和getByRole()有什麼區別?❌ expect()可以驗證哪些東西?❌ 測試失敗了怎麼調試?
3. 想測試實際項目,但不知道怎麼入手
你可能想測試自己公司的項目,或者像 sogoodtool.com 這樣的實際網站,但:
❌ 不知道怎麼分析頁面結構 ❌ 不知道怎麼設計測試用例 ❌ 不知道怎麼處理各種交互場景
二、解決方案:用 playwright-cli Skill 寫第一個測試
今天給大家介紹 playwright-cli Skill,它包含了 Playwright 的基礎能力:
playwright-cliSkill 包含什麼?
┌─────────────────────────────────────────────────────────┐
│ playwright-cli Skill 核心能力 │
├─────────────────────────────────────────────────────────┤
│ │
│ 【瀏覽器啓動】 │
│ ├── 啓動 Chromium、Firefox、WebKit │
│ ├── 無頭模式 / 有頭模式 │
│ ├── 瀏覽器窗口大小設置 │
│ └── 多瀏覽器並行執行 │
│ │
│ 【頁面導航】 │
│ ├── 打開 URL(page.goto) │
│ ├── 頁面刷新(page.reload) │
│ ├── 前進後退(page.goBack / page.goForward) │
│ └── 等待頁面加載(waitForLoadState) │
│ │
│ 【元素定位】 │
│ ├── getByRole(推薦) │
│ ├── getByText │
│ ├── getByLabel │
│ ├── getByPlaceholder │
│ ├── getByTestId │
│ └── CSS / XPath(不推薦) │
│ │
│ 【元素交互】 │
│ ├── 點擊(click) │
│ ├── 輸入(fill) │
│ ├── 選擇(selectOption) │
│ ├── 勾選(check / uncheck) │
│ └── 鍵盤操作(press) │
│ │
│ 【斷言驗證】 │
│ ├── URL 驗證(toHaveURL) │
│ ├── 標題驗證(toHaveTitle) │
│ ├── 可見性驗證(toBeVisible) │
│ ├── 文本驗證(toHaveText) │
│ ├── 屬性驗證(toHaveAttribute) │
│ └── 包含驗證(toContainText) │
│ │
│ 【等待機制】 │
│ ├── 等待元素可見(waitFor) │
│ ├── 等待網絡請求(waitForResponse) │
│ └── 等待導航(waitForNavigation) │
│ │
│ 【調試支持】 │
│ ├── 截圖(screenshot) │
│ ├── 錄屏(video) │
│ ├── 追蹤(trace) │
│ └── Playwright Inspector │
│ │
└─────────────────────────────────────────────────────────┘
元素定位優先級
playwright-cli Skill 強調了一個非常重要的原則:元素定位優先級
┌─────────────────────────────────────────────────────────┐
│ 元素定位優先級 │
├─────────────────────────────────────────────────────────┤
│ │
│ 推薦程度從高到低: │
│ │
│ 1. getByRole ✅ 最推薦 │
│ ├── 語義化定位,最穩定 │
│ └── 例如:getByRole('button', { name: '登錄' }) │
│ │
│ 2. getByLabel ✅ 推薦 │
│ ├── 適用於表單輸入框 │
│ └── 例如:getByLabel('郵箱') │
│ │
│ 3. getByPlaceholder ✅ 推薦 │
│ ├── 適用於有 placeholder 的輸入框 │
│ └── 例如:getByPlaceholder('請輸入郵箱') │
│ │
│ 4. getByText ✅ 推薦 │
│ ├── 適用於文本內容 │
│ └── 例如:getByText('登錄成功') │
│ │
│ 5. getByTestId ⚠️ 儘量用 │
│ ├── 需要開發配合添加 data-testid │
│ └── 例如:getByTestId('login-button') │
│ │
│ 6. CSS 選擇器 ❌ 不推薦 │
│ ├── 容易受 CSS 類名變化影響 │
│ └── 例如:page.locator('.login-btn') │
│ │
│ 7. XPath ❌ 不推薦 │
│ ├── 最不穩定,容易受 DOM 結構變化影響 │
│ └── 例如:page.locator('//button[text()="登錄"]') │
│ │
└─────────────────────────────────────────────────────────┘
三、實際案例:測試 sogoodtool.com 的登錄功能
讓我們用 sogoodtool.com 來實際演練,寫一個完整的登錄功能測試。
第一步:分析登錄頁面
首先,讓我們看看 sogoodtool.com 的登錄頁面:
┌─────────────────────────────────────────────────────────┐
│ sogoodtool.com 登錄頁面 │
├─────────────────────────────────────────────────────────┤
│ │
│ [sogoodtool 標誌] │
│ │
│ 郵箱: [________________________________] │
│ 請輸入郵箱 │
│ │
│ 密碼: [________________________________] │
│ 請輸入密碼 │
│ │
│ [記住我] 忘記密碼? │
│ │
│ [ 登 錄 ] │
│ │
│ 還沒有賬號?[立即註冊] │
│ │
└─────────────────────────────────────────────────────────┘
第二步:設計測試用例
基於 playwright-cli Skill,我們可以設計以下測試用例:
第三步:編寫測試代碼
創建 tests/login.spec.ts 文件:
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
// 測試套件:登錄功能測試
test.describe('登錄功能測試', () => {
// 每個測試用例執行前的操作
test.beforeEach(async ({ page }) => {
// 導航到登錄頁面
await page.goto('https://sogoodtool.com/#/login');
// 等待頁面加載完成
await page.waitForLoadState('networkidle');
});
// TC001: 頁面正常加載
test('頁面能夠正常加載', async ({ page }) => {
// 驗證頁面標題
await expect(page).toHaveTitle(/登錄/);
// 驗證郵箱輸入框可見(通過 placeholder)
await expect(page.getByPlaceholder('請輸入郵箱')).toBeVisible();
// 驗證密碼輸入框可見
await expect(page.getByPlaceholder('請輸入密碼')).toBeVisible();
// 驗證登錄按鈕可見(通過 role)
await expect(page.getByRole('button', { name: '登錄' })).toBeVisible();
});
// TC002: 登錄成功
test('用戶可以成功登錄', async ({ page }) => {
// 輸入郵箱(使用 getByPlaceholder)
await page.getByPlaceholder('請輸入郵箱').fill('test@sogoodtool.com');
// 輸入密碼
await page.getByPlaceholder('請輸入密碼').fill('Test1234');
// 點擊登錄按鈕(使用 getByRole)
await page.getByRole('button', { name: '登錄' }).click();
// 等待導航完成
await page.waitForLoadState('networkidle');
// 驗證跳轉到 dashboard
await expect(page).toHaveURL(/dashboard/);
});
// TC003: 登錄失敗 - 密碼錯誤
test('登錄失敗:密碼錯誤', async ({ page }) => {
// 輸入正確的郵箱
await page.getByPlaceholder('請輸入郵箱').fill('test@sogoodtool.com');
// 輸入錯誤的密碼
await page.getByPlaceholder('請輸入密碼').fill('WrongPassword');
// 點擊登錄按鈕
await page.getByRole('button', { name: '登錄' }).click();
// 驗證顯示錯誤提示
await expect(page.getByText('密碼錯誤')).toBeVisible();
// 驗證沒有跳轉(仍然在登錄頁面)
await expect(page).toHaveURL(/login/);
});
// TC004: 登錄失敗 - 用戶不存在
test('登錄失敗:用戶不存在', async ({ page }) => {
// 輸入不存在的郵箱
await page.getByPlaceholder('請輸入郵箱').fill('nonexistent@sogoodtool.com');
// 輸入任意密碼
await page.getByPlaceholder('請輸入密碼').fill('Test1234');
// 點擊登錄按鈕
await page.getByRole('button', { name: '登錄' }).click();
// 驗證顯示錯誤提示
await expect(page.getByText('用戶不存在')).toBeVisible();
});
// TC005: 登錄失敗 - 郵箱為空
test('登錄失敗:郵箱為空', async ({ page }) => {
// 不輸入郵箱,直接輸入密碼
await page.getByPlaceholder('請輸入密碼').fill('Test1234');
// 點擊登錄按鈕
await page.getByRole('button', { name: '登錄' }).click();
// 驗證顯示錯誤提示
await expect(page.getByText('請輸入郵箱')).toBeVisible();
});
// TC006: 登錄失敗 - 密碼為空
test('登錄失敗:密碼為空', async ({ page }) => {
// 輸入郵箱,不輸入密碼
await page.getByPlaceholder('請輸入郵箱').fill('test@sogoodtool.com');
// 點擊登錄按鈕
await page.getByRole('button', { name: '登錄' }).click();
// 驗證顯示錯誤提示
await expect(page.getByText('請輸入密碼')).toBeVisible();
});
});
第四步:運行測試
# 運行所有測試
npx playwright test
# 運行特定測試文件
npx playwright test tests/login.spec.ts
# 在 UI 模式下運行(可以看到瀏覽器操作)
npx playwright test tests/login.spec.ts --ui
# 只運行 Chromium
npx playwright test tests/login.spec.ts --project=chromium
第五步:查看測試報告
# 運行測試並生成 HTML 報告
npx playwright test tests/login.spec.ts --reporter=html
# 打開報告
npx playwright show-report
四、核心知識點總結
1. 頁面導航
// 基礎導航
await page.goto('https://sogoodtool.com/#/login');
// 等待頁面加載
await page.waitForLoadState('networkidle');
// 等待導航完成
await page.waitForNavigation();
// 頁面刷新
await page.reload();
// 前進後退
await page.goBack();
await page.goForward();
2. 元素定位(推薦方式)
// 1. getByRole(最推薦)
await page.getByRole('button', { name: '登錄' }).click();
await page.getByRole('textbox', { name: '郵箱' }).fill('test@example.com');
// 2. getByPlaceholder(適用於輸入框)
await page.getByPlaceholder('請輸入郵箱').fill('test@example.com');
await page.getByPlaceholder('請輸入密碼').fill('Test1234');
// 3. getByText(適用於文本)
await expect(page.getByText('密碼錯誤')).toBeVisible();
await expect(page.getByText('用戶不存在')).toBeVisible();
// 4. getByLabel(適用於表單)
await page.getByLabel('郵箱').fill('test@example.com');
await page.getByLabel('記住我').check();
3. 元素交互
// 點擊
await page.getByRole('button', { name: '登錄' }).click();
// 輸入
await page.getByPlaceholder('請輸入郵箱').fill('test@example.com');
// 清空
await page.getByPlaceholder('請輸入郵箱').fill('');
// 選擇下拉框
await page.getByRole('combobox').selectOption('公開訪問');
// 勾選複選框
await page.getByLabel('記住我').check();
// 取消勾選
await page.getByLabel('記住我').uncheck();
// 鍵盤操作
await page.getByPlaceholder('請輸入密碼').press('Enter');
4. 斷言驗證
// URL 驗證
await expect(page).toHaveURL(/dashboard/);
await expect(page).toHaveURL('https://sogoodtool.com/#/dashboard');
// 標題驗證
await expect(page).toHaveTitle(/登錄/);
// 可見性驗證
await expect(page.getByText('密碼錯誤')).toBeVisible();
await expect(page.getByText('登錄成功')).toBeHidden();
// 文本驗證
await expect(page.getByRole('heading')).toHaveText('歡迎回來');
// 包含驗證
await expect(page.locator('.error-message')).toContainText('錯誤');
// 屬性驗證
await expect(page.getByRole('button', { name: '登錄' })).toBeEnabled();
await expect(page.getByRole('button', { name: '登錄' })).toBeDisabled();
5. 等待機制
// 等待元素可見
await page.getByText('登錄成功').waitFor();
// 等待指定時間(不推薦,但調試時有用)
await page.waitForTimeout(1000);
// 等待網絡請求
await page.waitForResponse('**/api/login');
// 等待導航
await page.waitForNavigation();
// 等待頁面加載狀態
await page.waitForLoadState('load'); // 等待 load 事件
await page.waitForLoadState('domcontentloaded'); // 等待 DOM 加載
await page.waitForLoadState('networkidle'); // 等待網絡空閒(推薦)
五、下一篇預告
恭喜你!現在你已經學會了 如何寫第一個 Playwright 自動化測試。
下一篇文章,我將帶你解決一個更實際的問題:
【AI 測試 Skill 進階篇】03 | 健壯元素定位:UI 變更時測試不崩潰的秘訣
在那篇文章中,你將學到:
為什麼 UI 一變,測試就全掛? 什麼是多備選定位器策略? 如何判斷元素是否存在、是否可見? 如何用 playwright-robust-locatorsSkill 編寫健壯的測試?
敬請期待!
六、想更系統地學習?加入知識星球
你想獲得什麼?
今天給大家介紹的 playwright-cli Skill,只是 8 個 Playwright Skill 中的一個。
如果你想:
✅ 獲得 完整的 8 個 Playwright Skill ✅ 學習 playwright-robust-locators(健壯元素定位)✅ 獲得 sogoodtool.com 完整的測試用例 ✅ 有問題可以隨時提問 ✅ 持續學習更多測試乾貨
我推薦的 Skill
我整理了 8 個完整的 Playwright 自動化測試 Skill:
playwright-cli | ||
playwright-robust-locators | ||
playwright-core-features-testing | ||
playwright-positive-negative-testing | ||
playwright-cli-url-docs-to-json-zh | ||
playwright-cli-execute-stop-zh | ||
json-testcase-to-excel-zh | ||
ai-testing-skill |
如何獲取?
這些 Skill 都已經放在我的 「Bigtalk軟件測試進階」 知識星球裏了。
掃描下方二維碼,加入知識星球,即可獲得:
✅ 8 個完整的 Playwright 自動化測試 Skill ✅ sogoodtool.com 完整的測試用例 ✅ 我會在星球裏持續更新更多測試乾貨 ✅ 可以向我提問,我會在星球裏解答

微信掃碼,加入「Bigtalk軟件測試進階」
想轉型 AI 測試工程師?想系統地學習 Playwright 自動化測試?
掃描二維碼,加入知識星球,開始你的進階之路! 🚀
下一篇:《【AI 測試 Skill 進階篇】03 | 健壯元素定位:UI 變更時測試不崩潰的秘訣》,敬請期待!