I am having a hard time to get my ValidationPipe working within the class-validator, when using a nested object.
For instance, I have the NestedObject format:
{
Data: '123',
Value: 567
}
I then create the nested-object.ts class:
import { IsNumber, IsNumberString, Min, MinLength } from 'class-validator';
export class NestedObject {
@IsNumberString() @MinLength(2) public readonly Data: string;
@IsNumber() @Min(2) public readonly Value: number;
}
I can then write a Jest test case to cover this nested object in the ValidationPipe, and get the data validated.
nested-object.spec.ts
import { ArgumentMetadata, HttpStatus, ValidationPipe } from '@nestjs/common';
import { NestedObject } from './nested-object';
describe('NestedObject', () => {
it('should be defined', () => {
expect(new NestedObject()).toBeDefined();
});
it('should validate the NestedObject definition for JSON payload { Data: null, Value: 0 }', async () => {
const target: ValidationPipe = new ValidationPipe({
transform: true,
whitelist: true,
enableDebugMessages: true,
errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,
});
const metadata: ArgumentMetadata = {
type: 'body',
metatype: NestedObject,
data: '',
};
const Expected: string[] = [
'Data must be longer than or equal to 2 characters',
'Data must be a number string',
'Value must not be less than 2',
];
await target.transform({ Data: null, Value: 0 }, metadata).catch((err) => {
expect(err.getResponse().statusCode).toBe(HttpStatus.UNPROCESSABLE_ENTITY);
expect(err.getResponse().message).toEqual(Expected);
});
});
});
The above test passes. I have created the basic object, and this works fine. My issue is when I now try to get this object validated within another class. The new class validation works, but not the nested object.
parent-object.ts
import { Type } from 'class-transformer';
import { IsString, MinLength, ValidateNested } from 'class-validator';
import { NestedObject } from './nested-object';
export class ParentObject {
@IsString() @MinLength(1) public readonly FileName: string;
@ValidateNested()
@Type(() => NestedObject)
public Child: NestedObject;
}
I am now erxpecting that my ParentObject would be:
{
FileName: 'abc.txt',
Child: {
Data: '123',
Value: 567
}
}
I then write the test cases for the ParentObject.
parent-object.spec.ts
import { ArgumentMetadata, HttpStatus, ValidationPipe } from '@nestjs/common';
import { NestedObject } from './nested-object';
import { ParentObject } from './parent-object';
describe('ParentObject', () => {
it('should be defined', () => {
expect(new ParentObject()).toBeDefined();
});
it('should validate the ParentObject & NestedObject for JSON payload { FileName: null, Child: { Data: null, Value: 0 } }', async () => {
const target: ValidationPipe = new ValidationPipe({
transform: true,
whitelist: true,
enableDebugMessages: true,
errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,
});
const metadata: ArgumentMetadata = {
type: 'body',
metatype: ParentObject,
data: '',
};
const Expected: string[] = [
'FileName must be longer than or equal to 1 characters',
'FileName must be a string',
'Child.Data must be longer than or equal to 2 characters',
'Child.Data must be a number string',
'Child.Value must not be less than 2',
];
await target.transform({ FileName: null, Child: { Data: null, Value: 0 } }, metadata).catch((err) => {
expect(err.getResponse().statusCode).toBe(HttpStatus.UNPROCESSABLE_ENTITY);
expect(err.getResponse().message).toEqual(Expected);
});
});
});
The test fails. The test only returns the FileName validations, not the 3 Child validations that should come from the NestedObject.
- Expected - 3
+ Received + 2
Array [
- "Child.Data must be longer than or equal to 2 characters",
- "Child.Data must be a number string",
- "Child.Value must not be less than 2",
+ "FileName must be longer than or equal to 1 characters",
+ "FileName must be a string",
]
The validation ran and detected the FileName issue, but it did not find the NestedObject errors. Am I building the objects incorrectly when using the NestedObject? Am I missing something in the test to get the child node checked?