I’ve found this GitHub issue comment that has an interesting workaround for accessing a custom decorator through reflection, but the problem is that I’m trying to use it to test my use case which includes a validation pipe in it and it doesn’t seem to be executing the validation part of it.
This is the custom decorator:
import { createParamDecorator, ExecutionContext, ValidationPipe } from '@nestjs/common'
const RawBody = createParamDecorator((_: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest()
return request.body
})
export const StopAtFirstError = () =>
RawBody(
new ValidationPipe({
validateCustomDecorators: true,
transform: true,
whitelist: true,
stopAtFirstError: true,
}),
)
This is the test:
// Helper function to get the custom param decorator
const getParamDecoratorFactory = <T>(decorator: Function) => {
class Test {
public test(@decorator() _: T) {}
}
console.log(decorator)
const args = Reflect.getMetadata(ROUTE_ARGS_METADATA, Test, 'test')
return args[Object.keys(args)[0]].factory
}
...
it('should throw only 'password too long' error if password is too long and weak', async () => {
// Arrange
const mockBodyWithUser = {
username: 'username',
firstName: 'firstName',
lastName: 'lastName',
password: 'very long and weak password that should return only 'password too long' error',
role: Role.USER,
} as UserDto
const req = httpMock.createRequest()
const res = httpMock.createRequest()
req.body = mockBodyWithUser
const ctx = new ExecutionContextHost([req, res], UserController, controller.save)
const stopAtFirstErrorDecorator = getParamDecoratorFactory(StopAtFirstError)
// Act
const errors = stopAtFirstErrorDecorator(null, ctx)
// Assert
expect(errors.length).toEqual(1)
})
The thing is: errors
ends up being just the mockBodyWithUser
object instead of the errors that the validation normally retrieves because of the UserDTO password validation rules (it has many rules, but the relevant ones are @MaxLength(20)
and @Matches([Regexp])
that matches a strong password). I’ve tried typing the decorator in getParamDecoratorFactory
as ParamDecorator
, but then I can’t retrieve it through reflection. Any ideas if there could be any workaround to validate?