mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
test(common): add test for flattening children errors (validation)
This commit is contained in:
@@ -120,12 +120,7 @@ export class ValidationPipe implements PipeTransform<any> {
|
||||
if (this.isDetailedOutputDisabled) {
|
||||
return new HttpErrorByCode[this.errorHttpStatusCode]();
|
||||
}
|
||||
const errors = iterate(validationErrors)
|
||||
.filter(item => !!item.constraints)
|
||||
.map(item => Object.values(item.constraints))
|
||||
.flatten()
|
||||
.toArray();
|
||||
|
||||
const errors = this.flattenValidationErrors(validationErrors);
|
||||
return new HttpErrorByCode[this.errorHttpStatusCode](errors);
|
||||
};
|
||||
}
|
||||
@@ -172,4 +167,46 @@ export class ValidationPipe implements PipeTransform<any> {
|
||||
private isPrimitive(value: unknown): boolean {
|
||||
return ['number', 'boolean', 'string'].includes(typeof value);
|
||||
}
|
||||
|
||||
private flattenValidationErrors(
|
||||
validationErrors: ValidationError[],
|
||||
): string[] {
|
||||
return iterate(validationErrors)
|
||||
.map(error => this.mapChildrenToValidationErrors(error))
|
||||
.flatten()
|
||||
.filter(item => !!item.constraints)
|
||||
.map(item => Object.values(item.constraints))
|
||||
.flatten()
|
||||
.toArray();
|
||||
}
|
||||
|
||||
private mapChildrenToValidationErrors(
|
||||
error: ValidationError,
|
||||
): ValidationError[] {
|
||||
if (!(error.children && error.children.length)) {
|
||||
return [error];
|
||||
}
|
||||
const validationErrors = [];
|
||||
for (const item of error.children) {
|
||||
if (item.children && item.children.length) {
|
||||
validationErrors.push(...this.mapChildrenToValidationErrors(item));
|
||||
}
|
||||
validationErrors.push(this.prependConstraintsWithParentProp(error, item));
|
||||
}
|
||||
return validationErrors;
|
||||
}
|
||||
|
||||
private prependConstraintsWithParentProp(
|
||||
parentError: ValidationError,
|
||||
error: ValidationError,
|
||||
): ValidationError {
|
||||
const constraints = {};
|
||||
for (const key in error.constraints) {
|
||||
constraints[key] = `${parentError.property}.${error.constraints[key]}`;
|
||||
}
|
||||
return {
|
||||
...error,
|
||||
constraints,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import * as chai from 'chai';
|
||||
import { expect } from 'chai';
|
||||
import * as chaiAsPromised from 'chai-as-promised';
|
||||
import { Exclude, Expose } from 'class-transformer';
|
||||
import { IsOptional, IsString } from 'class-validator';
|
||||
import { Exclude, Expose, Type } from 'class-transformer';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsDefined,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
import { HttpStatus } from '../../enums';
|
||||
import { UnprocessableEntityException } from '../../exceptions';
|
||||
import { ArgumentMetadata } from '../../interfaces';
|
||||
@@ -27,10 +33,11 @@ class TestModelInternal {
|
||||
}
|
||||
|
||||
class TestModel {
|
||||
constructor() {}
|
||||
@IsString() public prop1: string;
|
||||
@IsString()
|
||||
public prop1: string;
|
||||
|
||||
@IsString() public prop2: string;
|
||||
@IsString()
|
||||
public prop2: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@@ -112,6 +119,43 @@ describe('ValidationPipe', () => {
|
||||
const testObj = { prop1: 'value1' };
|
||||
return expect(target.transform(testObj, metadata)).to.be.rejected;
|
||||
});
|
||||
|
||||
class TestModel2 {
|
||||
@IsString()
|
||||
public prop1: string;
|
||||
|
||||
@IsBoolean()
|
||||
public prop2: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
public optionalProp: string;
|
||||
}
|
||||
class TestModelWithNested {
|
||||
@IsString()
|
||||
prop: string;
|
||||
|
||||
@IsDefined()
|
||||
@Type(() => TestModel2)
|
||||
@ValidateNested()
|
||||
test: TestModel2;
|
||||
}
|
||||
it('should flatten nested errors', async () => {
|
||||
try {
|
||||
const model = new TestModelWithNested();
|
||||
model.test = new TestModel2();
|
||||
await target.transform(model, {
|
||||
type: 'body',
|
||||
metatype: TestModelWithNested,
|
||||
});
|
||||
} catch (err) {
|
||||
expect(err.getResponse().message).to.be.eql([
|
||||
'prop must be a string',
|
||||
'test.prop1 must be a string',
|
||||
'test.prop2 must be a boolean value',
|
||||
]);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe('when validation transforms', () => {
|
||||
it('should return a TestModel instance', async () => {
|
||||
|
||||
Reference in New Issue
Block a user