test: split vitest into node + nuxt projects and add a Postgres harness
Component/runtime specs (*.nuxt.spec.ts) run in the Nuxt environment; all other specs run in a plain node environment where node_modules stay external, so native CJS deps like `pg` load correctly (the Nuxt runtime inlines them and breaks pg's internal `class … extends Pool`). Adds tests/helpers/db.ts, which spins up and migrates a dedicated test database for repository integration tests, and renames the board spec to the .nuxt suffix.
This commit is contained in:
57
tests/helpers/db.ts
Normal file
57
tests/helpers/db.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Integration-test harness for the Postgres-backed repositories.
|
||||||
|
//
|
||||||
|
// Tests run against a dedicated database (default `andon_test`) so they never
|
||||||
|
// touch dev data. The database is created if missing and migrated to the
|
||||||
|
// current schema; `truncateAll` resets state between tests.
|
||||||
|
import { createRequire } from 'node:module'
|
||||||
|
import type pgType from 'pg'
|
||||||
|
import { drizzle, type NodePgDatabase } from 'drizzle-orm/node-postgres'
|
||||||
|
import { migrate } from 'drizzle-orm/node-postgres/migrator'
|
||||||
|
import { sql } from 'drizzle-orm'
|
||||||
|
import * as schema from '../../server/db/schema'
|
||||||
|
|
||||||
|
// Load `pg` through a native CJS require. Importing it via Vite's SSR transform
|
||||||
|
// breaks pg's internal `class … extends Pool` (the require of `pg-pool` resolves
|
||||||
|
// to a module namespace), so we sidestep the transform entirely.
|
||||||
|
const pg = createRequire(import.meta.url)('pg') as typeof pgType
|
||||||
|
|
||||||
|
const TEST_URL =
|
||||||
|
process.env.TEST_DATABASE_URL ??
|
||||||
|
'postgres://andon:andon@localhost:5432/andon_test'
|
||||||
|
|
||||||
|
export type TestDb = NodePgDatabase<typeof schema>
|
||||||
|
|
||||||
|
/** Connect to the test database (creating + migrating it first) and return a client + pool. */
|
||||||
|
export async function setupTestDb(): Promise<{ db: TestDb; pool: pgType.Pool }> {
|
||||||
|
await ensureDatabaseExists(TEST_URL)
|
||||||
|
const pool = new pg.Pool({ connectionString: TEST_URL })
|
||||||
|
const db = drizzle(pool, { schema })
|
||||||
|
await migrate(db, { migrationsFolder: 'server/db/migrations' })
|
||||||
|
return { db, pool }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Wipe all rows so each test starts from a clean slate. */
|
||||||
|
export async function truncateAll(db: TestDb): Promise<void> {
|
||||||
|
await db.execute(
|
||||||
|
sql`TRUNCATE TABLE defects, projects, push_subscriptions RESTART IDENTITY CASCADE`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create the target database via the maintenance `postgres` DB if it doesn't exist. */
|
||||||
|
async function ensureDatabaseExists(url: string): Promise<void> {
|
||||||
|
const dbName = new URL(url).pathname.slice(1)
|
||||||
|
const adminUrl = new URL(url)
|
||||||
|
adminUrl.pathname = '/postgres'
|
||||||
|
|
||||||
|
const admin = new pg.Client({ connectionString: adminUrl.toString() })
|
||||||
|
await admin.connect()
|
||||||
|
try {
|
||||||
|
const { rowCount } = await admin.query(
|
||||||
|
'SELECT 1 FROM pg_database WHERE datname = $1',
|
||||||
|
[dbName],
|
||||||
|
)
|
||||||
|
if (!rowCount) await admin.query(`CREATE DATABASE "${dbName}"`)
|
||||||
|
} finally {
|
||||||
|
await admin.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,30 @@
|
|||||||
|
import { defineConfig } from 'vitest/config'
|
||||||
import { defineVitestConfig } from '@nuxt/test-utils/config'
|
import { defineVitestConfig } from '@nuxt/test-utils/config'
|
||||||
|
|
||||||
export default defineVitestConfig({
|
// Two projects, split by filename:
|
||||||
|
// • *.nuxt.spec.ts → run in the Nuxt runtime (components, anything needing
|
||||||
|
// auto-imports or the app environment).
|
||||||
|
// • everything else → a plain node environment. node_modules stay external,
|
||||||
|
// so native CJS deps like `pg` load correctly (the Nuxt runtime inlines them
|
||||||
|
// and breaks pg's internal `class … extends Pool`).
|
||||||
|
export default defineConfig({
|
||||||
test: {
|
test: {
|
||||||
// Default to a plain node environment; component/integration specs opt into
|
projects: [
|
||||||
// the Nuxt runtime per-file with `// @vitest-environment nuxt`.
|
{
|
||||||
environment: 'node',
|
test: {
|
||||||
|
name: 'server',
|
||||||
|
environment: 'node',
|
||||||
|
include: ['tests/**/*.spec.ts'],
|
||||||
|
exclude: ['tests/**/*.nuxt.spec.ts'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defineVitestConfig({
|
||||||
|
test: {
|
||||||
|
name: 'nuxt',
|
||||||
|
environment: 'nuxt',
|
||||||
|
include: ['tests/**/*.nuxt.spec.ts'],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user