import 'reflect-metadata'; import { validate } from 'class-validator'; import { CreateScheduleDto, UpdateScheduleDto } from './schedule.dto'; const createSchedule = (notes: string) => Object.assign(new CreateScheduleDto(), { classId: 1, classroomId: 2, weekDay: 1, startTime: '09:00', endTime: '10:00', startDate: '2026-07-01', endDate: '2026-07-31', subject: '语文', notes, }); describe('schedule attendance window validation', () => { it('accepts a configurable number of minutes before class', async () => { const dto = createSchedule(''); dto.attendanceAdvanceMinutes = 45; const errors = await validate(dto); expect(errors.some((error) => error.property === 'attendanceAdvanceMinutes')).toBe(false); }); it('rejects values outside 0 to 1440 minutes', async () => { const dto = Object.assign(new UpdateScheduleDto(), { attendanceAdvanceMinutes: 1441 }); const errors = await validate(dto); expect(errors.some((error) => error.property === 'attendanceAdvanceMinutes')).toBe(true); }); }); describe('schedule notes validation', () => { it('rejects notes longer than 500 characters when creating', async () => { const errors = await validate(createSchedule('a'.repeat(501))); expect(errors.some((error) => error.property === 'notes')).toBe(true); }); it('rejects notes longer than 500 characters when updating', async () => { const dto = Object.assign(new UpdateScheduleDto(), { notes: 'a'.repeat(501) }); const errors = await validate(dto); expect(errors.some((error) => error.property === 'notes')).toBe(true); }); }); it('removes the retired departmentId field from create requests', async () => { const dto = Object.assign(new CreateScheduleDto(), { classId: 1, classroomId: 2, weekDay: 1, startTime: '09:00', endTime: '10:00', startDate: '2026-07-01', endDate: '2026-07-31', subject: '语文', departmentId: 99, }); await validate(dto, { whitelist: true }); expect(dto).not.toHaveProperty('departmentId'); }); describe('schedule boundary validation', () => { it.each(['24:00', '09:60', '99:99', '9:00'])('rejects invalid time %s', async (time) => { const dto = createSchedule(''); dto.startTime = time; expect((await validate(dto)).some((error) => error.property === 'startTime')).toBe(true); }); it.each(['2026-02-31', '2026-07-13T00:00:00Z', '2026-7-13'])( 'rejects invalid or non-date-only value %s', async (date) => { const dto = createSchedule(''); dto.startDate = date; expect((await validate(dto)).some((error) => error.property === 'startDate')).toBe(true); }, ); it('accepts inclusive attendance-window limits and a leap-day date', async () => { const zero = createSchedule(''); zero.attendanceAdvanceMinutes = 0; zero.startDate = '2028-02-29'; const fullDay = createSchedule(''); fullDay.attendanceAdvanceMinutes = 1440; expect(await validate(zero)).toEqual([]); expect(await validate(fullDay)).toEqual([]); }); });