168 lines
5.4 KiB
TypeScript
168 lines
5.4 KiB
TypeScript
|
|
import { afterAll, describe, expect, it } from 'vitest'
|
||
|
|
import { prisma, createCaller } from '../setup'
|
||
|
|
import {
|
||
|
|
createTestUser,
|
||
|
|
createTestProgram,
|
||
|
|
createTestProject,
|
||
|
|
cleanupTestData,
|
||
|
|
uid,
|
||
|
|
} from '../helpers'
|
||
|
|
import { mentorRouter } from '../../src/server/routers/mentor'
|
||
|
|
import type { UserRole } from '@prisma/client'
|
||
|
|
|
||
|
|
async function createUserWithRoles(primaryRole: UserRole, rolesArray: UserRole[]) {
|
||
|
|
const id = uid('user')
|
||
|
|
return prisma.user.create({
|
||
|
|
data: {
|
||
|
|
id,
|
||
|
|
email: `${id}@test.local`,
|
||
|
|
name: `Test ${primaryRole}`,
|
||
|
|
role: primaryRole,
|
||
|
|
roles: rolesArray,
|
||
|
|
status: 'ACTIVE',
|
||
|
|
},
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
const DAY = 86_400_000
|
||
|
|
|
||
|
|
describe('mentor.getMenteeActivity', () => {
|
||
|
|
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('classifies projects as unassigned / assigned / active / stalled and returns totals', async () => {
|
||
|
|
const admin = await createTestUser('SUPER_ADMIN')
|
||
|
|
userIds.push(admin.id)
|
||
|
|
const program = await createTestProgram({ name: `mentee-activity-${uid()}` })
|
||
|
|
programIds.push(program.id)
|
||
|
|
|
||
|
|
const lead = await createUserWithRoles('APPLICANT', ['APPLICANT'])
|
||
|
|
userIds.push(lead.id)
|
||
|
|
const mentor = await createUserWithRoles('MENTOR', ['MENTOR'])
|
||
|
|
userIds.push(mentor.id)
|
||
|
|
|
||
|
|
// Four projects all wantsMentorship
|
||
|
|
const pUnassigned = await createTestProject(program.id, { title: 'Unassigned' })
|
||
|
|
const pAssigned = await createTestProject(program.id, { title: 'Assigned' })
|
||
|
|
const pActive = await createTestProject(program.id, { title: 'Active' })
|
||
|
|
const pStalled = await createTestProject(program.id, { title: 'Stalled' })
|
||
|
|
for (const p of [pUnassigned, pAssigned, pActive, pStalled]) {
|
||
|
|
await prisma.project.update({ where: { id: p.id }, data: { wantsMentorship: true } })
|
||
|
|
await prisma.teamMember.create({
|
||
|
|
data: { projectId: p.id, userId: lead.id, role: 'LEAD' },
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// Assigned: mentor assigned, no activity yet
|
||
|
|
await prisma.mentorAssignment.create({
|
||
|
|
data: {
|
||
|
|
projectId: pAssigned.id,
|
||
|
|
mentorId: mentor.id,
|
||
|
|
method: 'MANUAL',
|
||
|
|
assignedBy: admin.id,
|
||
|
|
workspaceEnabled: true,
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
// Active: mentor + recent message
|
||
|
|
const aActive = await prisma.mentorAssignment.create({
|
||
|
|
data: {
|
||
|
|
projectId: pActive.id,
|
||
|
|
mentorId: mentor.id,
|
||
|
|
method: 'MANUAL',
|
||
|
|
assignedBy: admin.id,
|
||
|
|
workspaceEnabled: true,
|
||
|
|
},
|
||
|
|
})
|
||
|
|
await prisma.mentorMessage.create({
|
||
|
|
data: {
|
||
|
|
projectId: pActive.id,
|
||
|
|
senderId: mentor.id,
|
||
|
|
message: 'recent ping',
|
||
|
|
workspaceId: aActive.id,
|
||
|
|
createdAt: new Date(Date.now() - 2 * DAY),
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
// Stalled: mentor + last message > 14 days ago
|
||
|
|
const aStalled = await prisma.mentorAssignment.create({
|
||
|
|
data: {
|
||
|
|
projectId: pStalled.id,
|
||
|
|
mentorId: mentor.id,
|
||
|
|
method: 'MANUAL',
|
||
|
|
assignedBy: admin.id,
|
||
|
|
workspaceEnabled: true,
|
||
|
|
assignedAt: new Date(Date.now() - 30 * DAY),
|
||
|
|
},
|
||
|
|
})
|
||
|
|
await prisma.mentorMessage.create({
|
||
|
|
data: {
|
||
|
|
projectId: pStalled.id,
|
||
|
|
senderId: mentor.id,
|
||
|
|
message: 'old ping',
|
||
|
|
workspaceId: aStalled.id,
|
||
|
|
createdAt: new Date(Date.now() - 20 * DAY),
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
const caller = createCaller(mentorRouter, {
|
||
|
|
id: admin.id,
|
||
|
|
email: admin.email,
|
||
|
|
role: 'SUPER_ADMIN',
|
||
|
|
})
|
||
|
|
const result = await caller.getMenteeActivity({ programId: program.id })
|
||
|
|
|
||
|
|
const byTitle = Object.fromEntries(
|
||
|
|
result.rows.map((r: (typeof result.rows)[number]) => [r.project.title, r]),
|
||
|
|
)
|
||
|
|
expect(byTitle['Unassigned'].status).toBe('unassigned')
|
||
|
|
expect(byTitle['Unassigned'].mentor).toBeNull()
|
||
|
|
expect(byTitle['Assigned'].status).toBe('assigned')
|
||
|
|
expect(byTitle['Assigned'].mentor?.id).toBe(mentor.id)
|
||
|
|
expect(byTitle['Active'].status).toBe('active')
|
||
|
|
expect(byTitle['Active'].lastActivityAt).not.toBeNull()
|
||
|
|
expect(byTitle['Stalled'].status).toBe('stalled')
|
||
|
|
|
||
|
|
expect(result.totals.unassigned).toBe(1)
|
||
|
|
expect(result.totals.assigned).toBe(1)
|
||
|
|
expect(result.totals.active).toBe(1)
|
||
|
|
expect(result.totals.stalled).toBe(1)
|
||
|
|
|
||
|
|
// Team lead resolved
|
||
|
|
expect(byTitle['Active'].teamLead?.email).toBe(lead.email)
|
||
|
|
})
|
||
|
|
|
||
|
|
it('only includes projects that wantMentorship within the program scope', async () => {
|
||
|
|
const admin = await createTestUser('SUPER_ADMIN')
|
||
|
|
userIds.push(admin.id)
|
||
|
|
const program = await createTestProgram({ name: `mentee-scope-${uid()}` })
|
||
|
|
programIds.push(program.id)
|
||
|
|
|
||
|
|
const pYes = await createTestProject(program.id, { title: 'Yes' })
|
||
|
|
const pNo = await createTestProject(program.id, { title: 'No' })
|
||
|
|
await prisma.project.update({ where: { id: pYes.id }, data: { wantsMentorship: true } })
|
||
|
|
await prisma.project.update({ where: { id: pNo.id }, data: { wantsMentorship: false } })
|
||
|
|
|
||
|
|
const caller = createCaller(mentorRouter, {
|
||
|
|
id: admin.id,
|
||
|
|
email: admin.email,
|
||
|
|
role: 'SUPER_ADMIN',
|
||
|
|
})
|
||
|
|
const result = await caller.getMenteeActivity({ programId: program.id })
|
||
|
|
|
||
|
|
expect(
|
||
|
|
result.rows.map((r: (typeof result.rows)[number]) => r.project.title).sort(),
|
||
|
|
).toEqual(['Yes'])
|
||
|
|
})
|
||
|
|
})
|