import { afterAll, describe, expect, it } from 'vitest' import { prisma, createCaller } from '../setup' import { createTestProgram, createTestProject, cleanupTestData, uid, } from '../helpers' import { applicantRouter } from '../../src/server/routers/applicant' // ─── shared helpers ──────────────────────────────────────────────────────── async function createApplicant() { const id = uid('user') return prisma.user.create({ data: { id, email: `${id}@test.local`, name: 'Test Applicant', role: 'APPLICANT', roles: ['APPLICANT'], status: 'ACTIVE', }, }) } /** * Build a fully-confirmed finalist setup: * - Program with visaStatusVisibleToMembers=true * - Project with a TeamMember (LEAD) * - CONFIRMED FinalistConfirmation * - Hotel for the program * - AttendingMember for the caller * - FlightDetail for that attendee * - VisaApplication GRANTED for that attendee */ async function buildConfirmedFinalist() { const program = await createTestProgram({ name: `logistics-${uid()}`, defaultAttendeeCap: 3, }) await prisma.program.update({ where: { id: program.id }, data: { visaStatusVisibleToMembers: true }, }) const project = await createTestProject(program.id, { title: 'Ocean Wave Project', competitionCategory: 'STARTUP', }) const user = await createApplicant() await prisma.teamMember.create({ data: { projectId: project.id, userId: user.id, role: 'LEAD' }, }) const confirmation = await prisma.finalistConfirmation.create({ data: { projectId: project.id, category: 'STARTUP', status: 'CONFIRMED', deadline: new Date(Date.now() + 86_400_000), token: `tok_${uid()}`, confirmedAt: new Date(), }, }) // Hotel for the program (1:1) await prisma.hotel.create({ data: { programId: program.id, name: 'Hotel Hermitage', address: '11 Avenue de la Costa, Monaco', link: 'https://example.com/hotel', notes: 'Breakfast included.', }, }) const attendee = await prisma.attendingMember.create({ data: { confirmationId: confirmation.id, userId: user.id, needsVisa: true, }, }) // FlightDetail await prisma.flightDetail.create({ data: { attendingMemberId: attendee.id, arrivalFlightNumber: 'AF1234', arrivalAirport: 'NCE', arrivalAt: new Date('2026-06-20T10:00:00Z'), departureFlightNumber: 'AF5678', departureAirport: 'NCE', departureAt: new Date('2026-06-23T15:00:00Z'), status: 'CONFIRMED', }, }) // VisaApplication GRANTED await prisma.visaApplication.create({ data: { attendingMemberId: attendee.id, status: 'GRANTED', nationality: 'French', }, }) return { program, project, user, confirmation, attendee } } // ─── Task 1 tests ────────────────────────────────────────────────────────── describe('applicant.getMyLogistics', () => { const programIds: string[] = [] const userIds: string[] = [] afterAll(async () => { for (const programId of programIds) { await prisma.visaApplication.deleteMany({ where: { attendingMember: { confirmation: { project: { programId } } } }, }) await prisma.flightDetail.deleteMany({ where: { attendingMember: { confirmation: { project: { programId } } } }, }) await prisma.hotel.deleteMany({ where: { programId } }) await prisma.attendingMember.deleteMany({ where: { confirmation: { project: { programId } } }, }) await prisma.finalistConfirmation.deleteMany({ where: { project: { programId } } }) await cleanupTestData(programId, []) } if (userIds.length > 0) { await prisma.user.deleteMany({ where: { id: { in: userIds } } }) } }) it('returns hotel, flight, and visa for a confirmed finalist', async () => { const { program, user } = await buildConfirmedFinalist() programIds.push(program.id) userIds.push(user.id) const caller = createCaller(applicantRouter, { id: user.id, email: user.email, role: 'APPLICANT', }) const result = await caller.getMyLogistics() expect(result).not.toBeNull() expect(result!.projectTitle).toBe('Ocean Wave Project') expect(result!.confirmationStatus).toBe('CONFIRMED') expect(result!.hotel).not.toBeNull() expect(result!.hotel!.name).toBe('Hotel Hermitage') expect(result!.myFlight).not.toBeNull() expect(result!.myFlight!.arrivalFlightNumber).toBe('AF1234') expect(result!.myFlight!.arrivalAirport).toBe('NCE') expect(result!.visaVisible).toBe(true) expect(result!.myVisa).not.toBeNull() expect(result!.myVisa!.status).toBe('GRANTED') }) it('returns null for a user who has no confirmed finalist project', async () => { // user with no project at all const nonFinalist = await createApplicant() userIds.push(nonFinalist.id) const caller = createCaller(applicantRouter, { id: nonFinalist.id, email: nonFinalist.email, role: 'APPLICANT', }) const result = await caller.getMyLogistics() expect(result).toBeNull() }) it('returns null when the confirmation is PENDING (not CONFIRMED)', async () => { const program = await createTestProgram({ name: `logistics-pending-${uid()}`, defaultAttendeeCap: 2, }) programIds.push(program.id) const project = await createTestProject(program.id, { title: 'Pending Project', competitionCategory: 'STARTUP', }) const user = await createApplicant() userIds.push(user.id) await prisma.teamMember.create({ data: { projectId: project.id, userId: user.id, role: 'LEAD' }, }) await prisma.finalistConfirmation.create({ data: { projectId: project.id, category: 'STARTUP', status: 'PENDING', deadline: new Date(Date.now() + 86_400_000), token: `tok_${uid()}`, }, }) const caller = createCaller(applicantRouter, { id: user.id, email: user.email, role: 'APPLICANT', }) const result = await caller.getMyLogistics() expect(result).toBeNull() }) })