前面二十六篇裡,Claude Code 其實看不到你的網站。它是靠你的描述,猜出來要點哪裡。
這一篇要裝的東西叫 Playwright MCP,裝好之後,它可以自己打開瀏覽器、自己看那一頁長什麼樣子、自己點。
整篇是一條動線,八個練習從頭做到尾。每個練習需要的設定檔、指令、清單,都放在那一段裡,你不用翻來翻去。
不會寫程式也做得完。每一段程式碼後面都有白話說明。
先講一個場景。你要 Claude Code 幫你寫「匯出訂單報表」的測試,你打字告訴它:「點訂單頁右上角那個匯出按鈕」。
它沒看過你的訂單頁。它只能從你的描述去猜那顆按鈕在程式碼裡叫什麼名字。猜錯了,測試跑不動,你再回頭改一次。
裝上 Playwright MCP 之後,它會先打開那一頁,看清楚有哪些東西,再照著看到的寫。
手變得更能幹了;腦,還是你。這句話這一篇會反覆出現,因為它是這篇的重點。
先理解:它到底看到了什麼
很多人以為 AI 是「看螢幕截圖」。Playwright MCP 不是這樣做的,這個差別很重要。
它拿到的是一份文字清單,類似這樣:
這一頁上有:
標題 「訂單管理」
輸入框 「起始日期」
輸入框 「結束日期」
按鈕 「匯出報表」
表格 「訂單清單」
這份清單其實就是螢幕閱讀器唸給視障使用者聽的那份內容。每個元件是什麼類型、叫什麼名字,寫得清清楚楚。
這樣做有三個好處。第一,AI 不用看圖猜。第二,寫出來的測試比較耐改版——它抓的是「名字叫匯出報表的按鈕」,不是「畫面上第三個藍色方塊」,工程師改了顏色、換了版面,測試照樣跑得動。
第三個好處是意外的:它順帶會照出無障礙的問題。如果畫面上有個看起來是按鈕的東西,但在清單上沒出現,或者名字是空白,那代表這個元件的無障礙標記沒做好,螢幕閱讀器也讀不到它。這是產品的缺口,值得開一張單。
練習 1 把 MCP 裝起來,順便架好圍籬 (約 20 分鐘)
如果你平常不碰終端機,找一位工程師陪你做這一次,之後就都是你自己用了。
為什麼安裝和安全要放在同一個練習
因為那道圍籬就寫在安裝的設定檔裡。先裝好再補設定,中間那段時間 AI 是可以連到任何網站的。
一次做完,不留空窗。
步驟 1-1 安裝套件
在專案資料夾裡打這兩行:
npm install --save-dev @playwright/mcp @playwright/test
npx playwright install --with-deps
兩行都有 install,但拿的東西完全不同。這是最容易誤會的地方,拆開講一下。
第一行:拿 JavaScript 套件。
跑完會發生三件事:套件下載到 node_modules 資料夾、版本號記進 package.json、精確版本鎖進 package-lock.json。
那個 @ 開頭有實際的安全意義。@playwright/mcp 一定是官方發的,但 playwright-mcp(沒有 @)任何人都能註冊,這是套件生態常見的仿冒手法。複製指令的時候別把 @ 弄丟了。
第二行:拿瀏覽器。
--with-deps 主要是給 Linux 和 CI 環境用的,因為乾淨的 Linux 機器通常缺那些系統套件。在 Linux 上它會呼叫 apt-get,可能會要你輸入密碼。Mac 和 Windows 加了也無妨,只是通常用不到。
步驟 1-2 先想清楚圍籬要圍在哪
下一步要填一個網址,填之前先看這張圖:
等一下設定檔裡要填的,就是圖左邊那個「只准連測試網站的網址」。
這份講義全程只在 https://demo.playwright.dev 上練習,所以圍籬就先圍著它一個。設定檔已經幫你填好,這一步不用改東西。
但這個習慣要現在養成。等你哪天把它指向公司的系統,這一行就是唯一擋在中間的東西——那時候才回頭補,中間那段時間 AI 是可以連到任何網站的。
步驟 1-3 建立設定檔
要建立的檔案叫 .mcp.json,前面那個點要留著,而且要放在專案的最外層資料夾。
確認好位置之後,把下面這段整段複製進去:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"-y",
"@playwright/mcp@0.0.78",
"--browser=chromium",
"--isolated",
"--caps=testing",
"--allowed-origins=https://demo.playwright.dev",
"--output-dir=./artifacts/playwright-mcp"
]
}
}
}
這份設定整段複製就好,一個字都不用改
allowed-origins 那一行填的是官方練習站,八個練習都在那裡做。
之後要接你們自己的系統,改的就是這一行。最後一節會講。
這個檔案放在專案裡,團隊每個人抓下來就是同一套設定,不會有人裝的跟別人不一樣。
那幾行各自在做什麼,列在下面。不用背,知道有這回事就好:
步驟 1-4 把截圖資料夾排除在版本控制外
在 .gitignore 加一行。截圖裡可能有測試資料,不要進 git:
artifacts/
✓ 你應該看到
在終端機打 ls -a 看得到 .mcp.json,而且它跟 package.json 在同一層。
檔名前面有點,不是 mcp.json。
同一層也有 CLAUDE.md,裡面是那七條規則。
.gitignore 裡有 artifacts/ 這一行。
步驟 1-5 把規則寫進 CLAUDE.md
CLAUDE.md 是第 24 篇講過的那個檔案,跟 .mcp.json 放同一層。設定檔那道是「機器擋」,這份是「講給 AI 聽」,兩層都要。整段複製:
## 瀏覽器自動化規則
- Playwright MCP 只能連 https://demo.playwright.dev
- 不可以使用正式環境的帳號密碼
- 不可以執行會寄信、扣款、通知客戶的流程
- 每個動作後要重新讀一次畫面,不重複用上一輪的編號
- 產出的測試檔不可以出現 e5、e12 這種臨時編號
- 網址走專案的共用設定,不要硬寫在測試檔裡
- 產出後要自己跑一次 npx playwright test,並回報結果
在練習站上,第二條和第三條看起來是多餘的。還是先寫著。等你接上真的系統,這兩條會變成最重要的兩條,而那時候你不會想要才開始想這件事。
圍籬只是第一層
官方文件自己寫得很清楚:Playwright MCP 本身不是安全機制。--allowed-origins 是降低誤觸的機率,不是保證。
真正的保險是那個測試帳號本來就碰不到正式資料。這件事要在權限那一層處理,不是在設定檔裡拜託它。
練習 2 讓它第一次讀畫面 (約 10 分鐘)
這個練習只做一件事:確認它真的看得到,而且你看得懂它回給你的東西。
步驟 2-1 啟動並下指令
在專案資料夾打 claude 啟動,然後把這句話丟給它:
用 Playwright MCP 打開 https://demo.playwright.dev/todomvc,讀一次這一頁,告訴我上面有哪些可以操作的東西。
步驟 2-2 讀懂它的回答
它會回你類似這樣的東西:
這一頁上有:
標題 「todos」
輸入框 「What needs to be done?」
(目前清單是空的)
把這段跟你自己在瀏覽器打開那一頁看到的畫面對一下。它講的東西,你在畫面上都找得到嗎?
第一次看到它真的把畫面內容唸出來,體感會有點震撼。它是真的看得到了。
✓ 你應該看到
它列出來的東西,跟你在瀏覽器裡看到的畫面對得起來。
它有提到那個輸入框,提示文字是 What needs to be done?。
如果它說「我沒有 Playwright MCP 這個工具」
回到練習 1,先確認 .mcp.json 放在你啟動 claude 的那個資料夾裡,不是放在子資料夾。
還是不行的話,用 claude --debug 啟動,開場會印出載入 MCP 的錯誤訊息。
做練習 3 之前:先理解節奏
接下來要讓它走一整個流程了。在那之前,有一個節奏要先講,不然它會一路點下去都不檢查。
要求它按這個節奏走:先讀一次畫面,做一個動作,然後講出「我預期會看到什麼」,再回頭讀一次畫面。
為什麼「檢查」這一步不能省
點了「送出」,只證明這個點擊的動作有發生。它不證明訂單真的建立了,也不證明畫面有沒有跳出錯誤訊息。
要有人把「我預期會看到『訂單已建立』這幾個字」講出來,這一輪才算是測試。
AI 很容易一路點下去都不檢查,因為它不會覺得哪裡怪。這件事只有你會在意。
它會用到的五個檢查工具
設定檔裡那行 --caps=testing 打開之後,AI 會多五個工具可以用。你不用去呼叫它們,但看得懂它在用哪一個,就知道它檢查得夠不夠仔細:

