使用Vitest编写测试时遇客户端访问服务端环境变量错误
Next.js App Router 中 Vitest 测试服务端环境变量访问错误
环境与背景
- 基于 TypeScript、Prisma、TRPC 构建 Next.js 应用
- 集成 Auth0 实现用户登录,采用新版 Next.js App Router
- 使用 Vitest 运行组件测试时,触发服务端环境变量被客户端访问的错误
测试代码
测试目标为验证app/page.tsx(Welcome 组件)是否显示指定文本:
import { render, screen } from "@testing-library/react"; import Welcome from "../app/page"; import { describe, test, expect, it } from "vitest"; test("1 + 1", () => { expect(1 + 1).toEqual(2); }); describe("Welcome", () => { test("welcome component displays", () => { render(<Welcome />); const message = screen.getByText("Hello"); expect(message).toBeVisible(); }); });
错误信息
运行测试时抛出如下错误:
Error: ❌ Attempted to access a server-side environment variable on the client ❯ onInvalidAccess node_modules/@t3-oss/core/index.ts:223:13 ❯ Object.get node_modules/@t3-oss/core/index.ts:246:16 ❯ src/server/db.ts:13:11 11| new PrismaClient({ 12| log: 13| env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"], | ^ 14| }); 15| ❯ src/server/auth.ts:5:31
排查尝试
- 确认
src/server/db.ts和src/server/auth.ts位于server目录下,符合服务端代码存放规范 - 尝试移除错误指向的代码片段,问题仍未解决
相关服务端代码
src/server/auth.ts
import { PrismaAdapter } from "@next-auth/prisma-adapter"; import { getServerSession, type DefaultSession, type NextAuthOptions, } from "next-auth"; import Auth0Provider from "next-auth/providers/auth0"; import { env } from "~/env.mjs"; import { db } from "~/server/db"; declare module "next-auth" { interface Session extends DefaultSession { user: { id: string; } & DefaultSession["user"]; } } export const authOptions: NextAuthOptions = { callbacks: { session: ({ session, user }) => ({ ...session, user: { ...session.user, id: user.id, }, }), }, adapter: PrismaAdapter(db), providers: [ Auth0Provider({ clientId: env.AUTH0_CLIENT_ID, clientSecret: env.AUTH0_CLIENT_SECRET, issuer: env.AUTH0_ISSUER_BASE_URL, authorization: { params: { prompt: "login", }, }, }), ], }; export const getServerAuthSession = () => getServerSession(authOptions);
src/server/db.ts
import { PrismaClient } from "@prisma/client"; import { env } from "~/env.mjs"; const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined; }; export const db = globalForPrisma.prisma ?? new PrismaClient({ log: env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"], }); if (env.NODE_ENV !== "production") globalForPrisma.prisma = db;
解决方案
原因分析
Vitest 默认在客户端上下文执行组件渲染,若app/page.tsx间接导入了服务端代码(比如 NextAuth 的getServerSession、Prisma 实例),会导致服务端环境变量被客户端代码访问,触发t3-oss的环境变量校验错误。
解决步骤
- 隔离服务端依赖:若 Welcome 组件中使用了服务端数据逻辑(如
getServerAuthSession),将这部分逻辑迁移到服务端组件或服务器动作中,避免客户端代码直接依赖服务端模块。 - Mock 服务端依赖:在 Vitest 中对服务端模块进行 mock,避免实际加载服务端代码:
// 在测试文件顶部添加 mock 代码 vi.mock("~/server/auth", () => ({ getServerAuthSession: vi.fn().mockResolvedValue({ user: { id: "test-id", name: "Test User", email: "test@example.com" }, }), })); vi.mock("~/server/db", () => ({ db: { // 根据组件实际使用的 Prisma 方法添加对应 mock }, })); - 确认组件类型:若
app/page.tsx是服务端组件,需调整测试方式,比如在服务端上下文执行测试,或改用 Next.js 官方测试工具链。 - 环境变量校验:检查
env.mjs配置,确保服务端环境变量未被标记为客户端可访问,避免跨上下文引用。
内容的提问来源于stack exchange,提问作者Mist
相关产品推荐
相关产品推荐

