test: harden business boundary conditions
This commit is contained in:
35
apps/server/src/sync/dto/schedule-sync.dto.spec.ts
Normal file
35
apps/server/src/sync/dto/schedule-sync.dto.spec.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'reflect-metadata';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { ScheduleSyncQueryDto } from './schedule-sync.dto';
|
||||
|
||||
describe('ScheduleSyncQueryDto', () => {
|
||||
it('transforms valid query strings', async () => {
|
||||
const dto = plainToInstance(ScheduleSyncQueryDto, {
|
||||
dateFrom: '2026-07-13',
|
||||
days: '7',
|
||||
attendanceMachineOnly: 'true',
|
||||
});
|
||||
expect(await validate(dto)).toEqual([]);
|
||||
expect(dto).toMatchObject({ days: 7, attendanceMachineOnly: true });
|
||||
});
|
||||
|
||||
it.each(['0', '-1', '91', '7.5', 'abc'])('rejects invalid sync days %s', async (days) => {
|
||||
const dto = plainToInstance(ScheduleSyncQueryDto, { days });
|
||||
expect((await validate(dto)).some((error) => error.property === 'days')).toBe(true);
|
||||
});
|
||||
|
||||
it.each(['not-a-date', '2026-02-31', '2026-07-13T00:00:00Z'])(
|
||||
'rejects invalid or non-date-only start date %s',
|
||||
async (dateFrom) => {
|
||||
const dto = plainToInstance(ScheduleSyncQueryDto, { dateFrom });
|
||||
expect((await validate(dto)).some((error) => error.property === 'dateFrom')).toBe(true);
|
||||
},
|
||||
);
|
||||
|
||||
it('treats non-true boolean strings as false', async () => {
|
||||
const dto = plainToInstance(ScheduleSyncQueryDto, { attendanceMachineOnly: 'false' });
|
||||
expect(await validate(dto)).toEqual([]);
|
||||
expect(dto.attendanceMachineOnly).toBe(false);
|
||||
});
|
||||
});
|
||||
21
apps/server/src/sync/dto/schedule-sync.dto.ts
Normal file
21
apps/server/src/sync/dto/schedule-sync.dto.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Transform, Type } from 'class-transformer';
|
||||
import { IsBoolean, IsISO8601, IsInt, IsOptional, Matches, Max, Min } from 'class-validator';
|
||||
|
||||
export class ScheduleSyncQueryDto {
|
||||
@IsOptional()
|
||||
@Matches(/^\d{4}-\d{2}-\d{2}$/)
|
||||
@IsISO8601({ strict: true })
|
||||
dateFrom?: string;
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
@Max(90)
|
||||
days: number = 30;
|
||||
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => value === true || value === 'true')
|
||||
@IsBoolean()
|
||||
attendanceMachineOnly: boolean = false;
|
||||
}
|
||||
Reference in New Issue
Block a user