Files
hackerspace.sh/__tests__/classes-logic.test.ts
T
Moheeb Zara dc23e9261f feat(classes): pure capacity/waitlist logic + Zod schemas
classes-logic.ts: effectiveCapacity (session override > class > unlimited),
computeSignupStatus (registered vs waitlisted), sessionTiming, canSignUp
eligibility, pickPromotion (earliest waitlisted when a seat frees).
Dependency-free, 10 unit tests (suite 372 -> 382).

validations.ts: class/session/signup/attendance schemas. payment_link is
a generic http(s) link only (empty -> null); capacity is a positive int;
no live payment integration.
2026-05-16 19:29:08 -07:00

75 lines
3.0 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import {
effectiveCapacity,
computeSignupStatus,
sessionTiming,
canSignUp,
pickPromotion,
} from '@/lib/classes-logic'
describe('effectiveCapacity', () => {
it('session override wins, else class, else unlimited', () => {
expect(effectiveCapacity(5, 10)).toBe(5)
expect(effectiveCapacity(null, 10)).toBe(10)
expect(effectiveCapacity(undefined, undefined)).toBeNull()
expect(effectiveCapacity(0 as unknown as number, 10)).toBe(0)
})
})
describe('computeSignupStatus', () => {
it('unlimited capacity always registers', () => {
expect(computeSignupStatus(null, 999)).toBe('registered')
})
it('registers under capacity, waitlists at/over', () => {
expect(computeSignupStatus(3, 2)).toBe('registered')
expect(computeSignupStatus(3, 3)).toBe('waitlisted')
expect(computeSignupStatus(3, 4)).toBe('waitlisted')
})
})
describe('sessionTiming', () => {
const now = '2026-05-16T12:00:00.000Z'
it('classifies relative to now', () => {
expect(sessionTiming('2026-05-17T00:00:00.000Z', null, now)).toBe('upcoming')
expect(sessionTiming('2026-05-15T00:00:00.000Z', '2026-05-15T01:00:00.000Z', now)).toBe('past')
expect(sessionTiming('2026-05-16T11:00:00.000Z', '2026-05-16T13:00:00.000Z', now)).toBe('in_progress')
})
it('with no end, a started session is past once now exceeds start', () => {
expect(sessionTiming('2026-05-16T11:59:59.000Z', null, now)).toBe('past')
})
})
describe('canSignUp', () => {
const now = '2026-05-16T12:00:00.000Z'
it('rejects cancelled/completed/past', () => {
expect(canSignUp({ sessionStatus: 'cancelled', startsAt: '2026-06-01T00:00:00Z', now }).ok).toBe(false)
expect(canSignUp({ sessionStatus: 'completed', startsAt: '2026-06-01T00:00:00Z', now }).ok).toBe(false)
expect(canSignUp({ sessionStatus: 'scheduled', startsAt: '2026-05-01T00:00:00Z', endsAt: '2026-05-01T01:00:00Z', now }).ok).toBe(false)
})
it('allows an upcoming scheduled session', () => {
expect(canSignUp({ sessionStatus: 'scheduled', startsAt: '2026-06-01T00:00:00Z', now }).ok).toBe(true)
})
})
describe('pickPromotion', () => {
it('promotes the earliest waitlisted when a seat is free', () => {
const s = [
{ id: 'r1', status: 'registered', signed_up_at: '2026-01-01T00:00:00Z' },
{ id: 'w2', status: 'waitlisted', signed_up_at: '2026-01-03T00:00:00Z' },
{ id: 'w1', status: 'waitlisted', signed_up_at: '2026-01-02T00:00:00Z' },
]
expect(pickPromotion(s, 3)).toBe('w1')
})
it('returns null when still at capacity', () => {
const s = [
{ id: 'r1', status: 'registered', signed_up_at: '2026-01-01T00:00:00Z' },
{ id: 'r2', status: 'registered', signed_up_at: '2026-01-01T00:00:00Z' },
{ id: 'w1', status: 'waitlisted', signed_up_at: '2026-01-02T00:00:00Z' },
]
expect(pickPromotion(s, 2)).toBeNull()
})
it('returns null when nobody is waiting', () => {
expect(pickPromotion([{ id: 'r1', status: 'registered', signed_up_at: 'x' }], 5)).toBeNull()
})
})