diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c0a3bd9bea..d6bf524497 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -104,6 +104,13 @@ pnpm test For frontend or package changes, run the relevant package tests under `packages/` or `packages/app-tests/`. +Test quality matters more than test count: + +- Exercise production functions or mounted components and assert observable results, state changes, errors, or emitted events. Mock external boundaries, not the behavior under test. +- Do not copy the implementation into a test or use source-string matching to pin class names, local variable names, template fragments, or helper-call spelling. These checks break on harmless refactors without proving runtime behavior. Check layout in a browser rather than inferring it from CSS strings. +- Extend the existing behavior suite for a regression instead of adding a second source-wiring snapshot. Use table-driven cases when only the inputs and expected outputs differ. +- File-content checks are appropriate for shipped artifacts, permissions, compatibility rules, and cross-runtime contracts. Keep safety guards until equivalent behavior coverage exists; do not delete a test merely because it reads files, uses mocks, or runs slowly. + ### Documentation User-facing docs live in two places: diff --git a/CONTRIBUTING.zh-CN.md b/CONTRIBUTING.zh-CN.md index 515d346298..8aac8031cf 100644 --- a/CONTRIBUTING.zh-CN.md +++ b/CONTRIBUTING.zh-CN.md @@ -104,6 +104,13 @@ pnpm test 如果改的是前端或某个 package,再补跑对应目录下的测试。 +测试质量比测试数量更重要: + +- 调用生产函数或挂载真实组件,验证可观察的结果、状态变化、错误或事件。Mock 外部边界,不要 Mock 正在验证的行为。 +- 不要在测试中复制实现,也不要用源码字符串匹配锁定 class、局部变量名、模板片段或辅助函数调用写法。这类检查会阻碍无害重构,却不能证明运行行为;布局应在浏览器中验证,而不是从 CSS 字符串推断。 +- 回归用例优先补进已有行为测试,不再另加一份源码接线快照。只有输入和预期不同的场景优先使用参数化用例。 +- 发布产物、权限、兼容性规则和跨运行时契约可以使用文件内容检查。安全门禁在有等价行为覆盖前保留,不要仅因测试读文件、使用 Mock 或运行较慢就删除。 + ### 文档 用户文档主要分两块: diff --git a/apps/desktop/src/components/chart/__tests__/QueryChartSelection.spec.ts b/apps/desktop/src/components/chart/__tests__/QueryChartSelection.spec.ts deleted file mode 100644 index dffd02c640..0000000000 --- a/apps/desktop/src/components/chart/__tests__/QueryChartSelection.spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { readFileSync } from "node:fs"; -import { describe, expect, it } from "vitest"; - -const queryChartSource = readFileSync(new URL("../QueryChart.vue", import.meta.url), "utf8"); - -describe("QueryChart Y-axis selection", () => { - it("binds the visible checkbox state to the selected Y columns", () => { - expect(queryChartSource).toContain(':model-value="yColumnIndexes.includes(col.index)"'); - expect(queryChartSource).toContain('@update:model-value="setYColumn(col.index, $event)"'); - expect(queryChartSource).not.toContain(':checked="yColumnIndexes.includes(col.index)"'); - expect(queryChartSource).not.toContain('@click="toggleYColumn(col.index)"'); - expect(queryChartSource).not.toContain("CheckIcon"); - }); -}); diff --git a/apps/desktop/src/components/codeSnapshot/__tests__/CodeSnapshotDialogLayout.spec.ts b/apps/desktop/src/components/codeSnapshot/__tests__/CodeSnapshotDialogLayout.spec.ts deleted file mode 100644 index a3b5bed288..0000000000 --- a/apps/desktop/src/components/codeSnapshot/__tests__/CodeSnapshotDialogLayout.spec.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { readFileSync } from "node:fs"; -import { describe, expect, it } from "vitest"; - -const dialogSource = readFileSync(new URL("../CodeSnapshotDialog.vue", import.meta.url), "utf8"); - -describe("CodeSnapshotDialog layout", () => { - it("keeps the exported snapshot at its intrinsic width inside the scrollable preview", () => { - // 截图节点不能被外层 flex 布局压缩,否则长代码导出时会被裁切或错误换行。 - expect(dialogSource).toContain('v-html="snapshotHtml" class="flex w-max min-w-[320px] flex-none"'); - }); -}); diff --git a/apps/desktop/src/components/config/__tests__/DriverStoreDialog.visibility.spec.ts b/apps/desktop/src/components/config/__tests__/DriverStoreDialog.visibility.spec.ts deleted file mode 100644 index 9201ce17c7..0000000000 --- a/apps/desktop/src/components/config/__tests__/DriverStoreDialog.visibility.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { readFileSync } from "node:fs"; -import { describe, expect, it } from "vitest"; - -const source = readFileSync(new URL("../DriverStoreDialog.vue", import.meta.url), "utf8"); -const templateStart = source.indexOf("