90 lines
3.0 KiB
TypeScript
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([]);
|
|
});
|
|
});
|