From 25b658e981db13f035eb7c0c41723e06da9a43f4 Mon Sep 17 00:00:00 2001 From: digua Date: Sat, 27 Jun 2026 14:44:42 +0800 Subject: [PATCH] chore(tests): clarify runtime and regression rules --- .nvmrc | 1 + AGENTS.md | 4 ++-- docs/cn/contributing/development.md | 2 ++ scripts/run-tests.mjs | 16 ++++++++++++++++ scripts/run-tests.test.mjs | 11 ++++++++++- 5 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..a45fd52c --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +24 diff --git a/AGENTS.md b/AGENTS.md index d02afcbf..2ab2bf9a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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(...)` 一类字符串匹配来模拟数据库行为 diff --git a/docs/cn/contributing/development.md b/docs/cn/contributing/development.md index a7b700cf..e209dd7b 100644 --- a/docs/cn/contributing/development.md +++ b/docs/cn/contributing/development.md @@ -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`。 diff --git a/scripts/run-tests.mjs b/scripts/run-tests.mjs index c1cd9ad9..a23ea91c 100644 --- a/scripts/run-tests.mjs +++ b/scripts/run-tests.mjs @@ -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() diff --git a/scripts/run-tests.test.mjs b/scripts/run-tests.test.mjs index 88abc72a..fabbabb5 100644 --- a/scripts/run-tests.test.mjs +++ b/scripts/run-tests.test.mjs @@ -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.', + }) +})