refactor: 代码审查修复 — 错误边界、DRY抽取、测试修复、合规性改进
- P1: server.ts 统一错误边界 (withErrorHandler + AppError),修复 3 个失败/卡死测试 - P2: db 层 wrap/paginateQuery 抽取,前端 handleResponse 抽取,parseIdFromUrl 抽取 - P3: middleware 验证消息中文化,Flex→Space 替换 - P0: docs/development/README.md 新增已知设计决策章节 - P3-11 setup 拆分已尝试回退(@testing-library/react preload 依赖无法拆分) - P3-13 config 层测试从本次变更移除
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-function, @typescript-eslint/require-await */
|
||||
import { describe, expect, test } from "bun:test";
|
||||
/* eslint-disable @typescript-eslint/require-await */
|
||||
import { afterEach, describe, expect, test } from "bun:test";
|
||||
import { mkdirSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
@@ -49,6 +49,19 @@ function makeTempConfig(overrides: Partial<ResolvedConfig> = {}): ResolvedConfig
|
||||
}
|
||||
|
||||
describe("bootstrap", () => {
|
||||
const shutdownHandlers: Array<() => void> = [];
|
||||
|
||||
afterEach(() => {
|
||||
for (const fn of shutdownHandlers) {
|
||||
try {
|
||||
fn();
|
||||
} catch {
|
||||
// exit mock throws, that's expected
|
||||
}
|
||||
}
|
||||
shutdownHandlers.length = 0;
|
||||
});
|
||||
|
||||
test("使用默认依赖启动", async () => {
|
||||
let started = false;
|
||||
let signalRegistered = false;
|
||||
@@ -56,7 +69,8 @@ describe("bootstrap", () => {
|
||||
|
||||
const cfg = makeTempConfig();
|
||||
const mockLoadConfig = (async () => cfg) as unknown as BootstrapDependencies["loadConfig"];
|
||||
const mockOnSignal = (_signal: string, _handler: () => void) => {
|
||||
const mockOnSignal = (_signal: string, handler: () => void) => {
|
||||
shutdownHandlers.push(handler);
|
||||
signalRegistered = true;
|
||||
};
|
||||
const mockStartServer = (options: StartServerOptions) => {
|
||||
@@ -67,6 +81,9 @@ describe("bootstrap", () => {
|
||||
|
||||
const deps: BootstrapDependencies = {
|
||||
createLogger: async () => createMemoryLogger(),
|
||||
exit: (code: number) => {
|
||||
throw new Error(`exit(${code})`);
|
||||
},
|
||||
loadConfig: mockLoadConfig,
|
||||
onSignal: mockOnSignal,
|
||||
startServer: mockStartServer,
|
||||
@@ -90,8 +107,13 @@ describe("bootstrap", () => {
|
||||
expect(version).toBe("1.2.3");
|
||||
return createMemoryLogger();
|
||||
},
|
||||
exit: (code: number) => {
|
||||
throw new Error(`exit(${code})`);
|
||||
},
|
||||
loadConfig: async () => cfg,
|
||||
onSignal: () => {},
|
||||
onSignal: (_signal, handler) => {
|
||||
shutdownHandlers.push(handler);
|
||||
},
|
||||
startServer: (options: StartServerOptions) => {
|
||||
receivedVersion = options.version;
|
||||
return {};
|
||||
@@ -191,7 +213,13 @@ describe("bootstrap", () => {
|
||||
|
||||
const deps: BootstrapDependencies = {
|
||||
createLogger: async () => mockLogger,
|
||||
exit: (code: number) => {
|
||||
throw new Error(`exit(${code})`);
|
||||
},
|
||||
loadConfig: async () => cfg,
|
||||
onSignal: (_signal, handler) => {
|
||||
shutdownHandlers.push(handler);
|
||||
},
|
||||
startServer: () => ({}),
|
||||
};
|
||||
|
||||
@@ -202,7 +230,7 @@ describe("bootstrap", () => {
|
||||
|
||||
test("shutdown 时 flush logger", async () => {
|
||||
let flushed = false;
|
||||
let shutdownHandler: (() => void) | undefined;
|
||||
let exitCode: number | undefined;
|
||||
|
||||
const mockLogger = createMemoryLogger();
|
||||
mockLogger.flush = () => {
|
||||
@@ -212,17 +240,29 @@ describe("bootstrap", () => {
|
||||
const cfg = makeTempConfig();
|
||||
const deps: BootstrapDependencies = {
|
||||
createLogger: async () => mockLogger,
|
||||
exit: (code: number) => {
|
||||
exitCode = code;
|
||||
throw new Error("exit called");
|
||||
},
|
||||
loadConfig: async () => cfg,
|
||||
onSignal: (_signal, handler) => {
|
||||
shutdownHandler = handler;
|
||||
shutdownHandlers.push(handler);
|
||||
},
|
||||
startServer: () => ({}),
|
||||
};
|
||||
|
||||
await bootstrap({ configPath: join(cfg.configDir, "config.yaml"), mode: "production" }, deps);
|
||||
|
||||
expect(shutdownHandler).toBeDefined();
|
||||
shutdownHandler!();
|
||||
const handler = shutdownHandlers.pop();
|
||||
expect(handler).toBeDefined();
|
||||
|
||||
try {
|
||||
handler!();
|
||||
} catch {
|
||||
// expected - exit threw
|
||||
}
|
||||
|
||||
expect(flushed).toBe(true);
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -224,7 +224,8 @@ describe("loadServerConfig", () => {
|
||||
await loadServerConfig(yamlPath);
|
||||
expect.unreachable();
|
||||
} catch (error) {
|
||||
expect((error as Error).message).toContain("日志等级");
|
||||
expect((error as Error).message).toContain("server.logging.level");
|
||||
expect((error as Error).message).toContain("不在允许范围内");
|
||||
} finally {
|
||||
await rm(yamlPath, { force: true });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user