11package wonjun .stiky .acceptance ;
22
33import static com .epages .restdocs .apispec .ResourceDocumentation .resource ;
4+ import static org .springframework .restdocs .cookies .CookieDocumentation .cookieWithName ;
5+ import static org .springframework .restdocs .cookies .CookieDocumentation .requestCookies ;
6+ import static org .springframework .restdocs .cookies .CookieDocumentation .responseCookies ;
47import static org .springframework .restdocs .mockmvc .RestDocumentationRequestBuilders .post ;
58import static org .springframework .restdocs .payload .PayloadDocumentation .fieldWithPath ;
69import static org .springframework .test .web .servlet .result .MockMvcResultMatchers .cookie ;
2023import org .springframework .http .MediaType ;
2124import org .springframework .security .crypto .bcrypt .BCryptPasswordEncoder ;
2225import wonjun .stiky .auth .config .JwtTokenProvider ;
26+ import wonjun .stiky .auth .controller .dto .TokenDto ;
2327import wonjun .stiky .member .domain .Member ;
2428import wonjun .stiky .member .repository .MemberRepository ;
2529
@@ -232,4 +236,66 @@ void login() throws Exception {
232236 ));
233237 }
234238
239+ @ Test
240+ @ DisplayName ("토큰 재발급 API" )
241+ void reissue () throws Exception {
242+ // Given
243+ String email = "reissue@example.com" ;
244+ String role = "ROLE_USER" ;
245+
246+ TokenDto tokenDto = jwtTokenProvider .generateToken (email , role );
247+ String validRefreshToken = tokenDto .getRefreshToken ();
248+
249+ redisTemplate .opsForValue ().set ("RT:" + email , validRefreshToken , 7 , TimeUnit .DAYS );
250+
251+ memberRepository .save (Member .builder ()
252+ .email (email )
253+ .password ("password" )
254+ .nickname ("재발급유저" )
255+ .role (role )
256+ .provider ("local" )
257+ .build ());
258+
259+ // When & Then
260+ mockMvc .perform (post ("/api/auth/reissue" )
261+ .cookie (new jakarta .servlet .http .Cookie ("refresh_token" , validRefreshToken ))
262+ .contentType (MediaType .APPLICATION_JSON ))
263+ .andExpect (status ().isOk ())
264+ .andExpect (jsonPath ("$.accessToken" ).exists ())
265+ .andDo (document ("auth-reissue" ,
266+ resource (ResourceSnippetParameters .builder ()
267+ .tag ("Auth" )
268+ .summary ("토큰 재발급" )
269+ .description ("쿠키에 담긴 Refresh Token을 이용하여 Access Token을 재발급받습니다." )
270+ .responseSchema (Schema .schema ("ReissueResponse" ))
271+ .responseFields (
272+ fieldWithPath ("accessToken" ).description ("새로 발급된 액세스 토큰" )
273+ )
274+ .build ()),
275+ requestCookies (
276+ cookieWithName ("refresh_token" ).description ("리프레시 토큰 (HttpOnly)" )
277+ )
278+ ));
279+ }
280+
281+ @ Test
282+ @ DisplayName ("로그아웃 API" )
283+ void logout () throws Exception {
284+ // When & Then
285+ mockMvc .perform (post ("/api/auth/logout" )
286+ .contentType (MediaType .APPLICATION_JSON ))
287+ .andExpect (status ().isOk ())
288+ .andExpect (cookie ().maxAge ("refresh_token" , 0 )) // 쿠키 삭제 확인
289+ .andDo (document ("auth-logout" ,
290+ resource (ResourceSnippetParameters .builder ()
291+ .tag ("Auth" )
292+ .summary ("로그아웃" )
293+ .description ("사용자의 리프레시 토큰 쿠키를 삭제합니다." )
294+ .build ()),
295+ responseCookies (
296+ cookieWithName ("refresh_token" ).description ("삭제된 리프레시 토큰 (Max-Age: 0)" )
297+ )
298+ ));
299+ }
300+
235301}
0 commit comments