157 lines
5.1 KiB
TypeScript
157 lines
5.1 KiB
TypeScript
/**
|
|
* I-007: Cohort Voting — Closed Window Submit
|
|
*
|
|
* Tests that audience votes are rejected when the cohort voting window is closed.
|
|
* The castVote procedure checks for an open cohort before accepting votes.
|
|
*/
|
|
|
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
|
import { prisma, createTestContext } from '../setup'
|
|
import {
|
|
createTestUser,
|
|
createTestProgram,
|
|
createTestPipeline,
|
|
createTestTrack,
|
|
createTestStage,
|
|
createTestProject,
|
|
createTestCohort,
|
|
createTestCohortProject,
|
|
cleanupTestData,
|
|
} from '../helpers'
|
|
import { closeCohortWindow, openCohortWindow } from '@/server/services/live-control'
|
|
|
|
let programId: string
|
|
let userIds: string[] = []
|
|
|
|
beforeAll(async () => {
|
|
const program = await createTestProgram({ name: 'Cohort Voting Test' })
|
|
programId = program.id
|
|
})
|
|
|
|
afterAll(async () => {
|
|
await cleanupTestData(programId, userIds)
|
|
})
|
|
|
|
describe('I-007: Cohort Voting — Closed Window Submit', () => {
|
|
it('cohort starts closed, opens, then closes correctly', async () => {
|
|
const admin = await createTestUser('SUPER_ADMIN')
|
|
userIds.push(admin.id)
|
|
|
|
const pipeline = await createTestPipeline(programId)
|
|
const track = await createTestTrack(pipeline.id)
|
|
const stage = await createTestStage(track.id, {
|
|
name: 'Live Final Voting',
|
|
stageType: 'LIVE_FINAL',
|
|
status: 'STAGE_ACTIVE',
|
|
})
|
|
|
|
const project = await createTestProject(programId, { title: 'Vote Project' })
|
|
const cohort = await createTestCohort(stage.id, {
|
|
name: 'Voting Cohort',
|
|
isOpen: false,
|
|
})
|
|
await createTestCohortProject(cohort.id, project.id, 0)
|
|
|
|
// Verify cohort starts closed
|
|
const initialCohort = await prisma.cohort.findUnique({ where: { id: cohort.id } })
|
|
expect(initialCohort!.isOpen).toBe(false)
|
|
|
|
// Open the cohort window
|
|
const openResult = await openCohortWindow(cohort.id, admin.id, prisma)
|
|
expect(openResult.success).toBe(true)
|
|
|
|
const openedCohort = await prisma.cohort.findUnique({ where: { id: cohort.id } })
|
|
expect(openedCohort!.isOpen).toBe(true)
|
|
expect(openedCohort!.windowOpenAt).not.toBeNull()
|
|
|
|
// Close the cohort window
|
|
const closeResult = await closeCohortWindow(cohort.id, admin.id, prisma)
|
|
expect(closeResult.success).toBe(true)
|
|
|
|
const closedCohort = await prisma.cohort.findUnique({ where: { id: cohort.id } })
|
|
expect(closedCohort!.isOpen).toBe(false)
|
|
expect(closedCohort!.windowCloseAt).not.toBeNull()
|
|
})
|
|
|
|
it('rejects opening an already-open cohort', async () => {
|
|
const admin = await createTestUser('SUPER_ADMIN')
|
|
userIds.push(admin.id)
|
|
|
|
const pipeline = await createTestPipeline(programId)
|
|
const track = await createTestTrack(pipeline.id)
|
|
const stage = await createTestStage(track.id, {
|
|
name: 'Double Open Test',
|
|
stageType: 'LIVE_FINAL',
|
|
status: 'STAGE_ACTIVE',
|
|
})
|
|
|
|
const cohort = await createTestCohort(stage.id, {
|
|
name: 'Already Open Cohort',
|
|
isOpen: true, // Already open
|
|
})
|
|
|
|
const result = await openCohortWindow(cohort.id, admin.id, prisma)
|
|
expect(result.success).toBe(false)
|
|
expect(result.errors!.some(e => e.includes('already open'))).toBe(true)
|
|
})
|
|
|
|
it('rejects closing an already-closed cohort', async () => {
|
|
const admin = await createTestUser('SUPER_ADMIN')
|
|
userIds.push(admin.id)
|
|
|
|
const pipeline = await createTestPipeline(programId)
|
|
const track = await createTestTrack(pipeline.id)
|
|
const stage = await createTestStage(track.id, {
|
|
name: 'Double Close Test',
|
|
stageType: 'LIVE_FINAL',
|
|
status: 'STAGE_ACTIVE',
|
|
})
|
|
|
|
const cohort = await createTestCohort(stage.id, {
|
|
name: 'Already Closed Cohort',
|
|
isOpen: false,
|
|
})
|
|
|
|
const result = await closeCohortWindow(cohort.id, admin.id, prisma)
|
|
expect(result.success).toBe(false)
|
|
expect(result.errors!.some(e => e.includes('already closed'))).toBe(true)
|
|
})
|
|
|
|
it('creates audit trail for cohort window operations', async () => {
|
|
const admin = await createTestUser('SUPER_ADMIN')
|
|
userIds.push(admin.id)
|
|
|
|
const pipeline = await createTestPipeline(programId)
|
|
const track = await createTestTrack(pipeline.id)
|
|
const stage = await createTestStage(track.id, {
|
|
name: 'Audit Trail Test',
|
|
stageType: 'LIVE_FINAL',
|
|
status: 'STAGE_ACTIVE',
|
|
})
|
|
|
|
const cohort = await createTestCohort(stage.id, {
|
|
name: 'Audit Cohort',
|
|
isOpen: false,
|
|
})
|
|
|
|
// Open then close — verify both succeed
|
|
const openRes = await openCohortWindow(cohort.id, admin.id, prisma)
|
|
expect(openRes.success).toBe(true)
|
|
const closeRes = await closeCohortWindow(cohort.id, admin.id, prisma)
|
|
expect(closeRes.success).toBe(true)
|
|
|
|
// Verify audit trail
|
|
const auditLogs = await prisma.decisionAuditLog.findMany({
|
|
where: {
|
|
entityType: 'Cohort',
|
|
entityId: cohort.id,
|
|
},
|
|
orderBy: { createdAt: 'asc' },
|
|
})
|
|
|
|
expect(auditLogs.length).toBe(2)
|
|
expect(auditLogs[0].eventType).toBe('live.cohort_opened')
|
|
expect(auditLogs[1].eventType).toBe('live.cohort_closed')
|
|
})
|
|
})
|