API 测试失败的根本原因不是数据库或认证 Token 问题,而是 Next.js Server API 与测试环境的兼容性问题。
cookies() 调用限制
cookies was called outside a request scopesrc/lib/auth.ts → getAuthCookie() → cookies()cookies() 只能在真实的 HTTP 请求上下文中调用,测试环境的模拟 Request 无法提供该上下文getTranslations() 限制
getTranslations is not supported in Client Componentssrc/actions/users.ts → addUser() 等函数内getTranslations() 需要 Next.js 运行时环境,测试环境无法提供validateKey()validateKey() 内部调用了 cookies()addUser() 等函数调用了 getTranslations()在测试环境中 Mock cookies() 和 getTranslations(),让测试能够正常运行。
优点:
实现步骤:
创建测试 Mock 文件 tests/mocks/nextjs.ts:
import { vi } from "vitest";
// Mock next/headers cookies
vi.mock("next/headers", () => ({
cookies: vi.fn(() => ({
get: vi.fn((name: string) => {
// 从测试环境变量读取 Cookie
if (name === "auth-token") {
return { value: process.env.TEST_ADMIN_TOKEN || "test-admin-token" };
}
return undefined;
}),
set: vi.fn(),
delete: vi.fn(),
})),
}));
// Mock next-intl getTranslations
vi.mock("next-intl/server", () => ({
getTranslations: vi.fn(() => {
return (key: string, params?: Record<string, unknown>) => {
// 返回简单的英文消息(或使用 i18n 文件)
const messages: Record<string, string> = {
"users.created": "User created successfully",
"users.updated": "User updated successfully",
"users.deleted": "User deleted successfully",
"errors.unauthorized": "Unauthorized",
"errors.forbidden": "Forbidden",
// ... 更多翻译
};
let msg = messages[key] || key;
if (params) {
Object.entries(params).forEach(([k, v]) => {
msg = msg.replace(`{${k}}`, String(v));
});
}
return msg;
};
}),
}));
在 tests/setup.ts 中导入:
import "./mocks/nextjs";
不使用 callActionsRoute 直接调用 Server Actions,而是启动真实的 Next.js 开发服务器,通过 HTTP 请求测试 API。
优点:
缺点:
只测试不依赖 Next.js 特定功能的纯逻辑函数。
缺点:
文件:tests/mocks/nextjs.ts
tests/setup.ts在顶部添加:
import "./mocks/nextjs";
某些测试可能需要调整期望值,因为 Mock 环境与真实环境有差异。
npm run test
这个问题暴露了以下技术债务:
过度依赖 Next.js 特定 API
cookies() 应该通过依赖注入或上下文传递getTranslations() 应该有降级方案缺少测试友好的抽象层
AuthService 和 I18nService 抽象,便于 Mock文档不完善
状态:待修复 优先级:高 预计工作量:1-2 小时