You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sims-hq/apps/hq/test/db-resolve.test.ts

60 lines
2.9 KiB
TypeScript

// apps/hq/test/db-resolve.test.ts — pre-ship audit FIX A: server.ts and the deploy scripts
// (apps/hq/scripts/apply-onboarding-pipeline.ts, apps/hq/scripts/migrate-onboarding-templates.ts)
// must all resolve the DB engine + target through the ONE shared function. Before this fix
// the scripts computed it as `DATABASE_URL ?? ''` (no production fallback), so on the
// production box — where DATABASE_URL is unset — each script silently opened a brand-new
// empty SQLite file instead of the real Postgres.
import { describe, it, expect } from 'vitest'
import { pgTargetDescription, requireDbUrlForEnv, resolveDbUrl } from '../src/db-pg'
const HARDCODED = 'postgres://u:p@h:5432/db'
describe('resolveDbUrl (D19 engine selection, the one shared resolver)', () => {
it('DATABASE_URL wins regardless of NODE_ENV', () => {
expect(resolveDbUrl({ DATABASE_URL: 'postgres://x/y', NODE_ENV: 'production' })).toBe('postgres://x/y')
expect(resolveDbUrl({ DATABASE_URL: 'postgres://x/y' })).toBe('postgres://x/y')
})
it('falls back to the hardcoded production URL only when NODE_ENV=production and DATABASE_URL is unset', () => {
expect(resolveDbUrl({ NODE_ENV: 'production' }, HARDCODED)).toBe(HARDCODED)
})
it('resolves to SQLite (empty string) outside production with no DATABASE_URL — dev/tests stay green', () => {
expect(resolveDbUrl({})).toBe('')
expect(resolveDbUrl({ NODE_ENV: 'development' })).toBe('')
expect(resolveDbUrl({ NODE_ENV: 'test' })).toBe('')
})
})
describe('requireDbUrlForEnv (deploy-script guard — hard-fail instead of a throwaway SQLite write)', () => {
it('behaves exactly like resolveDbUrl when a Postgres target is available', () => {
expect(requireDbUrlForEnv({ DATABASE_URL: 'postgres://x/y' })).toBe('postgres://x/y')
expect(requireDbUrlForEnv({ NODE_ENV: 'production' }, HARDCODED)).toBe(HARDCODED)
expect(requireDbUrlForEnv({})).toBe('') // dev with no env: SQLite is fine, no hard-fail
})
it('hard-fails instead of silently returning SQLite when NODE_ENV=production resolves nothing', () => {
// Simulates the hardcoded URL having been accidentally emptied out.
expect(() => requireDbUrlForEnv({ NODE_ENV: 'production' }, '')).toThrow(/refusing to run/i)
})
})
describe('pgTargetDescription (never leaks the password into logs)', () => {
it('extracts host:port/dbname', () => {
expect(pgTargetDescription('postgres://user:secret@db.example.com:5432/hq'))
.toBe('db.example.com:5432/hq')
})
it('omits the port when absent', () => {
expect(pgTargetDescription('postgres://user:secret@db.example.com/hq')).toBe('db.example.com/hq')
})
it('never includes the credentials', () => {
expect(pgTargetDescription('postgres://user:hunter2@host/db')).not.toContain('hunter2')
})
it('degrades gracefully on an unparsable string', () => {
expect(pgTargetDescription('not-a-url')).toMatch(/unparsable/i)
})
})