Part 4 開始。換一個案子、換一個角度。
前面二十八天都在講「怎麼讓產出是對的」。接下來七天要處理一個更前面的問題:
你怎麼知道你「驗證過了」?
那個案子的回顧文件第一句話是這樣寫的:
整段過程中,最貴的錯誤都不是技術不會,而是「以為驗證過了,其實沒有」。
一個前端框架的長距離升級:跨十個大版本,逐版升,每版一個檢查點、每版可以回滾。它留下的東西很完整:221 筆動作日誌、14 個綠燈標記、22 個 commit、10 份逐版升級文件,最後萃取成 17 篇編號的知識點回顧。
而那 17 篇裡,排在最前面的五篇全部是驗證方法論。不是升級技巧。索引裡對這個安排有一句說明:
這裡留的不是「升級步驟」——那在標準作業程序裡。
這裡留的是判斷失準的地方,以及為什麼會失準。
今天先講第一篇,也是他們自己標為「代價最大的失誤」那一篇。
情境是這樣。
框架某一版的官方 migration 把對話框元件從新版改成 legacy 版,三十幾個檔案的 import 全部被改寫。這是官方工具做的,理論上很安全。
但那個版本同時把 legacy 元件的樣式,拆到了另一個主題檔。
prebuilt-themes/indigo-pink.css ← 新版主題(設定裡載入的是這個)
legacy-prebuilt-themes/legacy-indigo-pink.css ← legacy 版主題(從未載入)
migration 換了元件,卻沒有同步換主題。
於是從那一版開始,整個工作區的對話框完全沒有套到任何主題樣式。沒有白色面板、沒有陰影,內容直接透明浮在頁面上。
而接下來三次升級的 UI 比對報告,全部寫著:
4/4 畫面完全一致
因為那四張截圖裡,根本沒有對話框。
截圖腳本是對網址直接截圖的——它無法點擊。
而對話框要點按鈕才會出現。
所以那支腳本從第一天起就拍不到對話框。每次升級跑完,它忠實地比對了四張截圖、忠實地報告「完全一致」。而它報告的範圍,從來不包含那個壞掉的東西。這個失效有兩個性質讓它特別難發現:
一、報告是真的。 那四張截圖確實一致,沒有人造假。
二、沒有任何訊號。 編譯過、測試綠、頁面渲染正常、沒有 console error。壞掉的只有「使用者點開對話框之後看到的樣子」。Day 06 講過 UI 的沉默約束。這是它的極致版本:連你的驗證工具都沉默了。
回顧裡把這件事收成一句話,我認為是全系列最實用的檢查問句之一:
判斷 UI 沒跑版之前,先問一句:
「這次改動影響的東西,截圖裡拍得到嗎?」
而且它把「拍不到」的處置寫死成三種,沒有第四種:
絕對不能因為「其他畫面都一致」,就宣稱整體沒跑版。
第三種選項我特別想強調。因為它承認了一件事:有些東西你就是驗不了。
而驗不了的正確處理不是假裝驗了,是把它寫進報告,讓讀報告的人知道這一塊沒有涵蓋。

回顧裡列了一份清單,我覺得可以直接拿去用:
最後一項最麻煩,因為它的成本最高。你要先解決登入、解決測試資料、解決流程前置狀態,才拍得到那一張。
而成本高的東西,就是最容易被「其他都一致」帶過的東西。
後來補的那支可點擊的擷取腳本,有兩個設計我覺得值得學。
一、用按鈕文字或 title 屬性定位,不用 CSS class。
理由很直接:升版正是會改 class 的。 用 class 定位的腳本,會在升版之後自己壞掉。而它壞掉的方式是「找不到元素、拍不到、報告變空」。
你的驗證工具不能依賴那個正在被改變的東西。
二、每個對話框之前重新載入頁面。
因為有些對話框設定成不可用 Escape 關閉,殘留的遮罩層會攔截下一次點擊。不重新載入的話,第二個對話框就拍不到了。而且不會報錯,只會拍到上一個。
三、同時輸出 DOM class 清單。
這條最聰明:像素只能證明「看起來變了」,class 清單才能證明「為什麼變」。
他們補上工具之後,實際拍到了對話框。而結果跟事前預期完全相反。原本以為「遷移可能會弄壞畫面」,實際發現的是「遷移前才是壞的」。
那個遷移不是風險,是修復。
而為了確認「破圖是那一版引入的、不是一直存在」,他們做了一件我覺得很紮實的事:從最初的基準標籤開一個獨立的工作副本、裝回舊版本的一千九百多個套件、實際啟動起來擷取畫面。
結論:最初的版本確實是好的。
成本大約五分鐘。換來的是「破圖從哪一版開始」這個問題的直接證據,而不是推論。(這個手法後面會單獨講。)
最後講一件誠實的事。
那支可點擊的擷取腳本,只能用在其中一個專案。因為只有那個專案的測試入口在模擬模式下到得了。其他三個專案共 52 處對話框呼叫,至今沒有任何實拍。
它們需要各自的模擬資料與登入流程,成本很高。
所以那份回顧誠實地寫著:那 52 處在破圖期間很可能也是壞的,本次遷移應該一併修復,但需要人工確認。這是一個「知道自己沒驗到」的狀態,而不是「以為驗到了」的狀態。
那兩者的差距,就是這整個 Part 4 在講的東西。