Files
gongxue-base/apps/server/src/schedules/dto/schedule.dto.spec.ts

90 lines
3.0 KiB
TypeScript

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([]);
});
});