iT邦幫忙

2026 iThome 鐵人賽

DAY 4
0
Modern Web

別再讓 Agent 猜按鈕:30 天打造並實測 Agent-ready 的 WebMCP 活動網站系列 第 4

Day 04|四行 Playwright,藏著哪些畫面依賴?

  • 分享至 

  • xImage
  •  

Day 04|四行 Playwright,藏著哪些畫面依賴?

昨天我用表單找出「台北、免費、入門」的活動。今天我把相同流程改寫成
Playwright,原本幾秒鐘完成的動作,立刻被拆成網址、欄位、按鈕與成功條件。

人類看到表單就知道該填哪裡;Playwright 不會自己理解「幫我找活動」這句話。
工程師必須先替它寫好每一步。它擅長的是忠實重播劇本,而這正好讓我看清楚 Browser
Automation 到底依賴哪些畫面線索。

本系列使用的 Locator Lab 保留在:

/labs/day-04-playwright-locator/index.html

四行操作寫下四個前提

目前的成功案例是:

test("the original accessible-name locator performs the search", async ({ page }) => {
  await page.goto("/labs/day-04-playwright-locator/index.html");
  await page.getByLabel("關鍵字").fill("WebMCP");
  await page.getByRole("button", { name: "搜尋活動" }).click();
  await expect(page.getByRole("status"))
    .toContainText("人類操作已完成:1 場");
});

它做了四件很具體的事:

  1. 開啟固定 Lab。
  2. <label> 找到輸入欄,填入 WebMCP
  3. button role 與 accessible name 找到「搜尋活動」。
  4. 確認 status 顯示一場結果。

Playwright 官方 Locator 文件建議優先使用
面向使用者的屬性與明確契約。getByRole() 會依 ARIA role、屬性與 accessible
name 找元素;getByLabel() 適合表單欄位。這比用畫面座標點擊更接近使用者與
輔助技術理解頁面的方式。

accessible name 不一定等於肉眼看到的文字。瀏覽器會依元素內容、aria-label
aria-labelledby 與關聯 <label> 計算名稱。這也是為什麼「DOM 裡確實有一顆
button」仍不足以讓 getByRole() 成功:role 要符合,計算後的名稱也要符合。

Playwright 依 accessible name 成功完成搜尋

圖 1:Locator、目前 DOM 與可見結果放在同一張實測畫面中。這是 E2 browser test,不是 Agent trace。

我在按鈕外多包一層,兩種 Locator 走向不同結果

getByRole("button", { name: "搜尋活動" }) 同時寫下兩個契約:元素仍是按鈕,
而且使用者感知到的名稱仍是「搜尋活動」。產品若要求這段文案不可改,測試對名稱
敏感很合理。

Lab 還有另一個變體:

/labs/day-04-playwright-locator/index.html?variant=wrapped

它只在按鈕外面新增 .action-shell。role 與 accessible name 沒變,原本的
getByRole() 仍然成功;直接子元素 selector #search-form > button 卻會找不到。

Locator 的選擇,決定測試要保護哪一層。CSS selector 保護 DOM 關係,role locator
保護使用者可感知的語意。該選哪一個,要看這支測試想保護什麼,不能只比長短。

Locator 依賴的線索 介面改動後可能發生什麼
getByRole('button', { name }) role 與 accessible name 改文案會失敗,外層包裝通常不影響
getByLabel('關鍵字') label 與表單控制項關聯 移除 label 或改名稱會失敗
#search-form > button 固定父子 DOM 結構 多包一層元素就失敗
[data-action='search-events'] 團隊定義的穩定屬性 UI 可改,但團隊必須維護這份契約

Playwright 不是在測試開始時找到元素後就永遠抓著同一個節點。Locator 每次操作會
重新查詢當下 DOM,也有 auto-wait 與 retry。這能處理正常的非同步 render,卻不能
替工程師猜出「探索場次」是否等同原本的「搜尋活動」。

我怎麼重播這個實驗

  1. 啟動專案:

    npm run dev
    
  2. 開啟原始 Lab,手動搜尋一次:

    http://127.0.0.1:5173/labs/day-04-playwright-locator/index.html
    
  3. 執行 focused spec:

    npx playwright test tests/browser/reader-facing-labs.spec.ts --grep "Day 4" --reporter=line
    

本次結果是 4 passed。前兩題驗證原始 accessible-name Locator 與 DOM wrapper;
後兩題會在案例內刻意捕捉 timeout,再以正確 Locator 完成復原,因此整份 spec
仍是綠燈。

成功斷言也值得看。測試沒有停在「click 沒丟例外」,而是等待 role="status" 顯示
「人類操作已完成:1 場」。若按鈕存在卻沒有接上 submit handler,click 仍可能
成功,結果斷言會把這個問題攔下來。操作與可見結果必須一起驗收。

若要逐步看瀏覽器操作,可加上:

npx playwright test tests/browser/reader-facing-labs.spec.ts --grep "Day 4" --debug --workers=1

Playwright 也能保存 trace,讓工程師在失敗後檢查 action、DOM snapshot 與錯誤。
Trace Viewer 官方文件提供
npx playwright show-trace <trace.zip> 的開啟方式。

這也是它比手動截一張成功畫面更有用的地方。trace 能回答當時用了哪個 Locator、
頁面上有哪些節點、等待花了多久,以及錯誤發生在操作前還是操作後。Day 5 會用同一
種資訊判斷「網站壞掉」和「舊名稱找不到」的差別。

這次成功證明的是 UI 劇本,不是 Agent 理解

Browser Automation 沒有過時,也不會被 WebMCP 趕走。它負責驗證真實 UI 是否
仍能被人使用;WebMCP 則讓網站另外描述任務能力。前者知道工程師寫好的操作順序,
後者仍需要 Agent 判斷何時選擇哪個 Tool。

接著我會故意只改一個地方:把按鈕從「搜尋活動」換成「探索場次」。功能、資料與
submit handler 全部不動,再看今天這支成功腳本會在哪裡停下來。


上一篇
Day 03|我先把 Inspector 關掉,自己走一次活動網站
系列文
別再讓 Agent 猜按鈕:30 天打造並實測 Agent-ready 的 WebMCP 活動網站4
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言