import { mkdtempSync } from 'node:fs' import { tmpdir } from 'node:os' import path from 'node:path' import { openDatabase, type DB } from '../src/db.js' import { buildApp } from '../src/app.js' import type { Config } from '../src/config.js' import type { FastifyInstance } from 'fastify' export function testConfig(): Config { // artworkDir must be a real writable directory (cached images land there) const artworkDir = mkdtempSync(path.join(tmpdir(), 'rs-art-')) // dataDir must be a real writable directory (release-cache payloads land there) const dataDir = mkdtempSync(path.join(tmpdir(), 'rs-data-')) return { dataDir, artworkDir, dbPath: ':memory:', port: 0, sessionSecret: 'test-secret-test-secret-test-secret-1234', } } export async function buildTestApp(fetchImpl?: typeof fetch): Promise { const db = openDatabase(':memory:') return buildApp({ db, config: testConfig(), fetchImpl }) } export async function buildTestAppWithDb(db: DB, fetchImpl?: typeof fetch): Promise { return buildApp({ db, config: testConfig(), fetchImpl }) } /** Runs /api/setup to create admin 'admin' / 'adminpass123'. Returns session token value. */ export async function setupAdmin(app: FastifyInstance): Promise { const res = await app.inject({ method: 'POST', url: '/api/setup', payload: { username: 'admin', password: 'adminpass123' }, }) if (res.statusCode !== 200) throw new Error(`setup failed: ${res.body}`) return getCookie(res) } /** Creates and logs in a non-admin user via /api/users + /api/login. Returns session token value. */ export async function loginAs( app: FastifyInstance, adminToken: string, username: string, password: string ): Promise { const created = await app.inject({ method: 'POST', url: '/api/users', ...auth(adminToken), payload: { username, password }, }) if (created.statusCode !== 200) throw new Error(`user create failed: ${created.body}`) const login = await app.inject({ method: 'POST', url: '/api/login', payload: { username, password } }) if (login.statusCode !== 200) throw new Error(`login failed: ${login.body}`) return getCookie(login) } export function getCookie(res: { cookies: { name: string; value: string }[] }): string { const cookie = res.cookies.find((c) => c.name === 'rs_session') if (!cookie) throw new Error('no rs_session cookie in response') return cookie.value } /** inject option spread for an authenticated request: `app.inject({ ..., ...auth(token) })` */ export function auth(sessionToken: string): { cookies: Record } { return { cookies: { rs_session: sessionToken } } }