Back to skills
SKILL.md
Browser Qa
ASecurity瀏覽器功能測試方法論。當要對某功能 / 頁面 / 流程做功能測試時觸發——含「開發完成需驗證新互動 / 新畫面 / 新流程」, 也含使用者說「執行 / 跑 / 做 一些測試案例」、「幫我測這個功能」、「跑 e2e / 端對端測試」、「回歸測試」、 「測試落地 / 沉澱測試 / 存測試案例」等意圖(這些都指「設計並執行功能測試、沉澱成可重跑 runner」,不是單純跑一支既有腳本)。
- 2 stars
- 0 votes
- 0 copies
- 0 views
- Added September 3, 2026
Works with
Security analysis
100/100Pro scans all 5 files and shows the line behind each finding
npx -y skills add abs1294/fulin-claude-plugins --skill browser-qa --agent claude-codeAre you the author of Browser Qa?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/abs1294-browser-qa)---
name: browser-qa
description: >
瀏覽器功能測試方法論。當要對某功能 / 頁面 / 流程做功能測試時觸發——含「開發完成需驗證新互動 / 新畫面 / 新流程」,
也含使用者說「執行 / 跑 / 做 一些測試案例」、「幫我測這個功能」、「跑 e2e / 端對端測試」、「回歸測試」、
「測試落地 / 沉澱測試 / 存測試案例」等意圖(這些都指「設計並執行功能測試、沉澱成可重跑 runner」,不是單純跑一支既有腳本)。
---
# Browser QA Skill
兩階段皆由 QA agent(qa-engineer)一手包:設計測試計畫(含 critical points)→ 預擬 codify 草稿
(grep 原始碼填真實值)→ 首跑收失敗清單 → 只對失敗 CP 定向探索補值,以結構化證據
(API 碼 / DOM 讀回 / 來源 readback)自我驗證並輸出測試報告;主 Agent 只派工收結論、不親跑 MCP。
> **機械保證的邊界(先讀)**:本 skill 分兩層——
> **產物層**(每個功能在 `tests/e2e/` 留下可重跑的 `test_*.py` + junitxml 報告 + 情境登記〔三層:`<模組>/COVERAGE.md`;舊版:catalog〕)由 `qa-flow.sh` 強制。Stop hook 與 `project-knowledge-gate` 只在 qa-webwright plugin 已啟用的專案生效;只以 symlink 取用本 skill 時這兩道閘不存在,完成判準改由下方執行清單的 #5、#8 自行對照。
> **設計品質層**(覆蓋矩陣是否窮盡、證據是否夠強、是否真走兩階段 qa-engineer 設計)**無法機械強制**(品質是 AI-complete)——下面的方法論是**強烈建議的流程**,靠引導不靠閘門。
> 所以:產物一定會有,但「測得好不好」需人把關。別把「hook 全綠」當成「測試設計到位」。
把測試計畫的每條「預期結果」對映成一個 **critical point**,再落成可重跑 runner 裡**(至少)一行 `assert`**(雙向卡控等可多行)。
這條設計的好處:測試**寫一次**(探索階段花一次 agent token),之後直接 `pytest`(或對應 runner)跑——
有 assert 就能自動判 pass/fail、無 agent、不花 token、可掛 CI。
> **方法論中立、載體固定優先 pytest(核心原則)**:本 skill 的價值在「測試設計方法論」(覆蓋矩陣 /
> 可追溯 / CP→assert / 必測 checklist / 測試資料原則)。沉澱載體**固定優先 pytest-playwright**——
> **唯二例外**:(a) 目標專案「既有」測試資產就是別的 runner(如既有 Playwright JS 專案)→ 沿用既有、對齊風格;
> (b) greenfield 且**使用者明確不同意**裝 Python 環境 → 退而用 Playwright JS。除此之外一律 pytest,
> **不得因「載體中立」自行選 JS**(歷史踩雷:執行者看到子目錄有 JS 專案就鑽進去出 JS)。
> 判定一律靠**結構化證據**(API 業務碼、DOM/a11y 讀回、來源 readback),**不靠讀截圖**。截圖至多留檔備查。
>
> **落點鎖死**:測試 / 報告 / catalog 一律落在**你起 session 的那個資料夾**底下(`tests/e2e/`),
> **禁止鑽進子專案目錄**。此規範由 `qa-flow.sh`(鎖 `CLAUDE_PROJECT_DIR`)機械執行,見下方「qa-flow.sh 腳本」。
| Phase | 執行者 | 職責 |
|-------|--------|------|
| Phase 1 | QA Agent(本 plugin 的 `qa-engineer` agent) | 設計測試計畫、定義 critical points 與輸出格式 |
| Phase 2 | QA Agent(同一個 `qa-engineer` agent 接續執行) | 預擬草稿(每 CP 一行 assert)→ 首跑收失敗清單 → 定向探索補值 → 結構化證據自驗 → 輸出測試報告 + 回填 catalog |
> 主 Agent(指揮官)不出現在任何 Phase:它只判斷何時該 QA、派 qa-engineer agent(附環境啟動方式 /
> 已知 DOM 坑 / allow-list 前提)、收報告結論,**不親跑 MCP**。實作 agent 不做瀏覽器自驗。
> **allow-list 前提**:qa-engineer 是 sub-agent、無法互動回應 permission prompt——要用的
> `mcp__playwright__browser_*` 工具必須已在專案 `settings.json` / `settings.local.json` 的
> `permissions.allow`,否則會被 deny(跨專案使用本 plugin 時先確認這件事)。
## 派工範本(主 Agent 派 qa-engineer 用)
派 `qa-engineer` 時,派工單(Agent/Task 的 prompt)**照下方範本逐格填寫**。專案 `tests/e2e/qa-webwright.json` 有 `dispatch_gate` 段時,
`hooks/guard-qa-dispatch.js` 會在派工當下檢查這幾格(缺一即 deny,一次列完所有缺項);沒有該段時不檢查,但照填一樣是好派工單。
每一格為什麼要寫:派工單上沒寫的那一格,QA 就不會測、不會問——範圍完整性是指揮官的責任。
| 格 | 閘怎麼驗(只驗有沒有表態,不判內容對錯) |
|---|---|
| 首行回報指示+「本任務由你親自執行,不得再轉派」 | 出現「親自執行/不得再轉派」字樣(回報鏈固定一跳) |
| 【開工前必讀】 | `dispatch_gate.required_reading` 列的路徑都出現在派工單(斜線方向、大小寫不拘;預設只要求專案裡真的存在的檔) |
| 【增量分流】 | 該格第一行明選 `reuse`(附要改的既有 test 檔路徑)或 `新TC`(附一句為何既有案例接不住)——見 Phase 1「增量分流」 |
| 【目標環境】 | 該格不是空白、不是範本佔位(本機預設填一行 localhost 即可) |
| 【測試資料來源】 | 第一行開頭寫「選 a」「選 b」或「選 c」(固定格式,其他寫法不算表態);理由與證據只讀「作答段」(第一行起到空行,或到 a./b./c./(/⛔ 開頭的說明行為止);選 b、c 必附理由。a=走真實業務流程長出來(常態,不論成本)、b=封閉例外(只限產品外部系統產生、產品端沒有入口的前置;理由要點名是哪一類外部系統邊界,並附產品端證據的「檔名:行號」)、c=依賴既有資料(僅限字典/設定類) |
| 【範圍外發現】 | 要求 QA 把範圍外看到的異常列在報告「範圍外發現」節回報 |
| 【開工前對齊】 | 該格寫了對齊結論或「無分岔+理由」(不是空白、不是範本佔位) |
| 【範圍展開】 | 四格都寫到:正向/反向(終止分支)/狀態序列/共用元件;任一格填「無」附理由 |
| 【欄位級驗證】 | 寫出要拿什麼實值比對(DB 讀回/三方對照);「畫面有顯示」「回 200」不算 |
範本(`<…>` 換成實際內容;刪掉角括號):
<!-- qa-dispatch-template:begin -->
```text
完成後把測試報告(含「範圍外發現」節)回報給主對話。本任務由你親自執行,不得再轉派給其他 agent。
【任務】<要測的功能/變更範圍;使用者原話照貼>
【開工前必讀】<照 tests/e2e/qa-webwright.json 的 dispatch_gate.required_reading 逐條列路徑;另外一律寫出 CLAUDE.md(專案概要)、CONTEXT.md(專案用語)、tests/Project_Detail/PROJECT.md,專案沒有的寫「<檔名>:專案沒有這個檔」>
【增量分流】<reuse 或 新TC 擇一寫在最前面>:<reuse 寫要改的既有 test 檔路徑;新TC 寫一句為何既有案例接不住>
【目標環境】<前端網址;後端 API/登入身分來源與預設不同時一併寫>
【測試資料來源】<a、b、c 三選一,寫成「選 X」;a=走真實業務流程長出來(常態,不論成本);b=封閉例外,只限產品外部系統產生、產品端沒有入口的前置(外部簽核回呼/上游推送/外部主檔 mock/目錄服務),理由寫出是哪一類,並附產品端守門或寫入點的「檔名:行號」當證據;c=依賴既有字典/設定類,附理由;理由與證據寫在同一段,空行之後的內容不算>
【開工前對齊】<對齊結論一句話;或「無分岔:<一句理由>」>
【範圍展開】<1 正向:…;2 反向(退件/拒絕/取消/軟刪/逾時/重送/權限不足,逐條列適用與否,不適用說為什麼):…;3 狀態序列(做A→做B→撤銷A→存檔→重開):…;4 共用元件(本次觸及的共用元件與其他使用點是否連帶回歸):…>
【欄位級驗證】<涉及 N 個欄位;逐欄比對畫面顯示值 ↔ API 回傳 ↔ DB 實值;寫入型逐欄讀回 DB(bool/int 用非預設值、集合驗筆數+順序);不驗的欄位逐個列理由>
【範圍外發現】範圍外看到的異常一律列在報告「範圍外發現」節回報,不自行擴大修改、也不當作沒看到。
【驗收條件】browser-qa SKILL.md「執行清單(完成判準)」8 項全過;<本次功能行為條款,逐條可觀察>
【回報格式】已讀清單(逐檔列出實際讀過的開工前必讀檔案,沒讀的寫理由,例如專案沒有這個檔)/測試報告路徑/範圍展開四格逐格結果/範圍外發現/codify 的測試檔與實跑輸出
【執行方式】本任務由你親自執行,不得再轉派。照 browser-qa SKILL.md「執行清單(完成判準)」核對 8 項;每次呼叫 qa-flow.sh 都帶 CLAUDE_PROJECT_DIR=<Primary working directory>。完成後回報主對話。
```
<!-- qa-dispatch-template:end -->
填好的樣子(此例可一次過閘;`hooks/test-gate.mjs` 會拿這段實跑驗證):
<!-- qa-dispatch-example:begin -->
```text
完成後把測試報告(含「範圍外發現」節)回報給主對話。本任務由你親自執行,不得再轉派給其他 agent。
【任務】測 https://shop.example.test 的購物車:加入商品、移除商品、購物車徽章數量、結帳前明細
【開工前必讀】CLAUDE.md(專案概要)、CONTEXT.md、tests/Project_Detail/PROJECT.md
【增量分流】新TC:tests/e2e 還沒有購物車的既有案例(CATALOG 查無),既有案例接不住
【目標環境】https://shop.example.test(公開測試站;帳號用站方公開的測試帳號)
【測試資料來源】選 a,理由:購物車內容由 UI 加入商品自然產生,走真實流程即可
【開工前對齊】無分岔:需求就是驗購物車既有的四個操作,沒有「做成什麼樣」的解讀分岔
【範圍展開】1 正向:加入商品→徽章數量+1→明細列出該商品;2 反向:移除最後一件後徽章消失、明細顯示空狀態;結帳途中取消回到購物車;權限不足不適用(公開站只有一種角色);3 狀態序列:加入 A→加入 B→移除 A→重新整理→確認只剩 B 且數量正確;4 共用元件:購物車徽章也出現在頁首,頁首數字一併驗
【欄位級驗證】明細 4 個欄位(品名/單價/數量/小計)逐欄比對畫面顯示值與購物車資料的實值;公開站查不到 DB,實值以站方回傳的購物車資料為準
【範圍外發現】範圍外看到的異常一律列在報告「範圍外發現」節回報,不自行擴大修改、也不當作沒看到。
【驗收條件】browser-qa SKILL.md「執行清單(完成判準)」8 項全過;四個操作後徽章數量與明細逐欄一致
【回報格式】已讀清單(沒讀的寫理由)/測試報告路徑/範圍展開四格逐格結果/範圍外發現/codify 的測試檔與實跑輸出
【執行方式】本任務由你親自執行,不得再轉派。照 browser-qa SKILL.md「執行清單(完成判準)」核對 8 項;每次呼叫 qa-flow.sh 都帶 CLAUDE_PROJECT_DIR=/path/to/project。完成後回報主對話。
```
<!-- qa-dispatch-example:end -->
被閘擋下時:照 deny 訊息把**所有**列出的缺項一次補齊,重發**同一個** agent;不要改派其他 agent type 繞過。
專案要加檢查(如【開工前對齊】【範圍展開】或自訂 regex)改 `dispatch_gate.checks`/`custom_checks`,範本也要同步加格(加閘沒同步範本=照範本寫仍被擋)。
本 skill 分層維護:
- **方法論** `methodology/` — 怎麼做測試,穩定、不綁技術棧。
- **知識庫** `knowledge/` — 踩過的雷與領域知識,**會長大**、依專案技術棧選用。
---
## 前置(一次性 / 每次)
**一次性(每台開發機):**
- 沉澱 runner **固定優先 pytest-playwright**(例外見上方核心原則)。**不需自己 mkdir / 判斷落點**——
Phase 2 第一步一律先跑 `qa-flow.sh bootstrap`,它會盤點既有資產、發安裝決策訊號、鎖定落點。
- 探索方式優先用專案既有手段(Playwright MCP 的 a11y snapshot `ref`、Page Object)。
**選用(僅「真實外部站」備用探索):**
- 當未來需打**真實外部站**(無法注入 a11y test token、後端不可攔、`ERR_HTTP2_PROTOCOL_ERROR`/Akamai/H2
封鎖 Chromium、長程未知路徑)時,才裝 **webwright**(`/plugin install webwright@webwright` +
`playwright install firefox`,用其 SOTA 自主探索)。**探索完一律 codify 成上述 runner,回歸端永遠不是 webwright。**
(`ERR_HTTP2_PROTOCOL_ERROR`/指紋封鎖的處置見 `knowledge/pitfalls.md` H 段:先換 `playwright.firefox`。)
本機自家系統(有 a11y、有後端可攔)**不需要**裝 webwright。
**每次測試前:**
- **專案 QA 知識層(約定位置)**:`<CLAUDE_PROJECT_DIR>/tests/Project_Detail/`,入口 `PROJECT.md`。
入口是**路由中心、分層負責**:只放專案鐵則與路由表,細節(環境啟動、UI 操作規範、領域驗證知識…)
在同目錄分層檔,照路由**按需讀**、不整包灌。入口存在就**必先讀**(`bootstrap` 會回報 `PROJECT-KNOWLEDGE` 訊號);
不存在而專案有專屬 QA 知識時,建議依此分層建立,別把專案知識寫進泛用 skill。
「必先讀」由機械層執行:`hooks/project-knowledge-gate.js`(PreToolUse)在入口存在而未讀時 deny 瀏覽器呼叫
(最多兩次、FAIL-OPEN),`qa-early-nudge` 同步軟提醒——先軟後硬。
- 目標專案要能在本機跑起來(啟動方式見該專案的 CLAUDE.md / README;Windows 背景啟動雷見 `knowledge/pitfalls.md` D 段)。
---
## Phase 1:設計測試計畫(QA Agent)
### 增量分流(reuse-first,設計前先做)
**設計任何新 TC 之前,先盤點既有測試資產**:專案已有 codified 測試套件時(含索引/情境正本,如 CATALOG、COVERAGE 這類檔案),先查「這次變更落在哪個模組、既有案例的導航與斷言點能不能到達」。二選一表態後才進設計:
- **reuse**:變更落在既有案例的 seam 內(改欄位/驗證規則/顯示邏輯)→ **直接改既有 runner**:加 assert/參數化,只跑受影響案例+同資料夾回歸——不開瀏覽器探索、不寫新 TC。既有腳本已內建登入、導航、seed,邊際成本只剩斷言,且斷言永久留在回歸網。
- **新 TC**:無既有覆蓋/新畫面/新互動、或需視覺判斷(排版、loading、console 紅字)→ 附一句理由(為何既有案例接不住),走完整 Phase 1→2。
一句話判準:**既有腳本能到達並斷言的行為,不重新探索**。新功能的主動探索情境紀律不因此豁免——它管新功能的未知未知,本節管小改的增量。
由 `qa-engineer` agent 負責,依 `methodology/test-plan-design.md` 設計,**輸出一律用固定的單一 TC 表**
(每列一條 TC,欄位:TC / 功能情境 / 操作步驟 / 證據 / 預期結果 / 需求;格式詳見 `qa-engineer` agent 的「輸出」段):
- **內部設計動作(不寫進輸出)**:窮舉覆蓋矩陣(狀態維度)確保每維度有 TC、大型功能做一次紅隊漏測複查補漏——
補出來的 TC 直接併進表,矩陣與複查過程不另立段落。
- **可追溯**:每條驗收條件 / 需求點對應到表的「需求」欄;不測的另列寫「不測 + 理由」。
**關鍵交接規則**:每條 TC 的每個「預期結果」都要寫成「可由其結構化證據獨立驗證」的形式
—— 這就是 Phase 2 要列成的 critical point 清單、再落成 runner 的 assert。
詳見 `methodology/critical-points.md`。
---
## Phase 2:執行測試(QA Agent)
QA Agent(qa-engineer,接續 Phase 1 由自己執行)嚴格按測試計畫執行,不得自行增減步驟。流程是「**預擬 codify 草稿 → 首跑收失敗清單 → 只對失敗 CP 定向探索補值**」(draft-first:探索是補洞手段,不是起手式)。
### 執行清單(完成判準)
沉澱成可重跑的 runner 是本 skill 的目的,不要問要不要做;唯一要問的是 greenfield 時同不同意在這台電腦裝 pytest-playwright。
### 髒資料紀律(造資料的測試必守)
- **可識別**:測試造的業務資料(單據、名稱、標題類欄位)一律帶專案約定的測試前綴(無約定時用 `E2E-`)——含瀏覽器探索階段造的資料,殘留才能被機械定位。
- **自種自清**:造資料的 runner 必配 fixture teardown(`yield` 後清理,失敗也會執行)。「跑完整生命週期到終態」是首選(終態路徑本身有測試價值),但它扛不住測試中途失敗——teardown 是兜底,兩者並用。
- **收尾清掃**:大批執行結束後,用專案的殘留清掃工具(或按前綴查詢)確認無測試殘留,才算收工。
- **只刪自己造的**:teardown 用 `SCOPE_IDENTITY`/唯一前綴鎖定自己造的那幾筆,**不要 UPDATE 回原值**——那會把別人的資料改壞。
### ⭐ 五條硬規則:測試不得依賴環境既有資料(寫 assert 前必讀)
判準一句話:**把業務資料清空、只留 schema 與字典,這支測試仍該能跑通**。
① **前提資料自己生,走產品入口**(不寫死既有 Id/代碼;直接 INSERT 造出的形狀產品永遠不會產生)
② **期望值查來源推導,且不得抄被測程式那句查詢**(同源=後端錯時測試一起錯)
③ **定位錨語系無關**(產品既有錨 → i18n key 取譯文 → 測試端 setAttribute;⛔ 不得在產品碼埋測試專用屬性)
④ **沒資料不准 skip 要自己生**(A 資料缺→自造/B 環境→具名 skipif/C 結構變→改 fail/D 共用狀態被佔或前置沒做成功→改 fail;執行期 A/D 類 skip 由 conftest 掛點判整輪失敗)
⑤ **驗環境看 `response.url`,不信環境變數**(打錯後端=前四條做得再好也整輪作廢)
**五條的完整判準、理由與實測代價見 `methodology/critical-points.md`「五條硬規則」節——寫 CP 與草稿前讀那一節。**
⚠ ③ 特別注意:`assert xxx.get_by_text("送出").count() > 0` **是定位器不是斷言**,切語系一樣失效,別以為有 `assert` 就豁免。
8 項完成判準(可用任務清單工具追蹤進度,非強制;任一 CP self-verify 失敗〔#7〕時回到 #5/#6/#7 重跑):
```
#1 Phase2-0 qa-flow.sh bootstrap(盤點資產 + 鎖落點 + 回報登記模式 MODE)
#2 Phase2-0b 僅 greenfield 空目錄:問使用者「是否同意裝 pytest 環境」(不問要不要沉澱)
#3 Phase2-1 列 critical points 清單
#4 Phase2-2 預擬 codify 草稿:每 CP 先落 pytest assert(grep 原始碼填真實值,拿不到標 TODO-EXPLORE)
#5 Phase2-3 qa-flow.sh run(防假綠燈 grep + pytest --junitxml;首跑收失敗清單,修完重跑)
#6 Phase2-4 定向探索補值:僅對失敗 / TODO-EXPLORE 的 CP 做 MCP 探索修草稿(≤5 CP 一批,修完回 #5)
#7 Phase2-5 self-verify(逐 CP 對結構化證據 + FAIL 前排除紀律)
#8 Phase2-6 輸出報告 + qa-flow.sh catalog 登記每個情境(三層:<模組>/COVERAGE.md → 重生 CATALOG)+ qa-flow.sh audit 確認 drift 0/0/0
```
- **#5、#8 是硬性落地閘**:沒跑 `qa-flow.sh run` 出報告、沒跑 `qa-flow.sh catalog` 登記,**不得宣稱測試完成**。
三層模式下 **codify 完成判準=drift 0/0/0**(孤兒/幽靈/佔位皆 0;每次 pytest 結束總結區會印 `COVERAGE drift clean` 或 `⚠️ COVERAGE DRIFT`)。
- **假綠燈紀律(draft-first 的代價)**:#4 預擬的 assert 是推測——**禁止為了轉綠而弱化斷言、寫恆真條件、或把 FAIL 的 CP 改成 skip**;失敗 CP 唯一的修法是 #6 探索取真實值。「修到綠就交」不是完成,self-verify(#7)照樣逐 CP 對證據。
### ⚡ qa-flow.sh 腳本(必用)
本 skill 提供 `qa-flow.sh`(位於本 skill 目錄)把「一定要落地的動作」包成 subcommand,落點一律鎖 `CLAUDE_PROJECT_DIR`(session 起始目錄),執行者(QA Agent)**不要自己 mkdir / 自己組 pytest 指令 / 自己判斷落點**。
> **落點鐵則**:`CLAUDE_PROJECT_DIR` Claude Code 不一定內建,故**每次呼叫 qa-flow.sh 都要顯式帶 `CLAUDE_PROJECT_DIR=<Primary working directory>`(原封不動、即環境說明裡的 session 起始目錄)**。
> **嚴禁自己 export 成子目錄**(即使判斷子目錄才是被測 repo 也不行)。你知道 Primary working directory 是哪,就用那個。
> 要測某子專案 → 請使用者到該子專案目錄重啟 claude,不要從上層鑽進去(`test-plan-design.md` §0 原則)。
> `qa-flow.sh run` 內建守門員:落點若不在 `CLAUDE_PROJECT_DIR/tests/e2e/` 正下方(鑽了子目錄)會直接報錯擋下。
| 指令 | 動作 | 對應步驟 |
|------|------|---------|
| `qa-flow.sh bootstrap` | 盤點既有測試資產(pytest/JS/空)、偵測登記模式 `MODE`(three-layer/legacy-catalog/three-layer-no-config/none)、發安裝/runner 決策訊號(不擅自安裝)、順手 audit | Phase2-0 |
| `qa-flow.sh scaffold <feature> <pytest\|playwright-js>` | pytest:三層骨架(複製工具進 `tests/e2e/tools/`+參數檔 `qa-webwright.json`+conftest 掛點+`<feature>/COVERAGE.md`);安裝指令只印出讓使用者跑 | Phase2-0b(使用者同意後)|
| `qa-flow.sh run <feature> <test-file> [date]` | grep 驗證 test 函式存在(防假綠燈)→ `pytest --junitxml` 出報告(sqlite 自動記錄;三層模式跑完重生 CATALOG)| Phase2-3(首跑收失敗清單+每輪修完重跑)|
| `qa-flow.sh catalog <情境> <函式> <狀態> <模組>` | 三層:寫進 `<模組>/COVERAGE.md`(函式可寫 `test_x.py::test_y`,以函式為主鍵 update/append)再重生 CATALOG;舊版:回填單一 catalog.md。寫入一律同目錄 tmp+原子 rename | Phase2-6 |
| `qa-flow.sh audit [--fix]` | 三層:drift_check(孤兒/幽靈/佔位,有漂移 exit 3);`--fix` 把孤兒補成「待補」佔位列,補完仍有漂移(佔位待寫情境、幽靈)照樣 exit 3,exit 0 才是 drift 0/0/0;舊版:catalog 孤兒列。非本 plugin 格式的 catalog 一律跳過 | Phase2-6 收尾 |
| `qa-flow.sh tools-sync [--force]` | 以 plugin 新版更新已複製的工具;專案端改過的只警告不覆蓋;參數檔永不覆寫 | plugin 升級後 |
| `qa-flow.sh migrate [--dry-run]` | 舊版 4 欄 catalog → 三層(列數對帳、舊檔改名保留) | 舊專案一次性 |
**bootstrap 決策訊號怎麼接:**
- `ASSET: pytest-existing` → 直接復用既有、對齊風格,進 Phase2-1。
- `ASSET: js-existing` + `ACTION-REQUIRED: ask-user-runner` → **問使用者**:在既有 JS 旁另起 pytest,或沿用 JS。
- `ASSET: none` + `ACTION-REQUIRED: ask-user-install` → **問使用者**是否同意裝 pytest-playwright:同意→`scaffold <feature> pytest`;不同意→`scaffold <feature> playwright-js`。
> **腳本不代裝任何東西**:安裝指令一律印出來由使用者執行(依決策:安裝需經同意)。
### 執行步驟
1. **列 critical points**:把測試計畫**每條預期結果**列成一張清單,每個 CP 要能被其結構化證據
獨立驗證(讀取型一個即可;寫入/送出型需業務碼+readback;守門/卡控型斷言狀態或錯誤碼——證據強度依 CP 類型,
見 `methodology/critical-points.md` 證據規範)——不依賴「我記得剛剛點了什麼」。
2. **預擬 codify 草稿(draft-first,不先開瀏覽器)**:直接把每個 critical point 落成 `tests/e2e/<feature>/test_<feature>.py`(三層;舊版專案為 `tests/e2e/test_<feature>.py`)裡
**(至少)一行 `assert`**(雙向/多面卡控可對多行)——斷言打在結構化證據上(業務碼 `code=="0000"` 非只看 HTTP 200、
DOM/a11y 讀回 unique token、DB/重查 readback)。寫入型操作必「寫 unique token → 讀回那一筆比對」,不可只驗送出成功。
selector / 端點 / 欄位名 / 業務碼**先 grep 原始碼取真實值**——多數路徑落差是「程式碼真實值 ≠ 記憶」的問題,
grep 就能填掉大半;grep 拿不到的(動態 DOM、跨頁流程、登入態相依)在該處標 `TODO-EXPLORE` 註記,別瞎猜。
**草稿同時要滿足上方五條硬規則**:前提資料走產品入口自造(非寫死既有 Id)、期望值查來源推導(非字面數字)、
定位錨語系無關(非中文顯示字)、沒資料時自造(非 skip)、開跑前驗 `response.url` 確認打對後端。
斷言規範與五條硬規則的完整判準見 `methodology/critical-points.md`。
3. **Execute 首跑收失敗清單(用 `qa-flow.sh run`)**:跑 `qa-flow.sh run <feature> <test-file>`(date 可省略=今天)——
它先 grep 驗證 test 函式確實寫入(防假綠燈),再跑 `pytest --junitxml` 出報告到 `tests/e2e/reports/<feature>-<date>.xml`
(assert 失敗 → 非 0 exit)。**首跑的目的不是全綠**:是把「預擬猜錯 / TODO-EXPLORE」的 CP 變成明確的失敗清單,
探索預算只花在這份清單上。最終綠燈那次的報告路徑回填報告模板「報告產物」欄;截圖至多留檔備查,不作判定依據。
4. **定向探索補值(只探失敗的)**:僅對失敗與 `TODO-EXPLORE` 的 CP 開 MCP 探索——**先 grep 原始碼再上 DOM**;
a11y `ref` 比 CSS 文字選擇器精準。(僅「真實外部站、無 a11y、長程未知」才改用 webwright 自主探索,見前置。)
**Context 經濟(必守,違反會把 session 撐到反覆 compact)**:全頁 snapshot 只在「導航後首次 / 結構變化後」拍,
驗單一元素或讀值用 `browser_evaluate` / 既有 a11y `ref` 定向讀取;**批次修值**——探索一批 CP(建議 ≤5)
→ 立即回填草稿 → 回步驟 3 重跑,**禁止把全部失敗 CP 在 MCP 逐步跑完才開始回填**。細節與實測教訓見 `knowledge/pitfalls.md` I 段。
**修草稿只准用探索到的真實值——禁止為了轉綠而弱化斷言或改 skip**(見上方假綠燈紀律)。全綠後進步驟 5。
5. **Self-verify**:逐項走 CP 清單,確認**每個 assert 的結構化證據明確相符**才打勾。
任一 CP 失敗 → 診斷具體原因 → 修測試 → 重跑重驗。
**判 FAIL 前先走 `methodology/test-plan-design.md` §7 的「FAIL 前排除紀律」**(服務存活 / 操作沒生效五排除 /
業務語意三問),別把環境塌 / 探索沒對準 / by-design 卡控誤判成功能 FAIL。
6. **輸出測試報告(格式見下)+ 登記情境**:`qa-flow.sh run` 的防假綠燈 grep 已確認 test 函式存在
(Write / replace 在並行取消時可能假成功,造成「假登記、假綠燈」——腳本已把關)。
接著對**每個情境**跑 `qa-flow.sh catalog <白話情境> <test_x.py::測試函式> <完整/部分/未覆蓋> <模組資料夾>`
登記到 `tests/e2e/<模組>/COVERAGE.md`(三層;舊版專案回填 `tests/e2e/catalog.md`),最後 `qa-flow.sh audit` 確認 drift 0/0/0
(必做,見 `methodology/test-plan-design.md` §0.5、`methodology/test-asset-hygiene.md` §1)——讓 codify 閉環不止於 runner、累積成可查的跨功能應測情境索引。
寫測試碼當下若被 `guard-test-asset-hygiene` hook 擋(exit 2),照訊息修掉新增的硬編/漂移/A/D skip 再繼續;
合法例外用 `# SCAN-REVIEWED: safe — <理由>` 等註記宣告(總表見 plugin README「跳脫機制總表」),**不要**用 `--write-baseline` 把新增蓋章成存量。
### 測試哲學(通用,少數鐵則)
- **能走 UI 就走 UI**:模擬使用者操作要點畫面、填表、按鈕,不要繞過前端直接打資料來源
(例外與細節見 `knowledge/pitfalls.md` A 段)。UI 上跑通才算 PASS。
- 排名語意(最新 / 最便宜 / 評價最高)要用畫面實際的排序/篩選控制,不能用自己對結果的排序。
- 數字 / 日期 / 數量 / 單位是**精確**比對。
- 技術棧專屬的「怎麼驗 / 怎麼點 / 哪裡有雷」一律查 `knowledge/pitfalls.md`,**不要靠記憶猜 UI**。
---
## 測試報告格式
```
## 測試報告
測試範圍:{功能} 測試日期:{YYYY-MM-DD} 報告產物:{runner 報告路徑,如 pytest junitxml / log;若有截圖留檔一併附}
### 結果摘要
| 測試案例總數 | PASS | FAIL |
|---|---|---|
| N | N | N |
### 案例明細
| 編號 | 功能 | 結果 | 證據(assert / API 碼 / readback 值) | 備註 |
|------|------|------|--------------------------------------|------|
| TC-001 | {功能} | PASS/FAIL | submit code=="0000" + DB 讀回 token 相符 | {若 FAIL 說明差異} |
### 發現問題(若有 FAIL)
BUG-{編號}|嚴重度:Critical/Major/Minor|對應 TC-{編號}
重現步驟 / 預期 / 實際 / 證據(assert 失敗訊息 / 實際 API 碼 / readback 值)
### 範圍外發現(派工範圍以外看到的異常;沒有就寫「無」)
現象 / 重現步驟 / 證據——只回報,不擴大修改
### 結論
通過 / 需修正後重測(列出 BUG 編號)
```
**每個 PASS/FAIL 都必須引用一行 assert、一個 API 業務碼或一個 readback 值作證據**,不得用「看起來正常」這種模糊判定。截圖至多留檔備查,不作為判定依據。
---
## 文件地圖
- `qa-flow.sh` — 流程輔助腳本(bootstrap / scaffold / run / catalog / audit / tools-sync / migrate);把落地動作鎖進腳本,落點鎖 `CLAUDE_PROJECT_DIR`
- `tools/` — 測試資產工具(scaffold 複製進專案 `tests/e2e/tools/`):`qa_config.py`、`baseline.py`、`qa_pytest_plugin.py`、`runs_db.py`、`coverage_md.py`、`gen_catalog.py`、`drift_check.py`、`make_skeleton.py`、`fill_orphans.py`、`coverage_register.py`、`migrate_catalog.py`、`skip_audit.py`、`hardcode_check.py`、`i18n_locator_check.py`、`env_gates.py`、`sweep_residue.py`、`run_by_folder.py`
- `lib/install_tools.py` — 工具複製與版本比對(scaffold / tools-sync 用)
- `templates/qa-webwright.example.json` — 專案參數檔範例(欄位說明見 plugin README「專案參數檔」)
- `templates/conftest_snippet.py` — conftest 掛點片段(sqlite 執行紀錄、A/D skip 閘、drift 摘要、環境閘)
- `methodology/test-plan-design.md` — 覆蓋矩陣、可追溯、必測 checklist、TC 格式、測試資料原則、探索七類、失敗注入、前後端 A/B 對照、範圍展開四格與欄位級驗證
- `methodology/critical-points.md` — TC 預期 → critical point → assert 的對映與證據規範、五條硬規則、斷言隔離度
- `methodology/test-discipline.md` — 核心鐵則(選單導航不直打 URL、mock 在就不准拿外部系統當 skip 藉口、測試庫可破壞)、不打斷、整輪才出報告、直打界線、副作用邊界、判斷與交付的證據要求(掩蓋手段、每批三重重驗、red→green、ablation、掃描器盲區)
- `methodology/test-asset-hygiene.md` — 三層登記與 drift、skip 四分類紀律、xfail 鎖定與反向紀律、故意保留紅燈、缺陷現場當定位錨、直寫 DB 例外判準框架(四條判準、宣稱例外的四步證據、不算例外的理由)、G 類五種 safe 性質與 `G-REVIEWED`
- `knowledge/pitfalls.md` — 踩過的雷與領域知識(A 後端驗證、B 日期時區、C 壞值、D/D2 Windows 啟動與 pytest、E 元件互動、F state 同步、G webwright 操作雷〔僅啟用 webwright 時適用〕、H 外部站 TLS/HTTP2 指紋封鎖、I 長流程 context 經濟、J 定位比對強度與多語系、K 等待時序與 API 攔截、L 斷言盲區、M 種子資料與共用狀態、N 環境多實例與 runner 執行);**持續 append**(新增分類時同步更新此枚舉)
- 沉澱 runner 的官方文件(pytest-playwright / Playwright Test)— 瀏覽器啟動、locator、斷言、fixture
- (選用,僅外部站備用探索)webwright skill 的 `reference/` — 瀏覽器啟動、aria snapshot、log 格式
Files in this skill
- SKILL.md
- knowledge/pitfalls.md
- methodology/critical-points.md
- methodology/test-plan-design.md
- qa-flow.sh
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.