Home > OS >  NestJs e2e returns 201 created response though required form data is missing, expected 400 bad reque
NestJs e2e returns 201 created response though required form data is missing, expected 400 bad reque

Time:04-29

I'm trying to write a test that checks if request body does not have proper data, it should return an error, and the status code should be 400. Which I think is by default for nestjs's validator.

This is my contorller,

@Post("register/client-business-manager")
async registerClientBusinessManager(@Body() form: RegisterClientBusinessManager): Promise<any> {
    return { something: "ok" }
}

This is my form request class,


export class RegisterClientBusinessManager {
    @IsNotEmpty()
    @MaxLength(100)
    @IsString()
    first_name: string

    @IsNotEmpty()
    @MaxLength(100)
    @IsString()
    last_name: string

   // ... other fields
}
it("returns 400 if proper data is not given", () => {
        return request(app.getHttpServer())
            .post("/auth/register/client-business-manager")
            .expect(HttpStatus.BAD_REQUEST)
    })

But the response I get,

 expected 400 "Bad Request", got 201 "Created"

      38 |         return request(app.getHttpServer())
      39 |             .post("/auth/register/client-business-manager")
    > 40 |             .expect(HttpStatus.BAD_REQUEST)
         |              ^
      41 |     })
      42 | })
      43 |

I'm also using a global validation pipe,

In my main.ts,

const app = await NestFactory.create(AppModule)

app.setGlobalPrefix("api/v1")
app.useGlobalPipes(new ValidationPipe(VALIDATION_PIPE_OPTIONS))

On the other hand, making a request from postman gives the proper 400 bad request.

I'm new to nestjs. Why might be the reason for this type of behaviour and how can I solve it?

CodePudding user response:

Looks like you are not using the Validation Pipe from NestJs. You can either:

Register a global Validation Pipe in your bootstrap function like this:

async function bootstrap() {
  // ...
  app.useGlobalPipes(new ValidationPipe());
  // app.listen(), etc.
}

or you can register the ValidationPipe, in using your @Body decorator like this:

@Post("register/client-business-manager")
async registerClientBusinessManager(@Body(ValidationPipe) form: RegisterClientBusinessManager): Promise<any> {
    return { something: "ok" }
}

EDIT: You can also register a pipe at controller level using the @UsePipes decorator

CodePudding user response:

Okay, so you've bound the ValidationPipe globally in the main.ts file's bootstrap method. You don't call that method in your test though, so the pipe never gets bound and you need to still call app.useGlobalPipes(new ValidationPipe()) in the test file. Another option would be to use the APP_PIPE global provider and bind the pipe globally that way. In your AppModule (or any other module honestly) you can do the following:

@Module({
  imports: ServerImports,
  providers: [...ServerProviders, 
    {
      provide: APP_PIPE,
      useValue: new ValidationPipe(validationPipeOptions),
    }
  ],
  controllers: ServerControllers,
})
export class AppModule {}

Now whenever you use the AppModule, whether it is in a test or in the main.ts you have the pipe globally bound and you don't need to worry about binding it again.

  • Related