feat: config loading and sqlite schema
This commit is contained in:
46
server/test/config.test.ts
Normal file
46
server/test/config.test.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { mkdtempSync, rmSync, readFileSync, existsSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import path from 'node:path'
|
||||
import { loadConfig } from '../src/config.js'
|
||||
|
||||
function tempDir(): string {
|
||||
return mkdtempSync(path.join(tmpdir(), 'rs-config-'))
|
||||
}
|
||||
|
||||
describe('loadConfig', () => {
|
||||
it('creates data + artwork dirs and returns paths', () => {
|
||||
const dir = tempDir()
|
||||
try {
|
||||
const cfg = loadConfig({ DATA_DIR: dir })
|
||||
expect(cfg.dataDir).toBe(dir)
|
||||
expect(cfg.dbPath).toBe(path.join(dir, 'record-shop.db'))
|
||||
expect(cfg.port).toBe(3000)
|
||||
expect(existsSync(path.join(dir, 'artwork-cache'))).toBe(true)
|
||||
expect(cfg.sessionSecret).toMatch(/^[0-9a-f]{64}$/)
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('persists and reuses the session secret', () => {
|
||||
const dir = tempDir()
|
||||
try {
|
||||
const a = loadConfig({ DATA_DIR: dir })
|
||||
const b = loadConfig({ DATA_DIR: dir })
|
||||
expect(a.sessionSecret).toBe(b.sessionSecret)
|
||||
expect(readFileSync(path.join(dir, 'session-secret'), 'utf8')).toBe(a.sessionSecret)
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('honours PORT', () => {
|
||||
const dir = tempDir()
|
||||
try {
|
||||
expect(loadConfig({ DATA_DIR: dir, PORT: '8080' }).port).toBe(8080)
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
37
server/test/db.test.ts
Normal file
37
server/test/db.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { openDatabase } from '../src/db.js'
|
||||
|
||||
describe('openDatabase', () => {
|
||||
it('creates the full schema', () => {
|
||||
const db = openDatabase(':memory:')
|
||||
const tables = (
|
||||
db.prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name").all() as {
|
||||
name: string
|
||||
}[]
|
||||
).map((r) => r.name)
|
||||
for (const t of [
|
||||
'users',
|
||||
'sessions',
|
||||
'settings',
|
||||
'collection_items',
|
||||
'digital_albums',
|
||||
'match_links',
|
||||
'app_meta',
|
||||
]) {
|
||||
expect(tables).toContain(t)
|
||||
}
|
||||
})
|
||||
|
||||
it('enforces unique (user_id, discogs_release_id)', () => {
|
||||
const db = openDatabase(':memory:')
|
||||
db.prepare(
|
||||
"INSERT INTO users (username, password_hash, is_admin) VALUES ('sam', 'x', 1)"
|
||||
).run()
|
||||
const insert = db.prepare(
|
||||
`INSERT INTO collection_items (user_id, discogs_release_id, title, artist)
|
||||
VALUES (1, 100, 'Album', 'Artist')`
|
||||
)
|
||||
insert.run()
|
||||
expect(() => insert.run()).toThrow()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user