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

使用Vitest执行E2E测试时,Prisma ORM客户端未使用指定的测试数据库Schema

Vitest执行E2E测试时,Prisma ORM客户端未使用指定的测试数据库Schema

嘿,问题出在你的Prisma客户端实例初始化时机上!

你在lib/prisma.ts里直接导出了一个提前创建好的PrismaClient实例,这个实例在应用模块加载的时候就已经初始化完成了——也就是在Vitest的setup阶段修改process.env.DATABASE_URL之前。所以哪怕你后来改了环境变量,这个已经创建好的客户端还是会用最开始的env.DATABASE_URL(也就是指向public schema的那个),自然不会用你生成的新schema。

给你几个关键的修复步骤:

1. 把Prisma客户端改成动态创建的方式

先修改lib/prisma.ts,不要直接导出实例,改成导出一个创建客户端的函数,这样我们可以在需要的时候(比如测试环境)重新生成实例:

import { env } from '@/env/index.js'
import { PrismaClient } from '../../prisma/generated/prisma/client.js'
import { PrismaPg } from '@prisma/adapter-pg'

export function createPrismaClient() {
  // 优先用当前的process.env.DATABASE_URL,没有的话再用env里的默认值
  const connectionString = process.env.DATABASE_URL || env.DATABASE_URL
  
  return new PrismaClient({
    adapter: new PrismaPg({ connectionString }),
    log: env.NODE_ENV === 'development' ? ['query'] : [],
  })
}

// 开发环境还是可以直接导出默认实例,不影响正常使用
export const prisma = createPrismaClient()

2. 在测试中重新创建Prisma实例

在你的E2E测试文件里,不要直接导入原来的prisma实例,而是在beforeAll里调用createPrismaClient()——这时候Vitest已经修改了process.env.DATABASE_URL,所以新创建的客户端会自动使用测试用的schema:

import { app } from '@/app.js'
import { createPrismaClient } from '@/lib/prisma.js'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'

describe('Register User (e2e)', () => {
  let prisma: ReturnType<typeof createPrismaClient>

  beforeAll(async () => {
    // 这里创建的实例会用测试环境的DATABASE_URL
    prisma = createPrismaClient()
    await app.ready()
  })

  afterAll(async () => {
    // 别忘了断开Prisma连接
    await prisma.$disconnect()
    await app.close()
  })

  it('Should register user', async () => {
    const a = await prisma.$queryRaw`SELECT current_schema();`
    console.log(a) // 现在应该显示你生成的UUID schema了

    const user = {
      name: 'John Doe',
      email: 'johndoe@example.com',
      password: '12435djdj!',
    }

    const response = await app.inject({
      method: 'POST',
      path: '/users',
      body: user,
    })

    expect(response.statusCode).toEqual(201)
  })
})

3. 补充:清理测试用的Schema

你的Vitest环境setup里的teardown是空的,测试结束后记得删除生成的schema,不然数据库里会堆满无用的UUID命名的schema:

export default <Environment> {
  name: 'prisma',
  viteEnvironment: 'ssr',
  setup: async function () {
    const schema = randomUUID()
    process.env.DATABASE_URL = makeDatabaseUrl(schema)

    execSync('npx prisma migrate deploy')

    return {
      teardown: async function () {
        // 删除测试用的schema,CASCADE会连带删除里面的所有表
        execSync(`psql ${process.env.DATABASE_URL} -c "DROP SCHEMA IF EXISTS \"${schema}\" CASCADE;"`)
      },
    }
  },
}

这样改完之后,你的测试应该就能正确使用独立的测试schema,不会再出现用户已存在的错误啦!

备注:内容来源于stack exchange,提问作者tintin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 17:50:29