使用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
相关产品推荐
相关产品推荐

