Issue
I have a NestJS backend with CSRF protection and an endpoint to get the CSRF token. I’m getting TypeError: req.csrfToken is not a function
when testing this endpoint with jest and supertest.
My code is like this:
// main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(cookieParser());
app.use(csurf({ cookie: true }));
await app.listen(process.env.BACKEND_SERVER_PORT);
}
// authController.ts
import { Controller, Req, Get } from "@nestjs/common";
import { Request } from "express";
import * as AuthDto from "./modules/auth/dto/auth.dto";
@Controller("auth")
export class AppController {
constructor() {}
@Get("csrf")
async getCsrfToken(@Req() req: Request): Promise<AuthDto.CsrfOutput> {
return { csrfToken: req.csrfToken() }; // <-- ERROR HAPPENS HERE
}
}
// app.controller.spec.ts
import { Test, TestingModule } from "@nestjs/testing";
import { INestApplication } from "@nestjs/common";
import request from "supertest";
import AppModule from "../src/app.module";
describe("AppController (e2e)", () => {
let app: INestApplication;
let server: any;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
server = app.getHttpServer();
});
it("/csrf (GET)", () => {
return request(server).get("/auth/csrf").expect(200).expect("hello");
// I'll add more validations here once I get past this error
});
});
I believe this may be related with the test itself, since this endpoint is working fine when called by an external client (our frontend application or Postman). It just doesn’t work with supertest.
Anybody has an idea why? Thanks.
Solution
You only register csurf
in main.ts
, but your test uses AppModule
directly. AppModule doesn’t register csurf
on its own. Therefore, when the test creates your AppModule, it doesn’t have the necessary middleware.