当我在一个独立的环境中运行测试时,Prisma ORM客户端使用了错误的数据库URL

前端开发 2026-07-12

我在用vitest运行端到端测试。计划为测试创建一个不同的PostgreSQL模式。为了自动配置这个模式,我已经按vitest的文档这么做了:

// vitest-environment-prisma.ts

import { execSync } from 'node:child_process'
import { randomUUID } from 'node:crypto'
import type { Environment } from 'vitest/environments'
import 'dotenv/config'

function makeDatabaseUrl(schema: string) {
  const connectionString = process.env.DATABASE_URL

  if (!connectionString) {
    throw new Error('DATABASE_URL environment variable missing.')
  }

  const databaseUrl = new URL(connectionString)
  databaseUrl.searchParams.set('schema', schema)

  return databaseUrl.toString()
}

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 () {
      },
    }
  },
}

现在,我尝试运行到目前为止唯一的端到端测试:

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

describe('Register User (e2e)', () => {
  beforeAll(async () => {
    await app.ready()
  })

  afterAll(async () => {
    await app.close()
  })

  it('Should register user', async () => {
    const a = await prisma.$queryRaw`SELECT current_schema();`
    console.log(a)

    const user = {
      name: 'John Doe',
      email: '[email protected]',
      password: '12435djdj!',
    }

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

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

我一直收到一个错误,说用户已经存在。这是我的应用的行为。不过,由于我应该使用一个干净的数据库模式,里面不应该有任何东西。所以我增加了那个“a”的console.log,结果是: [ { current_schema: 'public' } ]

所以Prisma仍然使用默认的模式,尽管我把process.env.DATABASE_URL改成了一个全新的模式。

我到底做错了什么? 编辑:这是我的lib/prisma.ts文件:(我不知道怎么排版)

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

export const prisma = new PrismaClient({
    adapter: new PrismaPg({
        connectionString: env.DATABASE_URL,
    }),
    log: env.NODE_ENV === 'development' ? ['query'] : [],
})

解决方案

你创建Prisma过早了。

env.DATABASE_URL 在模块加载时读取一次,因此你的客户端一直使用原始URL,尽管你的Vitest环境后续会改变 process.env.DATABASE_URL

与此同时,prisma migrate deploy 确实使用了新的URL,导致不匹配。

修复:

  • 不要使用预构建的单例
  • 这里不要使用 env.DATABASE_URL
  • 在设置 process.env.DATABASE_URL 之后再创建Prisma
export function makePrisma() {
  return new PrismaClient({
    adapter: new PrismaPg({
      connectionString: process.env.DATABASE_URL!,
    }),
  })
}

然后在你的测试/应用中,在设置好模式后再初始化它。

如果仍然命中 public,你很可能遇到了一个已知的 @prisma/adapter-pg 模式问题。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章