test: harden business boundary conditions

This commit is contained in:
2026-07-15 00:03:55 +08:00
parent 17a5046ea0
commit b1f35f9d1a
65 changed files with 2311 additions and 293 deletions

View File

@@ -0,0 +1,42 @@
import { validate } from 'class-validator';
import { CreateRentalDto } from './rental.dto';
const createRental = (overrides: Partial<CreateRentalDto> = {}) =>
Object.assign(new CreateRentalDto(), {
classroomId: 1,
lesseeOrganizationId: 2,
startDate: '2026-08-01',
endDate: '2026-08-31',
...overrides,
});
describe('classroom rental DTO boundaries', () => {
it.each(['2026-02-31', '2026-08-01T00:00:00Z', '2026-8-1'])(
'rejects invalid or non-date-only value %s',
async (startDate) => {
const errors = await validate(createRental({ startDate }));
expect(errors.some((error) => error.property === 'startDate')).toBe(true);
},
);
it.each([
['dailyRate', 0],
['totalAmount', -1],
] as const)('rejects non-positive %s', async (field, value) => {
const errors = await validate(createRental({ [field]: value }));
expect(errors.some((error) => error.property === field)).toBe(true);
});
it('accepts positive amounts and a leap-day date', async () => {
await expect(
validate(
createRental({
startDate: '2028-02-29',
endDate: '2028-02-29',
dailyRate: 0.01,
totalAmount: 0.01,
}),
),
).resolves.toHaveLength(0);
});
});

View File

@@ -1,4 +1,4 @@
import { IsOptional, IsString, IsInt, IsNumber, IsDateString } from 'class-validator';
import { IsOptional, IsString, IsInt, IsNumber, IsISO8601, Matches, Min } from 'class-validator';
export class CreateRentalDto {
@IsInt()
@@ -11,18 +11,22 @@ export class CreateRentalDto {
@IsInt()
lesseeOrganizationId: number;
@IsDateString()
@Matches(/^\d{4}-\d{2}-\d{2}$/)
@IsISO8601({ strict: true })
startDate: string;
@IsDateString()
@Matches(/^\d{4}-\d{2}-\d{2}$/)
@IsISO8601({ strict: true })
endDate: string;
@IsOptional()
@IsNumber()
@Min(0.01)
dailyRate?: number;
@IsOptional()
@IsNumber()
@Min(0.01)
totalAmount?: number;
@IsOptional()
@@ -44,19 +48,23 @@ export class UpdateRentalDto {
lesseeOrganizationId?: number;
@IsOptional()
@IsDateString()
@Matches(/^\d{4}-\d{2}-\d{2}$/)
@IsISO8601({ strict: true })
startDate?: string;
@IsOptional()
@IsDateString()
@Matches(/^\d{4}-\d{2}-\d{2}$/)
@IsISO8601({ strict: true })
endDate?: string;
@IsOptional()
@IsNumber()
@Min(0.01)
dailyRate?: number;
@IsOptional()
@IsNumber()
@Min(0.01)
totalAmount?: number;
@IsOptional()