package roomescape.system.auth.web import io.mockk.every import org.hamcrest.Matchers.containsString import org.hamcrest.Matchers.`is` import org.springframework.data.repository.findByIdOrNull import roomescape.util.MemberFixture import roomescape.util.RoomescapeApiTest import roomescape.common.exception.ErrorType class AuthControllerTest : RoomescapeApiTest() { val userRequest: LoginRequest = MemberFixture.userLoginRequest() init { Given("로그인 요청을 보낼 때") { val endpoint: String = "/login" When("로그인에 성공하면") { val expectedToken: String = "expectedToken" every { memberRepository.findByEmailAndPassword(userRequest.email, userRequest.password) } returns user every { jwtHandler.createToken(user.id!!) } returns expectedToken Then("토큰을 쿠키에 담아 응답한다") { runPostTest(endpoint, body = MemberFixture.userLoginRequest()) { statusCode(200) cookie("accessToken", expectedToken) header("Set-Cookie", containsString("Max-Age=1800000")) header("Set-Cookie", containsString("HttpOnly")) header("Set-Cookie", containsString("Secure")) } } } When("회원을 찾지 못하면") { every { memberRepository.findByEmailAndPassword(userRequest.email, userRequest.password) } returns null Then("400 에러를 응답한다") { runPostTest(endpoint, body = userRequest) { log().all() statusCode(400) body("errorType", `is`(ErrorType.MEMBER_NOT_FOUND.name)) } } } When("잘못된 요청을 보내면 400 에러를 응답한다.") { Then("이메일 형식이 잘못된 경우") { val invalidRequest: LoginRequest = userRequest.copy(email = "invalid") runPostTest(endpoint, body = invalidRequest) { log().all() statusCode(400) body("message", `is`("이메일 형식이 일치하지 않습니다. 예시: abc123@gmail.com")) } } Then("비밀번호가 공백인 경우") { val invalidRequest = userRequest.copy(password = " ") runPostTest(endpoint, body = invalidRequest) { log().all() statusCode(400) body("message", `is`("비밀번호는 공백일 수 없습니다.")) } } } } Given("로그인 상태를 확인할 때") { val endpoint: String = "/login/check" When("로그인된 회원의 ID로 요청하면") { every { jwtHandler.getMemberIdFromToken(any()) } returns user.id!! every { memberRepository.findByIdOrNull(user.id!!) } returns user Then("회원의 이름을 응답한다") { runGetTest(endpoint) { statusCode(200) body("data.name", `is`(user.name)) } } } When("토큰은 있지만 회원을 찾을 수 없으면") { val invalidMemberId: Long = -1L every { jwtHandler.getMemberIdFromToken(any()) } returns invalidMemberId every { memberRepository.findByIdOrNull(invalidMemberId) } returns null Then("400 에러를 응답한다.") { runGetTest(endpoint) { statusCode(400) body("errorType", `is`(ErrorType.MEMBER_NOT_FOUND.name)) } } } } Given("로그아웃 요청을 보낼 때") { val endpoint: String = "/logout" When("로그인 상태가 아니라면") { setUpNotLoggedIn() Then("로그인 페이지로 이동한다.") { runPostTest(endpoint) { log().all() statusCode(302) header("Location", containsString("/login")) } } } When("로그인 상태라면") { setUpUser() every { memberRepository.findByIdOrNull(user.id!!) } returns user Then("토큰의 존재 여부와 무관하게 토큰을 만료시킨다.") { runPostTest(endpoint) { log().all() statusCode(200) cookie("accessToken", "") header("Set-Cookie", containsString("Max-Age=0")) } } } } } }