import { afterAll, describe, expect, it } from 'vitest' import { prisma, createCaller } from '../setup' import { createTestUser, createTestProgram, createTestCompetition, createTestRound, cleanupTestData, uid, } from '../helpers' import { programRouter } from '../../src/server/routers/program' describe('program.getEditionSettings', () => { const programIds: string[] = [] const userIds: string[] = [] afterAll(async () => { for (const programId of programIds) { await cleanupTestData(programId, []) } if (userIds.length > 0) { await prisma.user.deleteMany({ where: { id: { in: userIds } } }) } }) it('returns the merged view (program fields + LIVE_FINAL round config)', async () => { const admin = await createTestUser('SUPER_ADMIN') userIds.push(admin.id) const program = await createTestProgram({ name: `edition-merged-${uid()}`, defaultAttendeeCap: 5, }) programIds.push(program.id) await prisma.program.update({ where: { id: program.id }, data: { visaStatusVisibleToMembers: false }, }) const competition = await createTestCompetition(program.id) await createTestRound(competition.id, { roundType: 'LIVE_FINAL', sortOrder: 99, configJson: { attendeeEditCutoffHours: 24, confirmationWindowHours: 12 }, }) const caller = createCaller(programRouter, { id: admin.id, email: admin.email, role: 'SUPER_ADMIN', }) const result = await caller.getEditionSettings({ programId: program.id }) expect(result.defaultAttendeeCap).toBe(5) expect(result.visaStatusVisibleToMembers).toBe(false) expect(result.attendeeEditCutoffHours).toBe(24) expect(result.confirmationWindowHours).toBe(12) expect(result.liveFinalRoundId).not.toBeNull() }) it('falls back to defaults when LIVE_FINAL round has no relevant config', async () => { const admin = await createTestUser('SUPER_ADMIN') userIds.push(admin.id) const program = await createTestProgram({ name: `edition-defaults-${uid()}` }) programIds.push(program.id) const competition = await createTestCompetition(program.id) await createTestRound(competition.id, { roundType: 'LIVE_FINAL', sortOrder: 99, configJson: {}, }) const caller = createCaller(programRouter, { id: admin.id, email: admin.email, role: 'SUPER_ADMIN', }) const result = await caller.getEditionSettings({ programId: program.id }) expect(result.attendeeEditCutoffHours).toBe(48) expect(result.confirmationWindowHours).toBe(24) }) it('returns nulls for round-derived fields when no LIVE_FINAL round exists', async () => { const admin = await createTestUser('SUPER_ADMIN') userIds.push(admin.id) const program = await createTestProgram({ name: `edition-noround-${uid()}` }) programIds.push(program.id) const caller = createCaller(programRouter, { id: admin.id, email: admin.email, role: 'SUPER_ADMIN', }) const result = await caller.getEditionSettings({ programId: program.id }) expect(result.attendeeEditCutoffHours).toBeNull() expect(result.confirmationWindowHours).toBeNull() expect(result.liveFinalRoundId).toBeNull() }) }) describe('program.updateEditionSettings', () => { const programIds: string[] = [] const userIds: string[] = [] afterAll(async () => { for (const programId of programIds) { await cleanupTestData(programId, []) } if (userIds.length > 0) { await prisma.user.deleteMany({ where: { id: { in: userIds } } }) } }) it('writes program fields + round configJson + audit-logs', async () => { const admin = await createTestUser('SUPER_ADMIN') userIds.push(admin.id) const program = await createTestProgram({ name: `edition-update-${uid()}` }) programIds.push(program.id) const competition = await createTestCompetition(program.id) const round = await createTestRound(competition.id, { roundType: 'LIVE_FINAL', sortOrder: 99, }) const caller = createCaller(programRouter, { id: admin.id, email: admin.email, role: 'SUPER_ADMIN', }) await caller.updateEditionSettings({ programId: program.id, defaultAttendeeCap: 4, visaStatusVisibleToMembers: false, attendeeEditCutoffHours: 36, confirmationWindowHours: 18, }) const refreshed = await prisma.program.findUniqueOrThrow({ where: { id: program.id } }) expect(refreshed.defaultAttendeeCap).toBe(4) expect(refreshed.visaStatusVisibleToMembers).toBe(false) const updatedRound = await prisma.round.findUniqueOrThrow({ where: { id: round.id } }) const cfg = updatedRound.configJson as Record expect(cfg.attendeeEditCutoffHours).toBe(36) expect(cfg.confirmationWindowHours).toBe(18) const audit = await prisma.auditLog.findFirst({ where: { action: 'PROGRAM_EDITION_SETTINGS_UPDATE', entityId: program.id }, }) expect(audit).not.toBeNull() }) it('preserves untouched configJson keys', async () => { const admin = await createTestUser('SUPER_ADMIN') userIds.push(admin.id) const program = await createTestProgram({ name: `edition-preserve-${uid()}` }) programIds.push(program.id) const competition = await createTestCompetition(program.id) const round = await createTestRound(competition.id, { roundType: 'LIVE_FINAL', sortOrder: 99, configJson: { foo: 'bar', attendeeEditCutoffHours: 48 }, }) const caller = createCaller(programRouter, { id: admin.id, email: admin.email, role: 'SUPER_ADMIN', }) await caller.updateEditionSettings({ programId: program.id, attendeeEditCutoffHours: 24, }) const updated = await prisma.round.findUniqueOrThrow({ where: { id: round.id } }) const cfg = updated.configJson as Record expect(cfg.foo).toBe('bar') expect(cfg.attendeeEditCutoffHours).toBe(24) }) })