test: 测试体系全面优化,修复 Windows SQLite EBUSY 和前端产品缺陷

测试基础设施
- 统一 SQLite 测试 DB/临时目录 helper(tests/helpers.ts),支持 Windows EBUSY 重试清理
- 测试库使用 PRAGMA journal_mode=DELETE 避免 WAL 句柄延迟
- 路由 handler 测试改用 createMigratedMemoryTestDatabase 避免 File DB 锁
- SQLite 聚焦 --rerun-each=20 全部通过(720 pass)

后端测试补强
- 新增 tests/server/app.test.ts 真实 startServer 集成测试
- 覆盖 /api/meta、项目 CRUD、错误路径、静态 fallback、安全 header
- bootstrap/logger 测试捕获预期输出,消除测试噪音

前端测试补强
- 移除 .ant-* 内部类名依赖,改为角色/文本/导航/请求契约断言
- 项目页补充搜索、Tab 切换、表单、表格操作、错误反馈行为测试
- 新增 hooks(use-theme-preference、use-sidebar-collapsed、use-projects)纯逻辑测试
- 新增 ErrorBoundary 错误展示和刷新按钮测试
- 新增搜索清空行为测试
- 测试 setup 过滤 antd/rc-trigger NaN height warning

产品修复(测试暴露)
- 修复 ProjectToolbar 搜索框无法输入(新增 draftKeyword 状态)
- 加固 ProjectFormModal 表单字段同步(useEffect 替代不可靠的 afterOpenChange)
- 清理 ProjectFormModal 冗余 afterOpenChange 同步逻辑

重构与合规
- ProjectContext 拆分为三文件满足 React Fast Refresh 规则
- use-projects.ts 导出内部 helper 函数供测试验证
- scripts/build.ts 提取纯生成函数供测试使用,修复构建步骤日志编号
- 修复 build 测试覆盖真实生成逻辑

文档同步
- 更新后端/前端/开发文档测试规范、质量门禁和 helper 使用说明
This commit is contained in:
2026-05-29 00:45:21 +08:00
parent 6cb378d7cb
commit 2ea4bd4410
31 changed files with 1417 additions and 723 deletions

View File

@@ -4,6 +4,35 @@ import type { Logger } from "../../src/server/logger";
import { createConsoleFallback, createMemoryLogger, createNoopLogger, REDACT_PATHS } from "../../src/server/logger";
function captureConsole(callback: () => void): { errors: string[]; logs: string[]; warns: string[] } {
const originalError = console.error;
const originalLog = console.log;
const originalWarn = console.warn;
const errors: string[] = [];
const logs: string[] = [];
const warns: string[] = [];
console.error = (...args: unknown[]) => {
errors.push(args.map(String).join(" "));
};
console.log = (...args: unknown[]) => {
logs.push(args.map(String).join(" "));
};
console.warn = (...args: unknown[]) => {
warns.push(args.map(String).join(" "));
};
try {
callback();
} finally {
console.error = originalError;
console.log = originalLog;
console.warn = originalWarn;
}
return { errors, logs, warns };
}
describe("NoopLogger", () => {
test("所有方法不抛异常", () => {
const logger = createNoopLogger();
@@ -59,17 +88,33 @@ describe("MemoryLogger", () => {
describe("ConsoleFallbackLogger", () => {
test("不抛异常", () => {
const logger = createConsoleFallback();
logger.trace("trace");
logger.debug("debug");
logger.info("info");
logger.warn("warn");
logger.error("error");
logger.fatal("fatal");
logger.flush();
const child = logger.child({ component: "test" });
const child = captureConsole(() => {
const logger = createConsoleFallback();
logger.trace("trace");
logger.debug("debug");
logger.info("info");
logger.warn("warn");
logger.error("error");
logger.fatal("fatal");
logger.flush();
return logger.child({ component: "test" });
});
expect(child).toBeDefined();
});
test("按等级写入对应 console 通道", () => {
const output = captureConsole(() => {
const logger = createConsoleFallback();
logger.info("info");
logger.warn("warn");
logger.error("error");
logger.fatal("fatal");
});
expect(output.logs).toContain("info");
expect(output.warns).toContain("warn");
expect(output.errors).toEqual(["error", "fatal"]);
});
});
describe("Logger 接口契约", () => {
@@ -94,7 +139,7 @@ describe("Logger 接口契约", () => {
});
test("ConsoleFallbackLogger 满足 Logger 接口", () => {
expect(() => assertLogger(createConsoleFallback())).not.toThrow();
expect(() => captureConsole(() => assertLogger(createConsoleFallback()))).not.toThrow();
});
});