You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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的环境变量校验错误。

解决步骤

  1. 隔离服务端依赖:若 Welcome 组件中使用了服务端数据逻辑(如getServerAuthSession),将这部分逻辑迁移到服务端组件或服务器动作中,避免客户端代码直接依赖服务端模块。
  2. 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
      },
    }));
    
  3. 确认组件类型:若app/page.tsx是服务端组件,需调整测试方式,比如在服务端上下文执行测试,或改用 Next.js 官方测试工具链。
  4. 环境变量校验:检查env.mjs配置,确保服务端环境变量未被标记为客户端可访问,避免跨上下文引用。

内容的提问来源于stack exchange,提问作者Mist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 18:23:31