chore(tests): clarify runtime and regression rules

This commit is contained in:
digua committed 2026-06-27 15:54:08 +08:00
1 parent dfd330e6bb
commit 25b658e981
5 files changed
+31 -3

No files matched your search

+1
View File
@@ -0,0 +1 @@
24
+2 -2
View File
@@ -29,8 +29,8 @@
- 测试文件位置:与单个业务模块强相关的单元测试应就近放在被测文件同目录,命名为 `*.test.ts` / `*.test.js`;跨模块、集成、E2E、测试工具或不明显归属某个业务文件的测试放在根目录 `tests/`;某个 app/package 专属测试放在对应的 `apps/*` 或 `packages/*` 内,遵循该子项目现有约定
- 测试目标:测试应优先覆盖用户数据安全、数据库迁移、导入解析、权限/认证、AI 工具权限、配置/API key 迁移、跨端共享逻辑和已发生过的回归;不要为了提高数量给低风险 getter、常量、样式或纯展示细节机械补测
- 必须加测试:修复 bug 时必须先加能失败的回归测试;修改数据库 schema/迁移、导入解析、去重逻辑、权限认证、AI 工具 allowlist、配置/API key 迁移、跨端共享 service 时必须加或更新测试
- 可以不加测试:只改文案、样式、类型声明、日志、注释、无行为变化的小重构时,可以不新增测试,但仍需运行相关类型检查、lint 和 format
- 必须加测试:修复会影响用户数据、业务逻辑、异步任务、缓存状态、跨端共享 service、公开 API 契约、导入解析、去重逻辑、权限认证、AI 工具 allowlist、配置/API key 迁移或数据库 schema/迁移的行为 bug 时,必须先加能失败的回归测试;修改上述高风险模块时也必须加或更新测试
- 可以不加测试:只改 UI 文案、i18n key/翻译、样式、类型声明、日志、注释、无行为变化的小重构,或修复低风险展示细节时,可以不新增测试,但仍需运行相关类型检查、lint 和 format;不要为了低价值页面文案或源码字符串扫描新增脆弱测试
- 测试分层:纯函数、解析/格式化、权限判断、参数规范化、错误分支优先写单元测试;SQL 行为、数据库迁移、文件迁移、导入写库、Fastify route、跨包 service 优先写集成测试;Electron、真实浏览器、真实 LLM、真实网络仅用于少量关键 E2E/Smoke,并默认通过环境变量显式启用
- 避免重复测试:新增测试前先搜索同类断言;如果下层单测已覆盖算法,上层只测调用链是否接通,不重复枚举算法细节;如果测试只锁定实现写法、失败后不指向用户可见风险,应合并、改写或删除;优先写能覆盖全量场景的通用断言,而非针对单个条目的专项断言——若通用断言已完整覆盖,单个断言是冗余的
- 测试替身选择:涉及 SQL、数据库迁移、Fastify route 或跨包 service 时,优先使用轻量内存 SQLite / 临时文件 fixture 验证真实行为;只有在测试纯适配边界时才使用 mock/fake。避免用大量 `sql.includes(...)` 一类字符串匹配来模拟数据库行为
+2
View File
@@ -137,6 +137,8 @@ CHATLAB_ALLOW_INCOMPATIBLE_DATA_DIR=1
- 修改 TypeScript 或 Vue 代码后,至少运行相关类型检查。
- 修改公开文档后,运行 `pnpm docs:build` 或对修改的 Markdown/配置文件运行格式化检查。
- 修改跨平台共享逻辑后,确认 Electron 和 CLI Web 两端入口没有产生行为分歧。
- 修复会影响用户数据、业务逻辑、异步任务、缓存状态、跨端共享 service、公开 API 契约、导入解析、去重逻辑、权限认证、AI 工具 allowlist、配置/API key 迁移或数据库 schema/迁移的行为 bug 时,必须优先补能失败的回归测试。
- 只改 UI 文案、i18n key/翻译、样式、类型声明、日志、注释、无行为变化的小重构,或修复低风险展示细节时,可以不新增测试,但仍需运行相关类型检查、lint 和 format;不要为了低价值页面文案或源码字符串扫描新增脆弱测试。
- 日常默认运行 `pnpm test`;需要优先验证相关文件时运行 `pnpm test -- path/to/file.test.ts`。
- `pnpm test` 默认只包含单元/集成测试,不应依赖真实 LLM、真实 Electron、真实浏览器、真实网络或长时间 E2E。
- 与单个业务模块强相关的单元测试就近放在被测文件同目录,命名为 `*.test.ts` 或 `*.test.js`。
+16
View File
@@ -18,6 +18,7 @@ const SKIP_DIRS = new Set([
])
const TEST_FILE_RE = /\.(?:test|spec)\.(?:ts|tsx|js|jsx|mjs|mts|cjs|cts)$/
const SUPPORTED_NODE_MAJOR = 24
function normalizePath(filePath) {
return filePath.split(sep).join('/')
@@ -64,7 +65,22 @@ export function buildNodeTestArgs(testArgs) {
return ['--experimental-test-module-mocks', '--import', 'tsx', '--test', ...testArgs]
}
export function checkSupportedNodeVersion(version = process.versions.node) {
const major = Number.parseInt(version.split('.')[0] ?? '', 10)
if (major === SUPPORTED_NODE_MAJOR) return { ok: true }
return {
ok: false,
message: `ChatLab tests require Node.js >=24 <25. Current Node.js is ${version}. Switch to Node 24 before running tests.`,
}
}
function run() {
const nodeVersion = checkSupportedNodeVersion()
if (!nodeVersion.ok) {
console.error(nodeVersion.message)
process.exit(1)
}
const explicitArgs = process.argv.slice(2)
const testArgs = explicitArgs.length > 0 ? explicitArgs : collectDefaultTestFiles()
+10 -1
View File
@@ -1,7 +1,7 @@
import assert from 'node:assert/strict'
import test from 'node:test'
import { buildNodeTestArgs, filterDefaultTestFiles } from './run-tests.mjs'
import { buildNodeTestArgs, checkSupportedNodeVersion, filterDefaultTestFiles } from './run-tests.mjs'
test('default test collection excludes e2e, smoke, and real external tests', () => {
const files = [
@@ -30,3 +30,12 @@ test('explicit test arguments are passed through without default exclusions', ()
'tests/e2e/helpers/app-launcher.test.js',
])
})
test('node version check rejects unsupported test runtimes before native modules load', () => {
assert.deepEqual(checkSupportedNodeVersion('24.2.0'), { ok: true })
assert.deepEqual(checkSupportedNodeVersion('22.20.0'), {
ok: false,
message:
'ChatLab tests require Node.js >=24 <25. Current Node.js is 22.20.0. Switch to Node 24 before running tests.',
})
})