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

如何在Next.js13 App目录的Cypress测试中Mock NextAuth的/api/auth/session会话对象?

在Cypress中Mock NextAuth服务端会话(Next.js 13 App Router)

针对你遇到的Next.js 13.4.4 App Router + NextAuth v4.22.1的服务端会话无法在Cypress 12.3.0中Mock的问题,下面提供几个实用的解决方案:

方案1:测试环境下修改NextAuth配置,直接返回Mock会话

这个方案无需修改业务代码,只在NextAuth的认证逻辑中加入测试环境判断,绕过真实认证直接返回预设用户会话。

步骤:

  1. 配置测试环境变量
    在cypress.config.ts中添加Cypress专属环境变量:

    import { defineConfig } from "cypress";
    
    export default defineConfig({
      e2e: {
        env: {
          NEXT_PUBLIC_CYPRESS_TEST: "true",
        },
        // 其他Cypress配置
      },
    });
    
  2. 修改NextAuth路由配置
    在app/api/auth/[...nextauth]/route.ts中,针对测试环境修改认证和会话回调:

    import NextAuth from "next-auth";
    import CredentialsProvider from "next-auth/providers/credentials";
    
    const handler = NextAuth({
      providers: [
        CredentialsProvider({
          async authorize(credentials, req) {
            // 测试环境直接返回Mock用户
            if (process.env.NEXT_PUBLIC_CYPRESS_TEST === "true") {
              return {
                id: "1",
                name: "Test User",
                email: "test@example.com",
                // 按需添加其他用户字段
              };
            }
            // 生产/开发环境的正常凭证认证逻辑
            const user = // 你的数据库查询或验证逻辑
            return user ?? null;
          },
        }),
      ],
      session: { strategy: "jwt" }, // 保持你原本的session策略
      callbacks: {
        async session({ session, token }) {
          // 测试环境注入Mock会话数据
          if (process.env.NEXT_PUBLIC_CYPRESS_TEST === "true") {
            return {
              ...session,
              user: {
                id: "1",
                name: "Test User",
                email: "test@example.com",
              },
              expires: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
            };
          }
          // 正常环境的session回调逻辑
          session.user.id = token.sub!;
          return session;
        },
      },
    });
    
    export { handler as GET, handler as POST };
    
  3. 在Cypress测试中启用Mock
    在cypress/support/e2e.ts中添加全局前置操作,确保测试环境变量生效:

    beforeEach(() => {
      cy.visit("/", {
        onBeforeLoad(win) {
          win.localStorage.setItem("NEXT_PUBLIC_CYPRESS_TEST", "true");
        },
      });
    });
    

之后编写测试用例时,直接访问受保护页面即可自动获取Mock会话,无需登录操作。

NextAuth的会话通过HttpOnly Cookie存储,Cypress可以直接设置这个Cookie来模拟已登录状态。

步骤:

  1. 添加Cypress自定义命令
    在cypress/support/commands.ts中定义设置Mock会话的命令:

    import jwt from "jsonwebtoken";
    
    Cypress.Commands.add("mockNextAuthSession", () => {
      const secret = Cypress.env("NEXTAUTH_SECRET");
      if (!secret) throw new Error("请在Cypress环境变量中配置NEXTAUTH_SECRET");
    
      // 生成符合NextAuth格式的JWT Token
      const mockToken = jwt.sign(
        {
          sub: "1",
          name: "Test User",
          email: "test@example.com",
          iat: Math.floor(Date.now() / 1000),
          exp: Math.floor(Date.now() / 1000) + 24 * 60 * 60, // 24小时过期
        },
        secret,
        { algorithm: "HS256" }
      );
    
      // 设置Session Cookie,参数根据你的应用配置调整
      cy.setCookie("__Secure-next-auth.session-token", mockToken, {
        domain: "localhost",
        path: "/",
        secure: false, // 开发环境HTTP下设为false,HTTPS设为true
        httpOnly: true,
      });
    });
    
  2. 在测试用例中使用

    describe("受保护页面测试", () => {
      it("无需登录即可访问受保护内容", () => {
        cy.mockNextAuthSession();
        cy.visit("/protected");
        cy.contains("欢迎,Test User").should("可见");
      });
    });
    

方案3:拦截服务端Session请求(针对Server Components)

如果你的受保护页面使用了Server Components,客户端的cy.intercept无法拦截服务端发起的Session请求,此时可以通过Next.js的Middleware注入Mock会话。

步骤:

  1. 创建Middleware注入Mock会话头
    在项目根目录创建middleware.ts:

    import { NextResponse } from "next/server";
    import type { NextRequest } from "next/server";
    
    export function middleware(request: NextRequest) {
      if (process.env.NEXT_PUBLIC_CYPRESS_TEST === "true") {
        const mockSession = JSON.stringify({
          user: { id: "1", name: "Test User", email: "test@example.com" },
          expires: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
        });
    
        const requestHeaders = new Headers(request.headers);
        requestHeaders.set("x-mock-session", mockSession);
    
        return NextResponse.next({
          request: { headers: requestHeaders },
        });
      }
    
      return NextResponse.next();
    }
    
    export const config = {
      matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
    };
    
  2. 修改Server Component中的Session获取逻辑
    在Server Component中判断测试环境,优先使用Mock会话:

    import { getServerSession } from "next-auth/next";
    import { authOptions } from "@/app/api/auth/[...nextauth]/route";
    import { headers } from "next/headers";
    
    export default async function ProtectedPage() {
      let session;
      const headersList = headers();
      const mockSession = headersList.get("x-mock-session");
    
      if (process.env.NEXT_PUBLIC_CYPRESS_TEST === "true" && mockSession) {
        session = JSON.parse(mockSession);
      } else {
        session = await getServerSession(authOptions);
      }
    
      if (!session) return <div>未授权</div>;
    
      return <div>欢迎,{session.user.name}</div>;
    }
    

这个方案侵入性稍强,适合必须保留Server Component原生会话获取逻辑的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 09:35:41