import { afterAll, describe, expect, it } from 'vitest' import { prisma, createCaller } from '../setup' import { createTestUser, createTestProgram, createTestProject, createTestCompetition, createTestRound, cleanupTestData, uid, } from '../helpers' import { mentorRouter } from '../../src/server/routers/mentor' import type { UserRole } from '@prisma/client' async function createUserWithRoles( primaryRole: UserRole, rolesArray: UserRole[], overrides: { expertiseTags?: string[]; maxAssignments?: number | null; country?: string | null } = {}, ) { const id = uid('user') return prisma.user.create({ data: { id, email: `${id}@test.local`, name: `Test ${primaryRole}`, role: primaryRole, roles: rolesArray, status: 'ACTIVE', expertiseTags: overrides.expertiseTags ?? [], maxAssignments: overrides.maxAssignments ?? null, country: overrides.country ?? null, }, }) } describe('mentor.getRoundStats', () => { const programIds: string[] = [] const userIds: string[] = [] afterAll(async () => { for (const programId of programIds) { await prisma.mentorAssignment.deleteMany({ where: { project: { programId } } }) await cleanupTestData(programId, []) } if (userIds.length > 0) { await prisma.user.deleteMany({ where: { id: { in: userIds } } }) } }) it('returns counts of total / requested / assigned / awaiting + activity totals', async () => { const admin = await createTestUser('SUPER_ADMIN') userIds.push(admin.id) const program = await createTestProgram({ name: `round-stats-${uid()}` }) programIds.push(program.id) const competition = await createTestCompetition(program.id, { status: 'ACTIVE' }) const round = await createTestRound(competition.id, { roundType: 'MENTORING', configJson: { eligibility: 'requested_only', mentoringRequestDeadlineDays: 14 }, windowOpenAt: new Date('2026-04-01T00:00:00Z'), }) const projReqAssigned = await createTestProject(program.id, { title: 'Req+Assigned', tags: [] }) const projReqAwaiting = await createTestProject(program.id, { title: 'Req+Awaiting', tags: [] }) const projNotReqAssigned = await createTestProject(program.id, { title: 'NotReq+Assigned', tags: [] }) const projNotReq = await createTestProject(program.id, { title: 'NotReq', tags: [] }) await prisma.project.update({ where: { id: projReqAssigned.id }, data: { wantsMentorship: true } }) await prisma.project.update({ where: { id: projReqAwaiting.id }, data: { wantsMentorship: true } }) for (const p of [projReqAssigned, projReqAwaiting, projNotReqAssigned, projNotReq]) { await prisma.projectRoundState.create({ data: { projectId: p.id, roundId: round.id, state: 'PENDING' }, }) } const mentor = await createUserWithRoles('MENTOR', ['MENTOR']) userIds.push(mentor.id) const a1 = await prisma.mentorAssignment.create({ data: { projectId: projReqAssigned.id, mentorId: mentor.id, method: 'MANUAL', assignedBy: admin.id, workspaceEnabled: true }, }) await prisma.mentorAssignment.create({ data: { projectId: projNotReqAssigned.id, mentorId: mentor.id, method: 'MANUAL', assignedBy: admin.id, workspaceEnabled: true }, }) await prisma.mentorMessage.create({ data: { projectId: projReqAssigned.id, senderId: mentor.id, message: 'hello', workspaceId: a1.id }, }) await prisma.mentorMessage.create({ data: { projectId: projReqAssigned.id, senderId: mentor.id, message: 'still here', workspaceId: a1.id }, }) await prisma.mentorMessage.create({ data: { projectId: projNotReqAssigned.id, senderId: mentor.id, message: 'on it' }, }) await prisma.mentorFile.create({ data: { mentorAssignmentId: a1.id, uploadedByUserId: mentor.id, fileName: 'plan.pdf', objectKey: 'k', bucket: 'b', mimeType: 'application/pdf', size: 1, }, }) const caller = createCaller(mentorRouter, { id: admin.id, email: admin.email, role: 'SUPER_ADMIN' }) const stats = await caller.getRoundStats({ roundId: round.id }) expect(stats.totalProjects).toBe(4) expect(stats.requestedCount).toBe(2) expect(stats.assignedCount).toBe(2) expect(stats.awaitingAssignment).toBe(1) expect(stats.workspaceActivity.messageCount).toBe(3) expect(stats.workspaceActivity.fileCount).toBe(1) expect(stats.workspaceActivity.lastActivityAt).not.toBeNull() }) it('exposes request-window deadline computed from windowOpenAt + deadlineDays', async () => { const admin = await createTestUser('SUPER_ADMIN') userIds.push(admin.id) const program = await createTestProgram({ name: `round-stats-window-${uid()}` }) programIds.push(program.id) const competition = await createTestCompetition(program.id, { status: 'ACTIVE' }) const round = await createTestRound(competition.id, { roundType: 'MENTORING', configJson: { eligibility: 'requested_only', mentoringRequestDeadlineDays: 7 }, windowOpenAt: new Date('2026-05-01T00:00:00Z'), }) const caller = createCaller(mentorRouter, { id: admin.id, email: admin.email, role: 'SUPER_ADMIN' }) const stats = await caller.getRoundStats({ roundId: round.id }) expect(stats.requestWindow.deadline).not.toBeNull() expect(new Date(stats.requestWindow.deadline!).toISOString()).toBe('2026-05-08T00:00:00.000Z') }) it('returns zeros for an empty round', async () => { const admin = await createTestUser('SUPER_ADMIN') userIds.push(admin.id) const program = await createTestProgram({ name: `round-stats-empty-${uid()}` }) programIds.push(program.id) const competition = await createTestCompetition(program.id, { status: 'ACTIVE' }) const round = await createTestRound(competition.id, { roundType: 'MENTORING', configJson: { eligibility: 'requested_only' }, }) const caller = createCaller(mentorRouter, { id: admin.id, email: admin.email, role: 'SUPER_ADMIN' }) const stats = await caller.getRoundStats({ roundId: round.id }) expect(stats.totalProjects).toBe(0) expect(stats.requestedCount).toBe(0) expect(stats.assignedCount).toBe(0) expect(stats.awaitingAssignment).toBe(0) expect(stats.workspaceActivity.messageCount).toBe(0) expect(stats.workspaceActivity.fileCount).toBe(0) expect(stats.workspaceActivity.lastActivityAt).toBeNull() }) }) describe('mentor.getMentorPool', () => { const programIds: string[] = [] const userIds: string[] = [] afterAll(async () => { for (const programId of programIds) { await prisma.mentorAssignment.deleteMany({ where: { project: { programId } } }) await cleanupTestData(programId, []) } if (userIds.length > 0) { await prisma.user.deleteMany({ where: { id: { in: userIds } } }) } }) it('returns all MENTOR-role users with current/completed counts and capacity', async () => { const admin = await createTestUser('SUPER_ADMIN') userIds.push(admin.id) const program = await createTestProgram({ name: `pool-${uid()}` }) programIds.push(program.id) const m1 = await createUserWithRoles('MENTOR', ['MENTOR'], { expertiseTags: ['biology'], maxAssignments: 5, country: 'France', }) const m2 = await createUserWithRoles('MENTOR', ['MENTOR'], { expertiseTags: ['policy'] }) userIds.push(m1.id, m2.id) const project = await createTestProject(program.id, { title: 'P1', tags: [] }) await prisma.mentorAssignment.create({ data: { projectId: project.id, mentorId: m1.id, method: 'MANUAL', assignedBy: admin.id, completionStatus: 'in_progress', }, }) const caller = createCaller(mentorRouter, { id: admin.id, email: admin.email, role: 'SUPER_ADMIN' }) const result = await caller.getMentorPool({}) const mentor1 = result.mentors.find((m: { id: string }) => m.id === m1.id)! const mentor2 = result.mentors.find((m: { id: string }) => m.id === m2.id)! expect(mentor1).toBeDefined() expect(mentor2).toBeDefined() expect(mentor1.currentAssignments).toBe(1) expect(mentor1.completedAssignments).toBe(0) expect(mentor1.maxAssignments).toBe(5) expect(mentor1.capacityRemaining).toBe(4) expect(mentor1.country).toBe('France') expect(mentor2.currentAssignments).toBe(0) expect(mentor2.maxAssignments).toBeNull() expect(mentor2.capacityRemaining).toBeNull() expect(result.poolSize).toBeGreaterThanOrEqual(2) expect(result.totalCurrentAssignments).toBeGreaterThanOrEqual(1) }) it('counts completed assignments separately from in-progress', async () => { const admin = await createTestUser('SUPER_ADMIN') userIds.push(admin.id) const program = await createTestProgram({ name: `pool-completed-${uid()}` }) programIds.push(program.id) const m = await createUserWithRoles('MENTOR', ['MENTOR']) userIds.push(m.id) const projInProgress = await createTestProject(program.id, { title: 'A', tags: [] }) const projCompleted = await createTestProject(program.id, { title: 'B', tags: [] }) await prisma.mentorAssignment.create({ data: { projectId: projInProgress.id, mentorId: m.id, method: 'MANUAL', assignedBy: admin.id, completionStatus: 'in_progress', }, }) await prisma.mentorAssignment.create({ data: { projectId: projCompleted.id, mentorId: m.id, method: 'MANUAL', assignedBy: admin.id, completionStatus: 'completed', }, }) const caller = createCaller(mentorRouter, { id: admin.id, email: admin.email, role: 'SUPER_ADMIN' }) const result = await caller.getMentorPool({}) const found = result.mentors.find((x: { id: string }) => x.id === m.id)! expect(found.currentAssignments).toBe(1) expect(found.completedAssignments).toBe(1) }) })