1+ import { Request , Response } from 'express' ;
2+ import { authMiddleware } from '@/middlewares/auth.middleware' ;
3+ import pool from '@/configs/db.config' ;
4+
5+ // pool.query 모킹
6+ jest . mock ( '@/configs/db.config' , ( ) => ( {
7+ query : jest . fn ( ) ,
8+ } ) ) ;
9+
10+ // logger 모킹
11+ jest . mock ( '@/configs/logger.config' , ( ) => ( {
12+ error : jest . fn ( ) ,
13+ info : jest . fn ( ) ,
14+ } ) ) ;
15+
16+ describe ( '인증 미들웨어' , ( ) => {
17+ let mockRequest : Partial < Request > ;
18+ let mockResponse : Partial < Response > ;
19+ let nextFunction : jest . Mock ;
20+
21+ beforeEach ( ( ) => {
22+ // 테스트마다 request, response, next 함수 초기화
23+ mockRequest = {
24+ body : { } ,
25+ headers : { } ,
26+ cookies : { } ,
27+ } ;
28+ mockResponse = {
29+ json : jest . fn ( ) ,
30+ status : jest . fn ( ) . mockReturnThis ( ) ,
31+ } ;
32+ nextFunction = jest . fn ( ) ;
33+ } ) ;
34+
35+ afterEach ( ( ) => {
36+ jest . clearAllMocks ( ) ;
37+ } ) ;
38+
39+ describe ( 'verify' , ( ) => {
40+ const validToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYzc1MDcyNDAtMDkzYi0xMWVhLTlhYWUtYTU4YTg2YmIwNTIwIiwiaWF0IjoxNjAzOTM0NTI5LCJleHAiOjE2MDM5MzgxMjksImlzcyI6InZlbG9nLmlvIiwic3ViIjoiYWNjZXNzX3Rva2VuIn0.Q_I4PMBeeZSU-HbPZt7z9OW-tQjE0NI0I0DLF2qpZjY' ;
41+
42+ it ( '유효한 토큰으로 사용자 정보를 Request에 추가해야 한다' , async ( ) => {
43+ // 유효한 토큰 준비
44+ mockRequest . cookies = {
45+ 'access_token' : validToken ,
46+ 'refresh_token' : 'refresh-token'
47+ } ;
48+
49+ // 사용자 정보 mock
50+ const mockUser = {
51+ id : 1 ,
52+ username : 'testuser' ,
53+ email : 'test@example.com' ,
54+ velog_uuid : 'c7507240-093b-11ea-9aae-a58a86bb0520'
55+ } ;
56+
57+ // DB 쿼리 결과 모킹
58+ ( pool . query as jest . Mock ) . mockResolvedValueOnce ( {
59+ rows : [ mockUser ]
60+ } ) ;
61+
62+ // 미들웨어 실행
63+ await authMiddleware . verify (
64+ mockRequest as Request ,
65+ mockResponse as Response ,
66+ nextFunction
67+ ) ;
68+
69+ // 검증
70+ expect ( nextFunction ) . toHaveBeenCalledTimes ( 1 ) ;
71+ expect ( nextFunction ) . not . toHaveBeenCalledWith ( expect . any ( Error ) ) ;
72+ expect ( mockRequest . user ) . toEqual ( mockUser ) ;
73+ expect ( mockRequest . tokens ) . toEqual ( {
74+ accessToken : validToken ,
75+ refreshToken : 'refresh-token'
76+ } ) ;
77+ expect ( pool . query ) . toHaveBeenCalledWith (
78+ 'SELECT * FROM "users_user" WHERE velog_uuid = $1' ,
79+ [ 'c7507240-093b-11ea-9aae-a58a86bb0520' ]
80+ ) ;
81+ } ) ;
82+
83+ it ( '토큰이 없으면 InvalidTokenError를 전달해야 한다' , async ( ) => {
84+ // 토큰 없음
85+ mockRequest . cookies = { } ;
86+
87+ // 미들웨어 실행
88+ await authMiddleware . verify (
89+ mockRequest as Request ,
90+ mockResponse as Response ,
91+ nextFunction
92+ ) ;
93+
94+ // 검증
95+ expect ( nextFunction ) . toHaveBeenCalledTimes ( 1 ) ;
96+ expect ( nextFunction ) . toHaveBeenCalledWith (
97+ expect . objectContaining ( {
98+ name : 'InvalidTokenError' ,
99+ message : 'accessToken과 refreshToken의 입력이 올바르지 않습니다'
100+ } )
101+ ) ;
102+ } ) ;
103+
104+ it ( '유효하지 않은 토큰으로 InvalidTokenError를 전달해야 한다' , async ( ) => {
105+ // 유효하지 않은 토큰 (JWT 형식은 맞지만 내용이 잘못됨)
106+ const invalidToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpbnZhbGlkIjoidG9rZW4ifQ.invalidSignature' ;
107+ mockRequest . cookies = {
108+ 'access_token' : invalidToken ,
109+ 'refresh_token' : 'refresh-token'
110+ } ;
111+
112+ // 미들웨어 실행
113+ await authMiddleware . verify (
114+ mockRequest as Request ,
115+ mockResponse as Response ,
116+ nextFunction
117+ ) ;
118+
119+ // 검증
120+ expect ( nextFunction ) . toHaveBeenCalledTimes ( 1 ) ;
121+ expect ( nextFunction ) . toHaveBeenCalledWith ( expect . any ( Error ) ) ;
122+ } ) ;
123+
124+ it ( 'UUID가 없는 페이로드로 InvalidTokenError를 전달해야 한다' , async ( ) => {
125+ // UUID가 없는 토큰 (페이로드를 임의로 조작)
126+ const tokenWithoutUUID = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2MDM5MzQ1MjksImV4cCI6MTYwMzkzODEyOSwiaXNzIjoidmVsb2cuaW8iLCJzdWIiOiJhY2Nlc3NfdG9rZW4ifQ.2fLHQ3yKs9UmBQUa2oat9UOLiXzXvrhv_XHU2qwLBs8' ;
127+
128+ mockRequest . cookies = {
129+ 'access_token' : tokenWithoutUUID ,
130+ 'refresh_token' : 'refresh-token'
131+ } ;
132+
133+ // 미들웨어 실행
134+ await authMiddleware . verify (
135+ mockRequest as Request ,
136+ mockResponse as Response ,
137+ nextFunction
138+ ) ;
139+
140+ // 검증
141+ expect ( nextFunction ) . toHaveBeenCalledTimes ( 1 ) ;
142+ expect ( nextFunction ) . toHaveBeenCalledWith (
143+ expect . objectContaining ( {
144+ name : 'InvalidTokenError' ,
145+ message : '유효하지 않은 토큰 페이로드 입니다.'
146+ } )
147+ ) ;
148+ } ) ;
149+
150+ it ( '사용자를 찾을 수 없으면 DBError가 발생해야 한다' , async ( ) => {
151+ // 유효한 토큰 준비
152+ mockRequest . cookies = {
153+ 'access_token' : validToken ,
154+ 'refresh_token' : 'refresh-token'
155+ } ;
156+
157+ // 사용자가 없음 모킹
158+ ( pool . query as jest . Mock ) . mockResolvedValueOnce ( {
159+ rows : [ ]
160+ } ) ;
161+
162+ // 미들웨어 실행
163+ await authMiddleware . verify (
164+ mockRequest as Request ,
165+ mockResponse as Response ,
166+ nextFunction
167+ ) ;
168+
169+ // 검증
170+ expect ( nextFunction ) . toHaveBeenCalledTimes ( 1 ) ;
171+ expect ( mockRequest . user ) . toBeUndefined ( ) ;
172+ expect ( nextFunction ) . toHaveBeenCalledWith (
173+ expect . objectContaining ( {
174+ name : 'DBError' ,
175+ message : '사용자를 찾을 수 없습니다.'
176+ } )
177+ ) ;
178+ } ) ;
179+
180+ it ( '쿠키에 토큰이 없으면 헤더에서 토큰을 가져와야 한다' , async ( ) => {
181+ // 요청 본문에 토큰 설정
182+ mockRequest . body = {
183+ accessToken : validToken ,
184+ refreshToken : 'refresh-token'
185+ } ;
186+
187+ // 사용자 정보 mock
188+ const mockUser = {
189+ id : 1 ,
190+ username : 'testuser' ,
191+ email : 'test@example.com' ,
192+ velog_uuid : 'c7507240-093b-11ea-9aae-a58a86bb0520'
193+ } ;
194+
195+ // DB 쿼리 결과 모킹
196+ ( pool . query as jest . Mock ) . mockResolvedValueOnce ( {
197+ rows : [ mockUser ]
198+ } ) ;
199+
200+ // 미들웨어 실행
201+ await authMiddleware . verify (
202+ mockRequest as Request ,
203+ mockResponse as Response ,
204+ nextFunction
205+ ) ;
206+
207+ // 검증
208+ expect ( nextFunction ) . toHaveBeenCalledTimes ( 1 ) ;
209+ expect ( nextFunction ) . not . toHaveBeenCalledWith ( expect . any ( Error ) ) ;
210+ expect ( mockRequest . user ) . toEqual ( mockUser ) ;
211+ } ) ;
212+ } ) ;
213+ } ) ;
0 commit comments