package roomescape.auth.web import com.ninjasquad.springmockk.SpykBean import io.mockk.every import org.hamcrest.Matchers.equalTo import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.data.repository.findByIdOrNull import org.springframework.test.web.servlet.MockMvc import roomescape.auth.exception.AuthErrorCode import roomescape.auth.service.AuthService import roomescape.common.exception.CommonErrorCode import roomescape.common.exception.ErrorCode import roomescape.util.MemberFixture import roomescape.util.RoomescapeApiTest @WebMvcTest(controllers = [AuthController::class]) class AuthControllerTest( val mockMvc: MockMvc ) : RoomescapeApiTest() { @SpykBean private lateinit var authService: AuthService val userRequest: LoginRequest = MemberFixture.userLoginRequest() init { Given("로그인 요청을 보낼 때") { val endpoint = "/login" When("로그인에 성공하면") { val expectedToken = "expectedToken" every { memberRepository.findByEmailAndPassword(userRequest.email, userRequest.password) } returns user every { jwtHandler.createToken(user.id!!) } returns expectedToken Then("토큰을 반환한다.") { runPostTest( mockMvc = mockMvc, endpoint = endpoint, body = userRequest, ) { status { isOk() } jsonPath("$.data.accessToken", equalTo(expectedToken)) } } } When("회원을 찾지 못하면") { every { memberRepository.findByEmailAndPassword(userRequest.email, userRequest.password) } returns null Then("에러 응답을 받는다.") { val expectedError = AuthErrorCode.LOGIN_FAILED runPostTest( mockMvc = mockMvc, endpoint = endpoint, body = userRequest, ) { status { isEqualTo(expectedError.httpStatus.value()) } jsonPath("$.code", equalTo(expectedError.errorCode)) } } } When("입력 값이 잘못되면") { val expectedErrorCode: ErrorCode = CommonErrorCode.INVALID_INPUT_VALUE Then("400 에러를 응답한다") { listOf( userRequest.copy(email = "invalid"), userRequest.copy(password = " "), "{\"email\": \"null\", \"password\": \"null\"}" ).forEach { runPostTest( mockMvc = mockMvc, endpoint = endpoint, body = it, ) { status { isEqualTo(expectedErrorCode.httpStatus.value()) } jsonPath("$.code", equalTo(expectedErrorCode.errorCode)) } } } } } Given("로그인 상태를 확인할 때") { val endpoint = "/login/check" When("로그인된 회원의 ID로 요청하면") { loginAsUser() Then("회원의 이름과 권한을 응답한다") { runGetTest( mockMvc = mockMvc, endpoint = endpoint, ) { status { isOk() } jsonPath("$.data.name", equalTo(user.name)) jsonPath("$.data.role", equalTo(user.role.name)) } } } When("토큰은 있지만 회원을 찾을 수 없으면") { val invalidMemberId: Long = -1L every { jwtHandler.getMemberIdFromToken(any()) } returns invalidMemberId every { memberRepository.findByIdOrNull(invalidMemberId) } returns null Then("에러 응답을 받는다.") { val expectedError = AuthErrorCode.UNIDENTIFIABLE_MEMBER runGetTest( mockMvc = mockMvc, endpoint = endpoint, ) { status { isEqualTo(expectedError.httpStatus.value()) } jsonPath("$.code", equalTo(expectedError.errorCode)) } } } } Given("로그아웃 요청을 보낼 때") { val endpoint = "/logout" When("토큰으로 memberId 조회가 가능하면") { every { jwtHandler.getMemberIdFromToken(any()) } returns 1L Then("정상 응답한다.") { runPostTest( mockMvc = mockMvc, endpoint = endpoint, ) { status { isNoContent() } } } } } } }