diff --git a/bunfig.toml b/bunfig.toml
index 082bcacd..d073e330 100644
--- a/bunfig.toml
+++ b/bunfig.toml
@@ -1,4 +1,5 @@
[test]
+preload = ["./tests/preload.ts"]
coverage = true
coveragePathIgnorePatterns = [
"tests/converters/helpers/commonTests.ts"
diff --git a/tests/db/db.test.ts b/tests/db/db.test.ts
index 49ec9420..29a5f903 100644
--- a/tests/db/db.test.ts
+++ b/tests/db/db.test.ts
@@ -1,11 +1,8 @@
-import { test, expect, beforeEach, afterEach, afterAll } from "bun:test";
+import { test, expect, beforeEach, afterEach } from "bun:test";
import { Database } from "bun:sqlite";
import { unlinkSync, existsSync, mkdirSync } from "node:fs";
-// set environment variable to ensure the test database is used instead of production data
-process.env.DB_PATH = "./data/test-isolated.sqlite";
-
-// dynamic import ensures that db.ts is loaded after the env is set
+// tests/preload.ts points DB_PATH at a temporary database, so production data is never used
let initializeDatabase: (db: Database) => void;
let defaultDb: Database | undefined;
await import("../../src/db/db").then((mod) => {
@@ -97,37 +94,6 @@ afterEach(() => {
}
});
-afterAll(() => {
- // Close the module-level default database before cleanup to prevent file lock errors
- if (defaultDb) {
- defaultDb.close();
- }
- // Cleanup of the isolated test database after the test run
- if (existsSync("./data/test-isolated.sqlite")) {
- unlinkSync("./data/test-isolated.sqlite");
- }
- if (existsSync("./data/test-isolated.sqlite-wal")) {
- try {
- unlinkSync("./data/test-isolated.sqlite-wal");
- } catch (err) {
- // WAL file cleanup error - log but don't fail test
- if (err instanceof Error && err.message.includes("ENOENT")) {
- // File already gone, which is fine
- }
- }
- }
- if (existsSync("./data/test-isolated.sqlite-shm")) {
- try {
- unlinkSync("./data/test-isolated.sqlite-shm");
- } catch (err) {
- // SHM file cleanup error - log but don't fail test
- if (err instanceof Error && err.message.includes("ENOENT")) {
- // File already gone, which is fine
- }
- }
- }
-});
-
test("db initializes and creates tables on first run", () => {
const tables = queryAllTables(testDb);
expect(tables.length).toBeGreaterThanOrEqual(3);
diff --git a/tests/pages/chooseConverter.test.ts b/tests/pages/chooseConverter.test.ts
new file mode 100644
index 00000000..3042febf
--- /dev/null
+++ b/tests/pages/chooseConverter.test.ts
@@ -0,0 +1,49 @@
+import { describe, expect, test } from "bun:test";
+import { request } from "./helpers/app";
+
+async function conversionsFor(fileType: string) {
+ return (await request("/conversions", { json: { fileType } })).text();
+}
+
+describe("POST /conversions", () => {
+ test("lists the targets of every converter that accepts the file type", async () => {
+ const body = await conversionsFor("vcf");
+
+ expect(body).toContain('data-converter="vcf"');
+ expect(body).toContain('data-value="csv,vcf"');
+ expect(body).toContain('');
+ });
+
+ test("normalizes the file type", async () => {
+ expect(await conversionsFor("VCF")).toBe(await conversionsFor("vcf"));
+ expect(await conversionsFor("jpg")).toBe(await conversionsFor("jpeg"));
+ });
+
+ test("offers no converters for an unknown file type", async () => {
+ const body = await conversionsFor("xyz123");
+
+ expect(body).not.toContain("convert_to_group");
+ expect(body).not.toContain("