這五個是精選,不是全部。遇到它們表達不了的檢查——例如「這顆按鈕應該是灰的、不能點」——不要讓 AI 硬湊,叫它在測試檔裡用一般的寫法處理。
練習 3 帶它走一次完整流程 (約 25 分鐘)
這個練習還不產測試檔,先確認它會用對節奏。
步驟 3-1 下這一段指令
用 Playwright MCP 在 https://demo.playwright.dev/todomvc 上操作,先不要寫任何程式碼。
流程:新增一筆「買菜」、勾選完成、切到 Completed 篩選。
規則:每做完一個動作,重新讀一次畫面,不要重複用上一輪的編號。
每一步都要用 browser_verify_* 講出你預期會看到什麼。至少要有:新增後看得到「買菜」、勾選後剩餘數量變成 0 items left。
最後把每一步的截圖給我。
步驟 3-2 盯著它做,看這兩件事
過程大概長這樣。左邊是它做的動作,右邊是白話翻譯:
打開 todomvc 網頁
讀一次畫面 → 看到「What needs to be done?」輸入框
輸入「買菜」並按 Enter
檢查:「買菜」有沒有出現在畫面上 ✓
重新讀一次畫面 → 多出一個勾選框,還有「1 item left」
點那個勾選框
檢查:有沒有變成「0 items left」 ✓
你要盯的就兩件事:
• 每個動作後面,有沒有「重新讀一次畫面」?少了這個,它可能拿著過期的編號在點。
• 每個動作後面,有沒有跟著一句「檢查」?少了這個,那一步就白做了。
看到它連續三四步都沒重新讀畫面,直接打斷它,叫它重讀一次再繼續。
✓ 你應該看到
它走完了三個動作,而且每個動作後面都有一次重讀畫面。
至少有兩句明確的檢查,不是只有操作。
你拿到了幾張截圖,可以自己核對它說的是不是真的。
做練習 4 之前:三種東西,只有一種能留下來
這是最多人踩的坑,所以在產測試檔之前先講。
e12 這種編號,絕對不能出現在測試檔裡
AI 讀畫面的時候,會給每個元件一個臨時編號,像 e5、e12。它用這個編號記「我現在指的是哪一個」。
這個編號只在當下那一秒有效。頁面多插一列、跳轉一次,e12 可能就變成別的東西了。
練習 5 的第一條檢查,就是搜尋這個。
正確的做法是,讓 AI 把看到的元件轉成有名字的寫法:
它看到的臨時編號: e12
轉成測試用的寫法:
page.getByRole('button', { name: '匯出報表' })
白話講就是:「請點那顆名字叫『匯出報表』的按鈕」
轉出來還是草稿,不是定案。你要看三件事:這個名字在這一頁上是唯一的嗎?這個名字是使用者看得到的嗎?這段文案是不是 PM 每個月都在改?
第三個問題如果答「是」,就要換一種寫法,不然文案一改測試就紅了。
練習 4 把觀察變成一支測試檔 (約 20 分鐘)
練習 3 是口頭走一遍,這一次要它留下檔案。
步驟 4-1 用五段式指令
這是這篇最重要的一段。整段複製過去就能用:
用 Playwright MCP 打開 https://demo.playwright.dev/todomvc。
【探索】先讀一次畫面,列出所有可以操作的東西(類型和名字),還有你觀察到的頁面結構。這一步先不要寫任何程式碼。
【確認】接著實際操作一次:新增一筆「買菜」、勾選完成、切到 Completed 篩選。每做完一個動作,重新讀一次畫面,不要重複用上一輪的編號。
【檢查】每一步都要講出你預期會看到什麼。至少要有:新增後看得到「買菜」、勾選後剩餘數量變成 0 items left。
【產出】把觀察到的元件轉成有名字的寫法,組成一個測試檔 tests/todo/basic-flow.spec.ts。檔案裡不准出現 e5、e12 這種臨時編號,網址走專案的共用設定。
【留證】把你操作過程的截圖給我,並且說明每一行檢查對應到你觀察到的哪一個現象。
五段的用意各不相同:
• 探索段——讓你在它動手之前先看一眼方向對不對。
• 確認段——逼它走真實流程,而不是憑印象亂寫。
• 檢查段——確保每個動作後面都有一句「我預期看到什麼」。
• 產出段——把臨時編號擋在門外。
• 留證段——你不用瞎信它宣稱的觀察,可以自己看截圖對。
步驟 4-2 看它產出的檔案
打開 tests/todo/basic-flow.spec.ts,大概長這樣:
import { test, expect } from '@playwright/test';
test('新增待辦後勾選完成,剩餘數量歸零', async ({ page }) => {
await page.goto('/todomvc');
const 輸入框 = page.getByPlaceholder('What needs to be done?');
await 輸入框.fill('買菜');
await 輸入框.press('Enter');
await expect(page.getByText('買菜')).toBeVisible();
await expect(page.getByText('1 item left')).toBeVisible();
await page.getByRole('checkbox', { name: 'Toggle Todo' }).click();
await expect(page.getByText('0 items left')).toBeVisible();
});
逐行對照:
看得懂這張表,你就有能力審查 AI 產出的測試了。
✓ 你應該看到
tests/todo/ 底下真的有一個 .spec.ts 檔案。
檔案裡看得到 test、expect 這些字。
你看得懂它每一行大概在做什麼。
練習 5 自己跑一次,並且審過 (約 25 分鐘)
AI 說它跑過了,不算。這一步要你自己跑,自己審。
步驟 5-1 跑起來
npx playwright test tests/todo/basic-flow.spec.ts --headed
加了 --headed 會把瀏覽器叫出來給你看,適合第一次跑的時候確認它到底在做什麼。
如果紅了,先別急著叫 AI 重產。往下看步驟 5-3。
步驟 5-2 用清單審一遍
打開那個測試檔,逐條打勾。第一組你自己就能查:
☐ 搜尋檔案裡有沒有 e5、e12 這種臨時編號。有的話,退回去叫它重寫。
☐ 數一數:有幾個動作、幾個 expect?動作一堆卻只有一個 expect,代表檢查不夠。
☐ 測試的名字在講「什麼行為」,還是在講「第一步第二步」?後者要改。
☐ 檢查的內容是重要的事嗎?驗「訂單總金額」有意義,驗「頁尾的版權宣告」沒意義。
☐ 有沒有帳號密碼被直接寫在檔案裡?有的話一定要拿掉。
第二組請工程師幫你看一次:
☐ 網址是走專案共用的設定,還是硬寫在檔案裡?
☐ 測試用的資料是自己造的,還是依賴環境裡剛好存在的東西?
☐ 跑完之後,資料有沒有清乾淨?會不會影響下一支測試?
☐ 這支測試在 CI 上跑得起來嗎?
步驟 5-3 如果紅了,先查原因
不要靠「叫它重產」來把紅燈變綠
測試失敗的時候,先搞清楚原因:是導頁錯了?載入太慢?文案改了?還是真的有 bug?
一直叫 AI 換個寫法直到變綠,等於是把一個有意義的失敗,換成一個沒意義的檢查。
同樣的,測試偶爾會紅偶爾會綠的時候,第一反應也不該是把等待時間拉長。
✓ 你應該看到
測試跑出綠燈。
十條清單你都逐條看過,而且知道每一條在問什麼。
記下來:它第一次產出通過了幾條?這個數字下次可以拿來比。
練習 6 故意改壞,確認它抓得到 (約 20 分鐘)
綠燈只代表「這支測試沒有報錯」,不代表「它有在檢查東西」。這一步驗的是後者。
這是第 26 篇講過的突變驗證,在 MCP 產出的測試上更不能省——因為它的檢查點是它自己推測的。
步驟 6-1 挑一個地方改壞
在 TodoMVC 上不好改原始碼,所以這裡換個方式:直接改測試檔裡的預期值,看它會不會紅。
把這一行:
await expect(page.getByText('0 items left')).toBeVisible();
改成:
await expect(page.getByText('5 items left')).toBeVisible();
再跑一次。它應該要紅。
步驟 6-2 想清楚這代表什麼
如果改成一個明顯錯的預期值,測試還是綠的,那代表這一行根本沒在檢查東西——常見原因是那段文字在畫面上根本不存在,而 Playwright 的某些寫法在找不到的時候不會報錯。
改完記得改回來。
練習站的原始碼不在你手上,所以只能這樣代打。等你在自己的系統上跑的時候,做法就是直接的:把產品程式碼故意改壞一處(例如把計算金額的加號改成減號),看這支測試會不會紅。不會紅,那它就是在陪跑。
✓ 你應該看到
改壞之後測試變紅,改回來之後變綠。
你知道了「綠燈」和「有在檢查」是兩件事。
練習 7 拿它做功能盤點 (約 30 分鐘)
前面六個練習,測的都是你自己指定的那個流程。這一次換個用法:讓它把整個系統有哪些功能盤出來,再回頭看你測到了多少。
這個用法很多人沒想到,但做規劃的時候特別好用。
步驟 7-1 叫它盤點,不要叫它寫測試
用 Playwright MCP 探索 https://demo.playwright.dev/todomvc。
不要寫測試,只要盤點。請你:
1. 讀一次畫面,列出所有可以操作的元件。
2. 每一個都實際操作看看,包括那些一開始不明顯的——例如清單有項目之後才出現的東西、滑鼠移過去才冒出來的東西、要按兩下才會有反應的東西。
3. 試試看網址列上的 #/active、#/completed 會發生什麼事。
輸出成一份表格,欄位是:功能名稱、怎麼觸發、預期行為、什麼情況下才看得到這個功能。
第二點是這段指令的重點。只讀一次畫面,它只會看到那個輸入框——因為清單是空的,其他東西都還沒出現。要它動手操作,藏起來的功能才會冒出來。
步驟 7-2 自己也開一個瀏覽器對一遍
這一步不要跳過。你自己打開 TodoMVC 玩五分鐘,把你找到的功能列一張表,再跟它的表比。
可以往這幾個方向找,它們都是「畫面上沒有明顯按鈕、但功能存在」的那一類:
• 待辦項目本身可不可以修改?怎麼進入修改狀態?
• 修改到一半反悔,有辦法取消嗎?
• 全部標記完成,有沒有一次做完的方法?
• 已完成的項目,有沒有辦法一次清掉?
• 重新整理頁面之後,資料還在嗎?
• 三個篩選之間切換,瀏覽器的上一頁按鈕會怎麼反應?
對完之後你會有兩張清單的差集:它找到而你沒想到的,以及你找到而它漏掉的。兩邊都值得記下來。
步驟 7-3 對照練習 4 產出的測試
打開練習 4 那個測試檔,拿盤點表逐項對:這個功能,測試裡有對應的檢查嗎?
沒有的,在表格上打個記號。你會發現一支測試檔涵蓋到的,大概只有整張表的兩三成。
這件事本身不是問題——沒有人期待一支測試涵蓋全部。有價值的是那張表:它讓「涵蓋不夠」從一句感覺,變成一份看得到的清單。
回到公司之後,同樣的做法可以直接套在你們的系統上。這份清單拿去跟主管談測試資源,比口頭說「我們涵蓋不夠」有說服力得多。
✓ 你應該看到
你有一份 TodoMVC 的功能盤點表,而且比你一開始想的長。
表上標出了哪些功能在練習 4 的測試裡沒有對應的檢查。
你知道了「叫它讀畫面」和「叫它動手探索」拿到的結果差很多。
練習 8 找出三條它猜不到的規則 (約 30 分鐘)
這是最後一個練習,也是整篇最重要的一個。前面七個都在練「怎麼讓它做得更好」,這一個在練「它做不到什麼」。
步驟 8-1 自己動手找三條規則
回到 TodoMVC,這次不要叫 AI 做任何事。你自己玩,找出三條「光看畫面看不出來、要動手試才知道」的規則。
幾個可以試的方向:
• 輸入框裡什麼都不打就按 Enter,會發生什麼?
• 只打幾個空白鍵再按 Enter 呢?
• 打「 買菜 」前後各留幾個空白,存進去之後那些空白還在嗎?
• 新增很多筆之後,新的那一筆會排在最上面還是最下面?
• 只剩一筆的時候,計數的文字跟有兩筆的時候寫法一樣嗎?
• 修改一筆待辦,把內容全部刪光再離開,那一筆會怎樣?
把你找到的三條寫下來,寫成一句話的規則。例如:「輸入內容前後的空白會被自動去掉」。
步驟 8-2 叫 AI 針對這三條寫測試
用 Playwright MCP 在 https://demo.playwright.dev/todomvc 上,針對下面三條規則各寫一支測試,加進 tests/todo/rules.spec.ts:
1. [你找到的第一條規則]
2. [第二條]
3. [第三條]
每一條都要實際操作驗證過再寫。不准出現 e5、e12 這種臨時編號。寫完自己跑一次,回報結果。
注意這次的差別:規則是你給的,它負責把規則翻譯成測試。這才是這個工具最穩的用法。
步驟 8-3 想清楚剛剛發生了什麼
回頭看練習 4。那一次,是你給它流程、它自己決定要檢查什麼——它檢查的是「畫面上有沒有出現買菜」這種它從畫面推得出來的事。
剛剛這一次,檢查點是你定的。它猜不到「前後空白要去掉」是刻意設計還是 bug,因為畫面上看不出來。
TodoMVC 只是個小玩具,規則已經藏得這麼深了。換成你們的系統,它猜不到的東西通常是這幾類:
• 哪些欄位是法規要求必填的。
• 金額誤差到什麼程度算不能接受。
• 哪個看起來多餘的舊流程,其實是為了某個大客戶保留的。
• 哪一個錯誤訊息的用詞是法務審過的,不能改。
這些只有你知道。你的價值在這裡,不在打字速度。
還有一層 UI 測試天生驗不到的:畫面出現「訂單已建立」,不代表資料庫真的寫進去了,也不代表通知信真的寄出去了。那些要在別的層次各自驗。
✓ 你應該看到
你手上有三條自己找出來的規則,寫成了一句話。
tests/todo/rules.spec.ts 跑得起來,三支測試都綠。
你講得出來:哪些檢查點 AI 自己推得出來,哪些一定要人給。
做完之後:MCP 不是唯一解
八個練習做完,你已經有能力判斷它產出的東西了。最後補一個定位問題。
Playwright 從 1.56 版開始內建 Test Agents,分成規劃、產生、修復三個角色。要一次產很多測試、或者要它去修 CI 上壞掉的測試,用這個比用 MCP 一頁一頁探索省力。
成本也是現實考量。有分析指出,在達成差不多涵蓋的前提下,MCP 這條路消耗的 token 大約是其他做法的四倍——因為每讀一次畫面,那份清單就實打實地進了對話。
所以比較務實的組合是:MCP 用在你不確定那一頁長怎樣的時候,探索一次、產出測試檔,之後這支測試就是一般的測試,交給 CI 跑。不要讓每一個點擊都繞過 AI。