pricelees ef903cf267 [#22] 프론트엔드 React 전환 및 인증 API 수정 (#23)
<!-- 제목 양식 -->
<!-- [이슈번호] 작업 요약 (예시: [#10] Gitea 템플릿 생성) -->

## 📝 관련 이슈 및 PR

**PR과 관련된 이슈 번호**
- #22

##  작업 내용
<!-- 어떤 작업을 했는지 알려주세요! -->
- 기존 Thymeleaf 기반의 프론트엔드 코드를 React + Typescript 기반으로 마이그레이션
- 프론트엔드 분리에 따른 인증 API 수정 및 회원가입 API 추가

## 🧪 테스트
<!-- 어떤 테스트를 생각했고 진행했는지 알려주세요! -->
- 새로 추가된 API, 변경된 API 테스트 반영

## 📚 참고 자료 및 기타
<!-- 참고한 자료, 또는 논의할 사항이 있다면 알려주세요! -->
프론트엔드 코드는 Gemini CLI가 구현하였고, API 관련 코드(ee21782ef9, frontend/src/api/**) 만 직접 구성

Reviewed-on: #23
Co-authored-by: pricelees <priceelees@gmail.com>
Co-committed-by: pricelees <priceelees@gmail.com>
2025-07-27 03:39:20 +00:00

147 lines
5.2 KiB
Kotlin

package roomescape.member.controller
import io.kotest.assertions.assertSoftly
import io.kotest.matchers.collections.shouldContainAll
import io.kotest.matchers.shouldBe
import io.mockk.every
import io.mockk.mockk
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.test.web.servlet.MockMvc
import roomescape.auth.exception.AuthErrorCode
import roomescape.member.exception.MemberErrorCode
import roomescape.member.infrastructure.persistence.Role
import roomescape.member.web.MemberController
import roomescape.member.web.MemberRetrieveListResponse
import roomescape.member.web.SignupRequest
import roomescape.util.MemberFixture
import roomescape.util.RoomescapeApiTest
import kotlin.random.Random
@WebMvcTest(controllers = [MemberController::class])
class MemberControllerTest(
@Autowired private val mockMvc: MockMvc
) : RoomescapeApiTest() {
init {
given("GET /members 요청을") {
val endpoint = "/members"
every { memberRepository.findAll() } returns listOf(
MemberFixture.create(id = Random.nextLong(), name = "name1"),
MemberFixture.create(id = Random.nextLong(), name = "name2"),
MemberFixture.create(id = Random.nextLong(), name = "name3"),
)
`when`("관리자가 보내면") {
loginAsAdmin()
then("성공한다.") {
val result: String = runGetTest(
mockMvc = mockMvc,
endpoint = endpoint,
) {
status { isOk() }
}.andReturn().response.contentAsString
val response: MemberRetrieveListResponse = readValue(
responseJson = result,
valueType = MemberRetrieveListResponse::class.java
)
assertSoftly(response.members) {
it.size shouldBe 3
it.map { m -> m.name } shouldContainAll listOf("name1", "name2", "name3")
}
}
}
`when`("관리자가 아니면 에러 응답을 받는다.") {
then("비회원") {
doNotLogin()
val expectedError = AuthErrorCode.INVALID_TOKEN
runGetTest(
mockMvc = mockMvc,
endpoint = endpoint,
) {
status { isEqualTo(expectedError.httpStatus.value()) }
}.andExpect {
jsonPath("$.code") { value(expectedError.errorCode) }
}
}
then("일반 회원") {
loginAsUser()
val expectedError = AuthErrorCode.ACCESS_DENIED
runGetTest(
mockMvc = mockMvc,
endpoint = endpoint,
) {
status { isEqualTo(expectedError.httpStatus.value()) }
}.andExpect {
jsonPath("$.code") { value(expectedError.errorCode) }
}
}
}
}
given("POST /members") {
val endpoint = "/members"
val request = SignupRequest(
name = "name",
email = "email@email.com",
password = "password"
)
`when`("같은 이메일이 없으면") {
every {
memberRepository.findByEmail(request.email)
} returns null
every {
memberRepository.save(any())
} returns MemberFixture.create(
id = 1,
name = request.name,
account = request.email,
password = request.password,
role = Role.MEMBER
)
then("id과 이름을 담아 성공 응답") {
runPostTest(
mockMvc = mockMvc,
endpoint = endpoint,
body = request
) {
status { isCreated() }
jsonPath("$.data.name") { value(request.name) }
jsonPath("$.data.id") { value(1) }
}
}
}
`when`("같은 이메일이 있으면") {
every {
memberRepository.findByEmail(request.email)
} returns mockk()
then("에러 응답") {
val expectedError = MemberErrorCode.DUPLICATE_EMAIL
runPostTest(
mockMvc = mockMvc,
endpoint = endpoint,
body = request
) {
status { isEqualTo(expectedError.httpStatus.value()) }
jsonPath("$.code") { value(expectedError.errorCode) }
}
}
}
}
}
}