Morning everybody!
Tech Stack: NestJS + GraphQL + TypeORM
Have a strange problem with TypeORM Entity Field validators (@IsURL()
& @IsNotEmpty()
) not working when running E2E tests using SuperTest with a GraphQL API.
Important to note that the application functions as expected locally & in GraphQL Playground, with the validators triggering.
Take URL validation for example:
Response from Playground with correct URL:
{
"data": {
"createProject": {
"uuid": "da1d8f48-2109-4629-a10f-67a5a7c3a5a2",
"title": "f",
"description": "descriptions",
"releaseDate": null,
"websiteURL": "www.f.com",
"slug": "f"
}
}
}
Bad URL:
{
"errors": [
{
"message": "Bad Request Exception",
"extensions": {
"code": "BAD_USER_INPUT",
"response": {
"statusCode": 400,
"message": [
"websiteURL must be an URL address"
],
"error": "Bad Request"
}
}
}
],
"data": null
}
But when an invalid URL is used during an e2e test, no error is raised - seems that the validators are not triggering.
{
data: {
createProject: {
uuid: '2be26d1f-d6b9-4a82-addc-778e497cdb1e',
title: 'URL Project',
description: 'Sit aut iusto dolor sunt.',
releaseDate: null,
websiteURL: 'invalid url',
slug: 'url-project'
}
}
}
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [
TypeOrmModule.forRoot({
...testDataSourceOptions,
entities: [],
autoLoadEntities: true,
dropSchema: true,
}),
AppModule,
],
}).compile();
const dataSource = new DataSource(testDataSourceOptions);
await dataSource.initialize();
await dataSource.runMigrations();
app = moduleFixture.createNestApplication();
await app.init();
});
it('does not allow invalid urls', () => {
const newURLProject = (title: string, websiteURL: string) => {
const description = faker.lorem.sentence();
const query = `
mutation CreateProject {
createProject(newProject: {
title: "${title}",
description: "${description}",
websiteURL: "${websiteURL}"
}) {
uuid
title
description
releaseDate
websiteURL
slug
}
}
`;
return { title, description, websiteURL, query };
};
const projectURL = newURLProject("URL Project", "invalid url")
console.log(projectURL.websiteURL)
return request(app.getHttpServer())
.post('/graphql')
.send({ query: projectURL.query })
.expect(200)
.expect(
({
body: {
errors: { errors }
}
}) => {
console.log(errors)
expect(errors[0].extensions.response.statusCode).toEqual(400);
expect(errors[0].extensions.response.message).toEqual(["websiteURL must be an URL address"]);
}
)
})
});
I can include the relevant sections of the DTO and Entity code - but these work fine within the Playground and through curl
so I do not think they are the cause of the problem.
I have rewritten the test code to use supertest-graphql
, to no effect. Next step is to try replacing Supertest entirely, but that will be a significant task so I wanted to seek that Stack Overflow wisdom first.
Any help/advice is much appreciated.
We managed to find the solution in this PR - Class Validation had to be passed manually to the e2e test file by adding app.useGlobalPipes(new ValidationPipe());
Fixed test setup below:
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [
TypeOrmModule.forRoot({
...testDataSourceOptions,
entities: [],
autoLoadEntities: true,
dropSchema: true,
}),
AppModule,
],
}).compile();
const dataSource = new DataSource(testDataSourceOptions);
await dataSource.initialize();
await dataSource.runMigrations();
app = moduleFixture.createNestApplication();
app.useGlobalPipes(new ValidationPipe()); // <----- here
await app.init();
});