NestJS ValidationPipe() not processing Nested Object even with the @ValidateNested and @Type configurated

Viewed 169

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?

0 Answers
Related