Files
GearBox/e2e/seed.ts
Jean-Luc Makiola 54614869cf
Some checks failed
CI / ci (push) Successful in 1m0s
CI / e2e (push) Failing after 8m39s
fix: migrate E2E tests from SQLite to Postgres
- Rewrite e2e/seed.ts to use postgres driver instead of bun:sqlite
- Add userId to all seeded entities (multi-user schema)
- Add Postgres service container to CI E2E job
- Remove DATABASE_PATH from test server start script
- Re-enable E2E job in CI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 20:56:11 +02:00

229 lines
5.3 KiB
TypeScript

import { sql } from "drizzle-orm";
import { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator";
import postgres from "postgres";
import * as schema from "../src/db/schema";
const DATABASE_URL =
process.env.DATABASE_URL ||
"postgresql://gearbox:gearbox@localhost:5432/gearbox";
export async function seedTestDatabase() {
const client = postgres(DATABASE_URL, { max: 1 });
const db = drizzle(client, { schema });
// Run migrations
await migrate(db, { migrationsFolder: "./drizzle-pg" });
// Clean all tables for a fresh seed
const tables = [
"setup_items",
"setups",
"thread_candidates",
"threads",
"items",
"global_item_tags",
"global_items",
"tags",
"oauth_tokens",
"oauth_codes",
"oauth_clients",
"api_keys",
"settings",
"categories",
"users",
];
for (const t of tables) {
await db.execute(sql.raw(`TRUNCATE TABLE "${t}" RESTART IDENTITY CASCADE`));
}
// ── User ──
const [user] = await db
.insert(schema.users)
.values({ logtoSub: "e2e-test-user" })
.returning();
const userId = user.id;
// ── Categories ──
const [uncategorized] = await db
.insert(schema.categories)
.values({ name: "Uncategorized", icon: "package", userId })
.returning();
const [shelter] = await db
.insert(schema.categories)
.values({ name: "Shelter", icon: "tent", userId })
.returning();
const [sleep] = await db
.insert(schema.categories)
.values({ name: "Sleep System", icon: "moon", userId })
.returning();
const [cook] = await db
.insert(schema.categories)
.values({ name: "Cook Kit", icon: "flame", userId })
.returning();
// ── Items ──
const [tent] = await db
.insert(schema.items)
.values({
name: "Zpacks Duplex",
weightGrams: 539,
priceCents: 67900,
categoryId: shelter.id,
userId,
notes: "DCF shelter, 2-person",
})
.returning();
await db.insert(schema.items).values({
name: "Borah Gear Tarp",
weightGrams: 156,
priceCents: 11000,
categoryId: shelter.id,
userId,
});
const [quilt] = await db
.insert(schema.items)
.values({
name: "Enlightened Equipment Enigma 20",
weightGrams: 595,
priceCents: 34000,
categoryId: sleep.id,
userId,
notes: "20F quilt",
})
.returning();
const [pad] = await db
.insert(schema.items)
.values({
name: "Therm-a-Rest NeoAir XLite",
weightGrams: 354,
priceCents: 20999,
categoryId: sleep.id,
userId,
})
.returning();
const [stove] = await db
.insert(schema.items)
.values({
name: "BRS-3000T Stove",
weightGrams: 25,
priceCents: 2000,
categoryId: cook.id,
userId,
})
.returning();
await db.insert(schema.items).values({
name: "Toaks 750ml Pot",
weightGrams: 103,
priceCents: 3000,
categoryId: cook.id,
userId,
});
// ── Active Thread with 3 Candidates ──
const [activeThread] = await db
.insert(schema.threads)
.values({
name: "New Backpack",
status: "active",
categoryId: uncategorized.id,
userId,
})
.returning();
await db.insert(schema.threadCandidates).values({
threadId: activeThread.id,
name: "ULA Circuit",
weightGrams: 1077,
priceCents: 27500,
categoryId: uncategorized.id,
pros: "Great hip belt\nLarge capacity",
cons: "Heavier than competitors",
sortOrder: 1000,
status: "researching",
});
await db.insert(schema.threadCandidates).values({
threadId: activeThread.id,
name: "Gossamer Gear Mariposa",
weightGrams: 737,
priceCents: 28500,
categoryId: uncategorized.id,
pros: "Very lightweight\nGood ventilation",
cons: "Smaller hip belt pockets",
sortOrder: 2000,
status: "researching",
});
await db.insert(schema.threadCandidates).values({
threadId: activeThread.id,
name: "Granite Gear Crown2 38",
weightGrams: 850,
priceCents: 18000,
categoryId: uncategorized.id,
sortOrder: 3000,
status: "ordered",
});
// ── Resolved Thread ──
const [resolvedThread] = await db
.insert(schema.threads)
.values({
name: "Camp Stove",
status: "resolved",
categoryId: cook.id,
userId,
resolvedCandidateId: 1,
})
.returning();
await db.insert(schema.threadCandidates).values({
threadId: resolvedThread.id,
name: "BRS-3000T",
weightGrams: 25,
priceCents: 2000,
categoryId: cook.id,
sortOrder: 1000,
status: "arrived",
});
// ── Setup with Items ──
const [setup] = await db
.insert(schema.setups)
.values({ name: "Weekend Overnighter", userId })
.returning();
await db.insert(schema.setupItems).values([
{ setupId: setup.id, itemId: tent.id, classification: "base" },
{ setupId: setup.id, itemId: quilt.id, classification: "base" },
{ setupId: setup.id, itemId: pad.id, classification: "base" },
{ setupId: setup.id, itemId: stove.id, classification: "consumable" },
]);
// ── API Key for E2E Authentication ──
const rawKey = "e2e-test-api-key-for-gearbox-testing";
const keyHash = await Bun.password.hash(rawKey);
const keyPrefix = rawKey.slice(0, 8);
await db
.insert(schema.apiKeys)
.values({ name: "E2E Test Key", keyHash, keyPrefix, userId });
// ── Settings ──
await db.insert(schema.settings).values([
{ key: "weightUnit", value: "g", userId },
{ key: "currency", value: "USD", userId },
{ key: "onboardingComplete", value: "true", userId },
]);
await client.end();
console.log("E2E test database seeded via", DATABASE_URL);
}