Test runs that crash before reaching afterAll leave orphan @test.local users + programs (Test Program / getCandidates- / bulk- / source-flag- / mentor-files- name patterns). Mirrors tests/helpers.ts cleanupTestData cascade order. Idempotent — safe to re-run any time the dev DB picks up test pollution. Run: npx tsx scripts/cleanup-test-pollution.ts
102 lines
4.8 KiB
TypeScript
102 lines
4.8 KiB
TypeScript
/**
|
|
* One-shot: remove leaked test data from dev DB.
|
|
*
|
|
* Test runs that crashed before reaching `afterAll` left orphan test users +
|
|
* programs. This mirrors `tests/helpers.ts#cleanupTestData` with the same
|
|
* reverse-dependency order, applied to all programs whose name matches the
|
|
* test patterns.
|
|
*
|
|
* Run: npx tsx scripts/cleanup-test-pollution.ts
|
|
*/
|
|
import { PrismaClient } from '@prisma/client'
|
|
|
|
const prisma = new PrismaClient()
|
|
|
|
const TEST_PROGRAM_PATTERNS = [
|
|
'Test Program prog-%',
|
|
'getCandidates-%',
|
|
'bulk-%',
|
|
'source-flag-%',
|
|
'mentor-files-%',
|
|
'mentor-config-%',
|
|
]
|
|
|
|
async function main() {
|
|
const programs = await prisma.program.findMany({
|
|
where: {
|
|
OR: TEST_PROGRAM_PATTERNS.map((p) => ({ name: { startsWith: p.replace('%', '') } })),
|
|
},
|
|
select: { id: true, name: true },
|
|
})
|
|
|
|
console.log(`Found ${programs.length} test programs:`)
|
|
programs.forEach((p) => console.log(` - ${p.id} ${p.name}`))
|
|
|
|
for (const program of programs) {
|
|
const programId = program.id
|
|
console.log(`\nCleaning ${program.name}...`)
|
|
|
|
// MentorAssignment isn't in cleanupTestData — kill it first
|
|
const ma = await prisma.mentorAssignment.deleteMany({
|
|
where: { project: { programId } },
|
|
})
|
|
if (ma.count > 0) console.log(` ${ma.count} MentorAssignment`)
|
|
|
|
// Mirror tests/helpers.ts#cleanupTestData order
|
|
await prisma.cohortProject.deleteMany({ where: { cohort: { round: { competition: { programId } } } } })
|
|
await prisma.cohort.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.liveProgressCursor.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.filteringResult.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.filteringRule.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.filteringJob.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.assignmentJob.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.conflictOfInterest.deleteMany({ where: { assignment: { round: { competition: { programId } } } } })
|
|
await prisma.evaluation.deleteMany({ where: { assignment: { round: { competition: { programId } } } } })
|
|
await prisma.assignment.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.evaluationForm.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.fileRequirement.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.gracePeriod.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.reminderLog.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.evaluationSummary.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.evaluationDiscussion.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.projectRoundState.deleteMany({ where: { round: { competition: { programId } } } })
|
|
await prisma.awardEligibility.deleteMany({ where: { award: { program: { id: programId } } } })
|
|
await prisma.awardVote.deleteMany({ where: { award: { program: { id: programId } } } })
|
|
await prisma.awardJuror.deleteMany({ where: { award: { program: { id: programId } } } })
|
|
await prisma.specialAward.deleteMany({ where: { programId } })
|
|
await prisma.round.deleteMany({ where: { competition: { programId } } })
|
|
await prisma.competition.deleteMany({ where: { programId } })
|
|
await prisma.projectStatusHistory.deleteMany({ where: { project: { programId } } })
|
|
await prisma.projectFile.deleteMany({ where: { project: { programId } } })
|
|
await prisma.projectTag.deleteMany({ where: { project: { programId } } })
|
|
await prisma.project.deleteMany({ where: { programId } })
|
|
await prisma.program.deleteMany({ where: { id: programId } })
|
|
console.log(' cascade complete')
|
|
}
|
|
|
|
// Delete test users (@test.local). Catch any audit-log refs first.
|
|
const testUsers = await prisma.user.findMany({
|
|
where: { email: { endsWith: '@test.local' } },
|
|
select: { id: true },
|
|
})
|
|
const testUserIds = testUsers.map((u) => u.id)
|
|
console.log(`\nDeleting ${testUserIds.length} @test.local users...`)
|
|
if (testUserIds.length > 0) {
|
|
await prisma.decisionAuditLog.deleteMany({ where: { actorId: { in: testUserIds } } })
|
|
await prisma.auditLog.deleteMany({ where: { userId: { in: testUserIds } } })
|
|
// Any remaining MentorAssignments referencing these users (e.g., from other tests)
|
|
await prisma.mentorAssignment.deleteMany({ where: { mentorId: { in: testUserIds } } })
|
|
await prisma.user.deleteMany({ where: { id: { in: testUserIds } } })
|
|
}
|
|
|
|
console.log('\nDone.')
|
|
}
|
|
|
|
main()
|
|
.then(() => prisma.$disconnect())
|
|
.catch(async (e) => {
|
|
console.error(e)
|
|
await prisma.$disconnect()
|
|
process.exit(1)
|
|
})
|