Control UI E2E 是做什麼的?
Control UI 設計回饋 + 使用確定性 Gateway 資料的真實瀏覽器流程。
UI 壓力測試
- 大幅 UI 變更:及早建置本機 HTML 壓力測試畫廊;讓使用者比較有意義的狀態,並針對具體範例提供回饋。
- 用於佈局、互動、具有多種狀態的元件。若僅有小幅的文字/圖示編輯,且畫廊無法提供有用的比較,則可跳過此步驟。
- 從受影響的元件 + 資料合約中推導出範例。涵蓋相關的正常、載入中、空白、錯誤、無法使用、權限、選取、展開等狀態;以及會對佈局造成壓力的長文字/密集內容。互斥的狀態應分別顯示;標記目前實作不支援的提議狀態。
- 建立一份可在瀏覽器中開啟的 HTML 總覽:包含穩定的範例 ID、簡短的狀態標籤,以及足以理解每個範例的背景資訊。偏好使用真實元件 + 確定性的模擬 fixture。標記靜態/近似渲染;對於無法重現的互動,提供執行中 UI 的連結。產生的畫廊:屬於任務擁有的成品儲存;預設不進行提交。
- 每個範例都應有標籤化的回饋輸入。使用畫廊特定的儲存金鑰 + 穩定的範例 ID,在重新整理時於本機持續保存。複製回饋動作會將範例 ID、狀態標籤、評論匯出為 Markdown/純文字,供使用者帶回對話中。
- 在可用的預覽瀏覽器中開啟畫廊;分享 URL/檔案路徑。在迭代過程中保留相同的畫廊、範例 ID 及現有評論。將使用者回饋套用至畫廊與實作;保持兩者可比較。
- 在請求回饋之前:檢查相關可視區域大小下的渲染範例;驗證回饋在重新整理後仍存在,且能匯出正確的範例標籤。回報不支援的狀態/預覽限制。
畫廊支援設計審查;但絕不能取代重點行為測試,或從執行中的 UI 檢查前/後比對證據。將最終證據保留在下方全新的截圖目錄中,與持續演進的畫廊分開。
測試形狀
- 完整的 GUI 流程:
ui/src/**/*.e2e.test.ts。 ui/src/test-helpers/control-ui-e2e.ts:啟動 Vite Control UI + 安裝模擬的 Gateway WebSocket。- 確定性場景。除非使用者明確要求即時證明,否則不使用真實的 provider 金鑰、真實的頻道憑證、真實的 Gateway。
- 縮小渲染邏輯範圍:偏好使用現有的
.browser.test.ts/單元測試。E2E 通道用於:路由、應用程式啟動、Gateway 握手、請求、以及可見的 UI 行為整合。
指令
- 在 Codex 工作樹中鎖定一個 E2E 測試:
node scripts/run-vitest.mjs run --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner ui/src/e2e/chat-flow.messaging.e2e.test.ts
- 在一般檢出環境執行整個本機通道:
pnpm test:ui:e2e
- 使用已準備好的依賴安裝或已準備好的一般檢出環境;絕不在其他工作使用共用安裝時進行協調。
- 遵循
$openclaw-testing:可信賴的開發證明可在本機執行;遠端證明則需要瀏覽器/平台、乾淨環境或原始碼隔離的理由。
視覺證明預設
- 外觀變更:檢查前/後的視覺證據。
- 其他行為:最清晰的適當邊界證明;當斷言已能證明變更時,不強制要求影片 + 螢幕截圖組合。
- 確定性的 Vitest E2E 斷言;絕不提交產生的螢幕截圖/影片。
- 共用測試套件會停用 Chromium 的部分光柵化 + GPU 光柵化,以避免因繪製歷史而產生的邊緣像素差異。在聲明可重現性之前,仍需要進行精確的重複比較。
- 像 已儲存 這樣的短暫狀態:在 fixture 之前安裝
page.clock;使用pauseVirtualClock暫停;僅推進進入該狀態所需的 fixture 工作。單純的setFixedTime無法暫停計時器。擷取就緒狀態使用原生的佈局傳遞,而不推進 fixture 時鐘。 - 靜態影像:使用來自
ui/src/test-helpers/control-ui-e2e-screenshot.ts的takeControlUiScreenshotFrame,具備明確的語義內容 +animations: "disabled"。透過viewport/scrollTo傳遞可視區域變更/預期的捲動目標;驗證保留的置中效果、可視區域/捲動剪裁交集、穩定的佈局/字型/可見影像。 - 在
elements中傳遞所有相關的元素定位器;從單一幀中儲存傳回的頁面 PNG + 裁切。裁切會將分數邊界包圍在測量到的 PNG 像素內;會斷言尺寸及不變的邊界。絕不能將分開的頁面/定位器螢幕截圖組合作為同一幀的證據。 - 預設的目前幀模式 + 現有的可視區域/元素輔助函數會保留錄製 + 取樣動畫行為。靜態準備在邊界測量 + 未裁剪的擷取過程中保持啟用;全頁證明必須符合可視區域幀的尺寸。
- 在/與重點 E2E 測試並行執行:在可用時執行模擬的 Control UI 應用程式,例如
pnpm dev:ui:mock -- --port <port>。 - 使用 Playwright 驅動 Chromium 對抗本機模擬 URL。使用螢幕截圖/短片擷取所需的狀態。
- 使用
browser.newContext({ recordVideo: { dir, size }, viewport })、page.screenshot({ path });在回報影片路徑前關閉 context。 - 工作階段指令狀態證明:僅限可視區域的擷取,使用 Playwright 1.62.1 + Chrome 151.0.7922.34 (Linux 真實 Gateway;macOS arm64 合成重現) 驗證。其他錄製擁有者未由此修正進行遷移/認證;請分別驗證他們所需的螢幕截圖內容 + 最終影片。請參閱 已驗證的擷取路徑及上游限制。
- 使用來自
ui/src/test-helpers/control-ui-e2e-artifacts.ts的createControlUiE2eArtifactDir(scope, parentDir?)分配保留的證明。每次呼叫會以原子方式建立全新的目錄並記錄實際路徑。父目錄優先順序:明確的 parent → 修剪後的現有OPENCLAW_UI_E2E_ARTIFACT_DIR→ 儲存庫的.artifacts/control-ui-e2e父目錄。現有的自訂輸出控制會選擇父目錄;絕不新增/重寫環境變數來啟用擷取。 - 在測試/場景或
beforeEach中分配,每個嘗試一次;獨立腳本則每次呼叫一次。將擁有者明確傳遞給共用的擷取輔助函數。保留原始閘門、功能/階段名稱、可視區域、等待、錄製選項。不同的階段:不同的檔案名稱。將螢幕截圖/報告/影片保留在一起。 - 保留成功 + 失敗的證據。回報實際分配的路徑,包括重新命名的檔案覆蓋。在審查後僅手動刪除確切的擁有目錄;在重播前絕不清除共用的父目錄。可丟棄的建置/媒體 fixture + 擁有的暫時原始影片可以保留清理。新的合成擷取無法復原被覆寫的證據。
- 逾時診斷:在現有的診斷父目錄下建立新的子目錄。Mantis 會在呼叫擁有的目錄下保留每個擷取嘗試;拒絕報告覆寫。真實 Gateway 測試套件、
chat-outbox-*、chat-attachment-read-lifecycle:擁有者各自獨立;在聲明可安全重播的保留之前請先協調。 - 錄製 = 驗證,而非僅是示範擷取。如果錄製失敗或出現異常行為:停止、修正行為、新增/更新回歸測試、重新錄製。
- 如果視覺證明受阻:回報確切的阻礙因素;仍提供文字化的 E2E 證據。
模擬模式
啟動應用程式伺服器;在 page.goto 之前安裝模擬;斷言 Gateway 流量 + 可見的 UI:
const server = await startControlUiE2eServer();
const page = await context.newPage();
const gateway = await installMockGateway(page, {
historyMessages: [{ role: "assistant", content: [{ type: "text", text: "準備就緒." }] }],
});
await page.goto(`${server.baseUrl}chat`);
await page.locator(".agent-chat__composer-combobox textarea").fill("你好");
await page.getByRole("button", { name: "發送訊息" }).click();
const request = await gateway.waitForRequest("chat.send");
await gateway.emitChatFinal({ runId: String(request.params.idempotencyKey), text: "完成." });
await page.getByText("完成.").waitFor();
如果需要更多 Gateway 表面,可透過型別化的場景選項/方法回應來擴充 installMockGateway。
執行檢查器 (Run Inspector) 證據
- 使用來自
ui/src/test-helpers/control-ui-run-inspector.ts的withControlUiRunInspector收集。 擁有獨立的頁面;在成功/失敗時關閉;保留呼叫者的聊天頁面 + 未發送的草稿。 preparePage:模擬 Gateway 或進行中的每個分頁驗證設定。共用的瀏覽器 context 不會複製另一個分頁的 session-storage token。- 輔助函數使用渲染元件模型的
RunInspectorSelector+activityRunInspectorSelectorHref,包括所選收據的決策游標。 - 渲染面板的
data-run-id+data-execution-id:回傳存在的身分, 而不僅是請求的 URL。所選詳細資訊的data-receipt-selector-id=DecisionReceiptDisplayV1.selectorId。 - 遺失/不明確的身分或缺少所選收據不得視為匹配。
- 決策選擇器與選用的終端轉錄金鑰
agent.wait.terminalReceipt.assistantTranscriptIdempotencyKey分開。絕不能從 DOM 選擇器/歷史記錄行製造金鑰,或聲稱檢查器證據能修復其缺失。 - 側邊欄執行狀態的目前可存取標籤:
Active run,而非Running。
獨立錄製
- 含旁白字幕、平緩的目標縮放、加速的暫停:使用 proof-video 開發技能。獨立範本會錄製 原始證據 + 提示側車檔,並使用系統 ffmpeg 渲染含字幕的 MP4。 保留原始擷取;附加檢查過的潤飾影片。
- 已執行中的模擬 Control UI URL:暫時的 Playwright 腳本或
playwright test規格;保持錄製流程專注:- 開啟模擬 URL;透過穩定的
data-*/使用者面向的角色選擇器進行互動; 等待已斷言的狀態,而非固定的延遲。 - 請求驅動流程:斷言可見的 UI + 模擬的 Gateway 流量。例如:
預期的計數/列可見 +
sessions.list已使用預期的search、offset、limit被呼叫。 - 僅在斷言之後加入短暫延遲,以使錄製的影片可讀。
- 產生的影片:儲存在呼叫的全新分配目錄中。絕不提交或 移除舊的擷取。
- 開啟模擬 URL;透過穩定的