Files
pablan/frontend/e2e/residue.ts
T
ProfessorNovaandClaude Opus 5 784b76baf7 Pablan, as it stands
Self-hosted knowledge management for SMEs: a split-screen Markdown editor
whose sections an LLM refines while you write, and RAG question answering
over the documents that result. FastAPI + Postgres/pgvector on the back,
SvelteKit on the front, everything OpenAI-compatible and self-hostable.

Squashed into a single commit; the development history stays local.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CA43ZJda8Rbp2hKXNy8f6b
2026-09-04 09:21:37 +02:00

59 lines
1.8 KiB
TypeScript

// Zero-residue guard: the e2e suite must leave the dev database exactly as
// it found it. globalSetup snapshots row counts, globalTeardown re-counts
// and fails the run on any difference.
//
// Documented exception: done/failed rows in `jobs` are execution history
// (the queue's audit trail); only unprocessed jobs count as residue.
import { execSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
const TABLES = [
'users',
'departments',
'templates',
'conversations',
'messages',
'documents',
'chunks',
'doc_permissions',
'auth_sessions',
'llm_settings'
];
const SNAPSHOT = path.join(import.meta.dirname, '..', 'test-results', 'row-counts.json');
function query(sql: string): string {
return execSync(`docker exec pablan-dev-postgres-1 psql -tA -U pablan -d pablan -c "${sql}"`)
.toString()
.trim();
}
export function snapshotCounts(): Record<string, number> {
const counts: Record<string, number> = {};
for (const table of TABLES) {
counts[table] = Number(query(`SELECT count(*) FROM ${table}`));
}
counts['jobs (unprocessed)'] = Number(
query(`SELECT count(*) FROM jobs WHERE status IN ('pending','running')`)
);
return counts;
}
export async function globalSetup(): Promise<void> {
fs.mkdirSync(path.dirname(SNAPSHOT), { recursive: true });
fs.writeFileSync(SNAPSHOT, JSON.stringify(snapshotCounts(), null, 2));
}
export async function globalTeardown(): Promise<void> {
const before = JSON.parse(fs.readFileSync(SNAPSHOT, 'utf-8')) as Record<string, number>;
const after = snapshotCounts();
const diffs = Object.keys(after)
.filter((key) => before[key] !== after[key])
.map((key) => ` ${key}: ${before[key]} -> ${after[key]}`);
if (diffs.length > 0) {
throw new Error(`e2e suite left residue in the database:\n${diffs.join('\n')}`);
}
}