diff --git a/hub/test/integration/helpers.ts b/hub/test/integration/helpers.ts index dc3efb6..e13c5cb 100644 --- a/hub/test/integration/helpers.ts +++ b/hub/test/integration/helpers.ts @@ -50,20 +50,25 @@ export const prisma = new PrismaClient({ /** Truncate all tables before each test for isolation. */ export async function resetDb(): Promise { - // User and Organization are the aggregate roots for all domain rows; their - // declared FK cascades clear projects, search documents, permissions, - // sessions and connections without repeatedly truncating pg_trgm indexes. - // Event receipts and global audit rows are independent roots. - await prisma.$transaction([ - prisma.feishuEventReceipt.deleteMany(), - prisma.auditEntry.deleteMany(), - // Permission resource ids are intentionally polymorphic strings, so these - // two tables have no FK to Project and must be cleared explicitly. - prisma.permissionGrant.deleteMany(), - prisma.permissionSettings.deleteMany(), - prisma.user.deleteMany(), - prisma.organization.deleteMany(), - ]); + // Hard reset via TRUNCATE CASCADE. Parent RESTRICT edges and leftover + // folder trees made deleteMany-based cleanup race Prisma upserts + // ("Unique constraint failed on id" while the where-branch saw no row). + await prisma.$executeRawUnsafe(` + DO $$ + DECLARE + stmt text; + BEGIN + SELECT 'TRUNCATE TABLE ' || string_agg(format('%I.%I', schemaname, tablename), ', ') + || ' RESTART IDENTITY CASCADE' + INTO stmt + FROM pg_tables + WHERE schemaname = 'public' + AND tablename <> '_prisma_migrations'; + IF stmt IS NOT NULL THEN + EXECUTE stmt; + END IF; + END $$; + `); await seedTestOrganization(); }