SKILL.md
唯讀
名稱
testing
描述
Vitest 測試指南。適用於撰寫或更新測試、修復未通過的測試、提升測試覆蓋率、除錯測試問題或設定 Mock 模擬。
LobeHub 測試指南
快速參考
常用指令:
# 執行特定的測試檔案
bunx vitest run --silent='passed-only' '[file-path]'
# 資料庫套件(client-db,PGlite — 預設,跳過 BM25/pg_search)
cd packages/database && bunx vitest run --silent='passed-only' '[file]'
# 資料庫套件(server-db,Postgres — 對齊 BM25/pgvector,CI 測試覆蓋率採計標準)
cd packages/database && TEST_SERVER_DB=1 bunx vitest run --silent='passed-only' '[file]'
切勿執行 bun run test — 這會執行全部 3000 多個測試(約需 10 分鐘)。
資料庫 Model/Repository 規範: 凡是在
packages/database/src/models/**或src/repositories/**下新增的檔案,都必須在同一個 PR 中附帶同級的__tests__/<name>.test.ts。
請透過getTestDB()使用真實 DB(整合測試風格),使用describe.skipIf(!isServerDB)防護 BM25/全文檢索區塊,並務必測試使用者隔離(user-isolation)。環境設定、Schema 注意事項以及 client-vs-server-db 的差異,請參考references/db-model-test.md。
測試分類
| 類別 | 位置 | 設定檔 |
|---|---|---|
| Webapp | src/**/*.test.ts(x) |
vitest.config.ts |
| Packages | packages/*/**/*.test.ts |
packages/*/vitest.config.ts |
| Desktop | apps/desktop/**/*.test.ts |
apps/desktop/vitest.config.ts |
核心原則
- 優先使用
vi.spyOn而非vi.mock— 目標更精確,也更易於維護 - 測試必須通過型別檢查 — 撰寫測試後請執行
bun run type-check - 修復失敗 1~2 次後應即時停下尋求協助
- 測試外部行為,而非實作細節
- 修復 Bug 時需補上迴歸測試 — 修復 Bug 後,新增一個「修復前會失敗、修復後會通過」的迴歸測試,防止問題再次發生
- 不要新增 React 元件測試 — 僅維護現有的 React 元件測試。複雜邏輯應抽離至 Hooks 中進行獨立測試
- 先完成所有原始碼修改,再調整測試 — 先徹底完成原始碼修改,再統一更新測試。兩者交替進行會打亂對程式碼邏輯的思緒,特別是在跨多個檔案修改時
基本測試結構
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
vi.restoreAllMocks();
});
describe('ModuleName', () => {
describe('functionName', () => {
it('should handle normal case', () => {
// Arrange → Act → Assert
});
});
});
Mock 模式
// ✅ 針對直接相依的模組進行 Spy
vi.spyOn(messageService, 'createMessage').mockResolvedValue('id');
// ✅ 使用 vi.stubGlobal 模擬瀏覽器 API
vi.stubGlobal('Image', mockImage);
vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:mock');
// ❌ 避免在全域 Mock 整個模組
vi.mock('@/services/chat'); // 範圍過大
詳細指南
具體測試情境請參閱 references/ 目錄:
- 資料庫 Model 測試:
references/db-model-test.md - Electron IPC 測試:
references/electron-ipc-test.md - Zustand Store Action 測試:
references/zustand-store-action-test.md - Agent Runtime E2E 測試:
references/agent-runtime-e2e.md - Desktop Controller 測試:
references/desktop-controller-test.md
修復失敗的測試 — 優化還是刪除?
當測試因實作變更(而非 Bug)導致失敗時,盲目修復前請先進行評估:
保留並修復(更新測試資料/斷言)
- 行為測試(Behavior tests):驗證程式碼「做了什麼」(輸出、副作用、使用者可見行為)的測試。只需更新 Mock 資料格式或預期結果值。
- 範例:Tool 資料結構從
{ name }改為{ function: { name } }→ 更新 Mock 資料 - 範例:輸出格式從
Current date: YYYY-MM-DD改為Current date: YYYY-MM-DD (TZ)→ 更新預期的字串
- 範例:Tool 資料結構從
刪除(過度限定、價值低)
- 參數轉發測試(Param-forwarding tests):斷言內部函式呼叫精確參數的測試(例如
expect(internalFn).toHaveBeenCalledWith(expect.objectContaining({ exact params })))——這類測試每次重構都會毀壞,且只是在重複行為測試已涵蓋的內容。 - 與實作高度耦合的測試(Implementation-coupled tests):驗證程式碼內部「如何運作」而非「產生什麼結果」的測試。若較高層級的測試已涵蓋該行為,這類低層級測試只會增加維護成本,卻無法提高實質覆蓋率。
決策核對清單
- 測試是否驗證了外部可觀察的行為(API 回應、DB 寫入、渲染輸出)? → 保留
- 測試是否僅驗證內部呼叫流程(哪個函式接收了哪些參數)? → 檢查行為測試是否已涵蓋。若有 → 刪除
- 相同的行為是否已在更高的整合層級完成測試? → 刪除低層級的重複測試
- 測試是否會在下一次常規重構時再次損壞? → 考慮提升至整合層級測試或直接刪除
撰寫新測試時
- 優先使用整合層級斷言(驗證最終輸出),而非白箱斷言(驗證內部呼叫)
- 僅在面對穩定且公開的介面規格時使用
expect.objectContaining— 切勿用於隨重構頻繁變動的內部參數結構 - 僅在系統邊界(DB、網路、外部服務)進行 Mock,不要在內部模組之間做 Mock
常見問題
- 模組污染(Module pollution):測試莫名失敗時,請使用
vi.resetModules() - Mock 未生效:檢查設定位置,並在
beforeEach中使用vi.clearAllMocks() - 測試資料污染:在
beforeEach/afterEach中清理資料庫狀態 - 非同步問題(Async issues):針對 React Hooks 的狀態變更,請使用
act()包裹






