구현하고 있던 NestJS 프로젝트에서 e2e 테스트 코드를 작성하고 있었다.
다음과 같이 Guard를 통해 로그인한 사용자만이 접근할 수 있는 엔드 포인트에 대해 처리를 해야 했다.
@Post()
@UseGuards(JwtAuthGuard)
async writeComment(
@Body() createCommentDto: CreateCommentDto,
@GetUser() user: User,
) {
const newComment = await this.commentsService.writeComment(createCommentDto, user);
return newComment;
}
현재 프로젝트에서는 인증에 passport 모듈을 사용하고 있었고, 소셜 로그인(Google OAuth 2.0) 위한 Strategy, 사용자 인증을 위한 JWT Strategy, 토큰 재발급을 위한 Strategy 가 있었고 필요한 엔드 포인트에 알맞는 Guard 를 적용했다.
그런데 테스트 환경에서 로컬 로그인이 아닌 소셜 로그인 과정을 어떻게 접근하고 처리해야 할지 어려웠던 것 같다.
그래서 해결 방안을 찾아보던 중 Guard 를 오버라이드할 수 있다는 것을 알게 되었고 이를 적용해보았다.
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
})
.overrideGuard(JwtAuthGuard)
.useValue(mockAuthGuard)
.compile();
app = moduleFixture.createNestApplication();
setUpTestingAppModule(app);
await app.init();
...
});
다음과 같이 생성한 테스팅 모듈에 .overrideGuard() 메서드로 Guard 를 오버라이드 할 수 있다.
import { ExecutionContext } from "@nestjs/common";
export const mockAuthGuard = {
canActivate: (context: ExecutionContext) => {
const request = context.switchToHttp().getRequest();
request['user'] = { id: 1 };
return true;
}
}
NestJS 의 Guard 는 canActivate() 를 구현해야 한다. 따라서 해당 메서드를 오버라이드하는 객체 안에 포함시키고, 기존 Auth Guard 에서 requeest 객체에 user 정보를 넣어주던 작업을 수행하고 리턴했다.
이제 테스팅 모듈의 app 객체로 받는 요청은 JwtAuthGuard 인증을 통과한 채로 전달되었고, 이제 사용자 인증이 필요한 엔드 포인트에 대해 인증이 된 상태로 테스트할 수 있게 되었다.
Reference
https://stackoverflow.com/questions/57629191/nestjs-mock-jwt-authentication-in-e2e-tests
https://velog.io/@atoye1/Nest.js-e2e-test%EC%97%90%EC%84%9C-authGuard-%EC%9A%B0%ED%9A%8C%ED%95%98%EA%B8%B0