In following up from this question, I am trying to ensure the validation remains and works. However, my combined class does not validate the included fields. For instance, I have a basic AdminCodeDTO that sepcifies the AdminCode is required, has a valid value (1-999)
import { IsNumber, Min, Max, IsDefined } from '@nestjs/class-validator';
import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger';
export class AdminCodeDTO {
@ApiProperty({
description: 'Sweda Administration Code used for time tracking that is not part of a mantis.',
})
@ApiResponseProperty({ example: 5 })
@IsDefined() @IsNumber() @Min(1) @Max(999) public AdminCode: number;
constructor(AdminCode?: number) {
this.AdminCode = AdminCode;
}
}
Testing this class works, and the validation will return the errors:
import { validate } from '@nestjs/class-validator';
import { ValidationError } from '@nestjs/common';
import { AdminCodeDTO } from './admin-code-dto';
describe('AdminCodeDto', () => {
let TestDTO: AdminCodeDTO;
beforeEach( () => {
TestDTO = new AdminCodeDTO(5);
});
it('should be defined', () => {
expect(TestDTO).toBeDefined();
});
it('should have the AdminCode value set', () => {
expect(TestDTO.AdminCode).toBe(5);
});
it('should allow creation with an empty constructor', () => {
expect(new AdminCodeDTO()).toBeDefined();
});
it('should generate the DTO errors', async () => {
const DTOValidCheck: AdminCodeDTO = new AdminCodeDTO();
const Errors: Array<ValidationError> = await validate(DTOValidCheck);
expect(Errors.length).toBe(1);
expect(Errors[0].constraints['isDefined']).toBe('AdminCode should not be null or undefined');
expect(Errors[0].constraints['isNumber']).toBe('AdminCode must be a number conforming to the specified constraints');
expect(Errors[0].constraints['max']).toBe('AdminCode must not be greater than 999');
expect(Errors[0].constraints['min']).toBe('AdminCode must not be less than 1');
});
});
To then build a simple DTO combining 2 fields to do the testing, I create a description DTO as well, to add that field for this simple example.
import { IsDefined, IsString, MaxLength, MinLength } from '@nestjs/class-validator';
import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger';
export class DescriptionDTO {
@ApiProperty({
description: '',
minLength: 3,
maxLength: 20
})
@ApiResponseProperty({ example: 'Sick Day' })
@IsDefined() @IsString() @MaxLength(20) @MinLength(3) public Description: string;
constructor(Description?: string) {
this.Description = Description;
}
}
I then use the IntersectionType of @nestjs/swagger, to combine the AdminCodeDTO, with a new description field for the payload.
import { IsDefined, IsString, MaxLength, MinLength } from '@nestjs/class-validator';
import { ApiProperty, ApiResponseProperty, IntersectionType} from '@nestjs/swagger';
import { AdminCodeDTO } from './admin-code-dto';
export class AdmininstrationCodesDTO extends IntersectionType(
AdminCodeDTO,
DescriptionDTO
)
{
constructor(AdminCode?: number, Description?: string) {
this.AdminCode = AdminCode;
this.Description = Description;
}
My test however, while all the columns are defined, the validation does not work.
import { AdmininstrationCodesDTO } from './admininstration-codes-dto';
describe('AdmininstrationCodesDTO', () => {
let TestDTO: AdmininstrationCodesDTO;
beforeEach( () => {
TestDTO = new AdmininstrationCodesDTO(77, 'Test Admin Code');
})
it('should be defined', () => {
expect(TestDTO).toBeDefined();
});
it('should be defined when launched without parameters', () => {
expect(new AdmininstrationCodesDTO()).toBeDefined();
})
it.each([
['AdminCode', 77],
['Description', 'Test Admin Code'],
])('should have the proper field {%s} set to be %d', (FieldName, Expected) => {
expect(FieldName in TestDTO).toBe(true);
expect(TestDTO[FieldName]).toBe(Expected);
});
// This test fails as the validation settings are not enforced. Working on any of the DTOs directly though, the validation is confirmed.
it('should generate the DTO errors', async () => {
const TestDTO: AdmininstrationCodesDTO = new AdmininstrationCodesDTO();
const Errors: Array<ValidationError> = await validate(TestDTO, );
expect(Errors.length).toBe(8);
});
});
EDIT: This also causes a problem in my Swagger UI documentation, where this method now prevents my request schemas from showing the data. When I define my fields directly in the DTO (without IntersectionType) the fields show up in the request schema for Swagger. I have the CLI functions enabled in the project.json (NX monorepo).