Files
cms-website/tests/integration/global-setup.ts
T

43 lines
2.1 KiB
TypeScript
Raw Normal View History

// vitest globalSetup(Task 13):每次测试运行用完好的空临时库,结束即删——
// 彻底消除"测试碰开发库"与"清场残留"两类问题。
// 机制:用开发库凭据连维护库(postgres)CREATE DATABASE sf_test_<ts> →
// 用 drizzle-orm 程序化迁移器对临时库跑 apps/api/drizzle 全量迁移 →
// 设 process.env.DATABASE_URL_TEST(getDb() 的 DATABASE_URL_TEST ?? DATABASE_URL
// 回退链让所有测试自动连临时库;worker 由主进程在 setup 之后派生,env 继承生效)。
// 导出形式注意:vitest 的 globalSetup 加载器在有 default 导出时不捕获具名 teardown
// (loadGlobalSetupFile 的 if/default 分支只取 default 作 setup),故这里必须
// 用具名 setup + teardown 双导出、不写 default——teardown 才会被注册并在收尾执行。
// teardown DROP DATABASE 用 WITH (FORCE) 先断开残余业务连接再删;setup 中途失败也自清。
import { requireDatabaseUrl } from '../../apps/api/src/db/env.js'
import { createDatabase, dropDatabase, migrateDatabase } from '../../apps/api/src/db/migrate.js'
let created: { adminUrl: string; name: string } | undefined
export async function setup(): Promise<void> {
// 只认 DATABASE_URL(开发库凭据)——即便环境里残留 DATABASE_URL_TEST 也不受影响
const devUrl = requireDatabaseUrl({ allowTestUrl: false })
const adminUrl = new URL(devUrl)
adminUrl.pathname = '/postgres' // CREATE/DROP DATABASE 须在维护库会话里执行
const name = `sf_test_${Date.now()}`
const testUrl = new URL(devUrl)
testUrl.pathname = `/${name}`
await createDatabase(adminUrl.toString(), name)
try {
await migrateDatabase(testUrl.toString())
} catch (e) {
// 迁移半途而废:立即清掉本次临时库再抛出,失败运行也不留残留
await dropDatabase(adminUrl.toString(), name)
throw e
}
process.env.DATABASE_URL_TEST = testUrl.toString()
created = { adminUrl: adminUrl.toString(), name }
}
export async function teardown(): Promise<void> {
if (!created) return
const { adminUrl, name } = created
created = undefined
await dropDatabase(adminUrl, name)
}