Error statuses follow one rule: APIException takes a status and derives the code from it (BAD_REQUEST 400, UNAUTHORIZED 401, FORBIDDEN 403, NOT_FOUND 404, CONFLICT 409, RATE_LIMITED 429, SERVER_ERROR 500, BAD_GATEWAY 502), so a code can't contradict its status. That fixed real bugs: a wrong current password on change-password answered 401, on which authFetch signs the user out; editing or deleting someone else's comment or chat message answered 401 rather than 403; one invalid dump edit answered 422. A taken username is 409, like a taken email. Along the way: the database is created from schema.sql by connection.ts when the file doesn't exist, so every task works on a fresh checkout (dev and serve never ran db/init.ts, which is gone); the startup purge compared ISO dates with SQLite's datetime() as text and kept anything from the current UTC day, and now compares ISO cutoffs; the seeded admin's hash comes from lib/password.ts (split out of jwt.ts, which needs the JWT secret) rather than a copy of its format; avatar, thumbnail and playlist-cover uploads go through replaceUploadedFile, which writes beside the old file and renames over it before the record announces it (a failed avatar write lost the old avatar; a thumbnail was announced before it existed); upload.ts derives its size message from MAX_IMAGE_SIZE_BYTES and stops re-exporting the upload folders; ALLOWED_IMAGE_MIMES, which duplicated detectImageMime, is gone; the SPA fallback no longer calls next() after answering; a reply must answer a comment on the same dump (a foreign or unknown parent was a 500 or a cross-dump thread). 211 backend and 628 frontend tests pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
24 lines
1.2 KiB
TypeScript
24 lines
1.2 KiB
TypeScript
// Points the app at a throwaway database and uploads directory before any app
|
|
// module is evaluated. api/config.ts reads the environment and api/db/connection.ts
|
|
// opens the database at import time, creating it from schema.sql, so this
|
|
// module must be the first import of every test file — directly, or as
|
|
// helpers.ts's first import. It imports nothing from the app itself, and it is
|
|
// synchronous on purpose: a module with a top-level await doesn't hold back
|
|
// the sibling imports that follow it.
|
|
export const TEST_DIR = Deno.makeTempDirSync({ prefix: "gerbeur-test-" });
|
|
|
|
Deno.env.set("GERBEUR_DB_PATH", `${TEST_DIR}/gerbeur.db`);
|
|
Deno.env.set("GERBEUR_UPLOADS_DIR", `${TEST_DIR}/uploads`);
|
|
Deno.env.set("GERBEUR_JWT_SECRET", "test-secret-test-secret-test-secret");
|
|
Deno.env.set("GERBEUR_PUBLIC_URL", "http://gerbeur.test");
|
|
Deno.env.set("GERBEUR_ALLOWED_ORIGINS", "http://allowed.test");
|
|
// The suite never sends mail; the routes behave as on an instance without SMTP.
|
|
Deno.env.delete("GERBEUR_SMTPS_URL");
|
|
|
|
// The migrations, the error middleware and failed fetches all log; a passing
|
|
// run shouldn't drown in them. TEST_VERBOSE=1 brings them back for debugging.
|
|
if (!Deno.env.get("TEST_VERBOSE")) {
|
|
console.log = () => {};
|
|
console.error = () => {};
|
|
}
|