[#44] 매장 기능 도입 #45

Merged
pricelees merged 116 commits from feat/#44 into main 2025-09-20 03:15:06 +00:00
6 changed files with 92 additions and 78 deletions
Showing only changes of commit b8cf1d6c9d - Show all commits

View File

@ -5,6 +5,7 @@ import io.restassured.module.kotlin.extensions.Given
import io.restassured.module.kotlin.extensions.When
import org.springframework.data.repository.findByIdOrNull
import org.springframework.http.MediaType
import roomescape.common.config.next
import roomescape.payment.business.PaymentWriter
import roomescape.payment.infrastructure.client.CardDetail
import roomescape.payment.infrastructure.client.EasyPayDetail
@ -25,12 +26,16 @@ import roomescape.schedule.infrastructure.persistence.ScheduleRepository
import roomescape.schedule.infrastructure.persistence.ScheduleStatus
import roomescape.schedule.web.ScheduleCreateRequest
import roomescape.schedule.web.ScheduleUpdateRequest
import roomescape.store.infrastructure.persistence.StoreEntity
import roomescape.store.infrastructure.persistence.StoreRepository
import roomescape.store.infrastructure.persistence.StoreStatus
import roomescape.theme.infrastructure.persistence.ThemeEntity
import roomescape.theme.infrastructure.persistence.ThemeRepository
import roomescape.theme.web.ThemeCreateRequest
import java.time.LocalDateTime
class DummyInitializer(
private val storeRepository: StoreRepository,
private val themeRepository: ThemeRepository,
private val scheduleRepository: ScheduleRepository,
private val reservationRepository: ReservationRepository,
@ -241,4 +246,19 @@ class DummyInitializer(
return reservationRepository.findByIdOrNull(createdReservationId)
?: throw RuntimeException("unexpected error occurred")
}
fun createStore(): StoreEntity {
return StoreEntity(
id = tsidFactory.next(),
name = "Hello 매장-${System.currentTimeMillis()}",
address = "강북구 행복로 123",
contact = randomPhoneNumber(),
businessRegNum = randomBusinessRegNum(),
regionCode = "1111000000",
status = StoreStatus.ACTIVE
).also {
storeRepository.save(it)
}
}
}

View File

@ -12,6 +12,7 @@ import roomescape.payment.web.PaymentConfirmRequest
import roomescape.reservation.web.PendingReservationCreateRequest
import roomescape.schedule.web.ScheduleCreateRequest
import roomescape.store.infrastructure.persistence.StoreEntity
import roomescape.store.infrastructure.persistence.StoreStatus
import roomescape.theme.infrastructure.persistence.Difficulty
import roomescape.theme.web.ThemeCreateRequest
import roomescape.user.infrastructure.persistence.UserEntity
@ -32,15 +33,17 @@ object StoreFixture {
name: String = "테스트-${randomString()}",
address: String = "서울특별시 강북구 행복길 123",
contact: String = randomPhoneNumber(),
businessRegNum: String = "123-45-67890",
regionCode: String = "1111000000"
businessRegNum: String = randomBusinessRegNum(),
regionCode: String = "1111000000",
status: StoreStatus = StoreStatus.ACTIVE
) = StoreEntity(
id = id,
name = name,
address = address,
contact = contact,
businessRegNum = businessRegNum,
regionCode = regionCode
regionCode = regionCode,
status = status
)
}

View File

@ -59,6 +59,7 @@ abstract class FunSpecSpringbootTest : FunSpec({
class TestConfig {
@Bean
fun dummyInitializer(
storeRepository: StoreRepository,
themeRepository: ThemeRepository,
scheduleRepository: ScheduleRepository,
reservationRepository: ReservationRepository,
@ -70,7 +71,8 @@ class TestConfig {
scheduleRepository = scheduleRepository,
reservationRepository = reservationRepository,
paymentWriter = paymentWriter,
paymentRepository = paymentRepository
paymentRepository = paymentRepository,
storeRepository = storeRepository
)
}
}

View File

@ -21,7 +21,7 @@ import roomescape.theme.infrastructure.persistence.ThemeEntity
import roomescape.theme.infrastructure.persistence.ThemeRepository
import roomescape.theme.web.ThemeUpdateRequest
class HQAdminThemeApiTest(
class AdminThemeApiTest(
private val themeRepository: ThemeRepository
) : FunSpecSpringbootTest() {
@ -236,6 +236,58 @@ class HQAdminThemeApiTest(
}
}
context("현재 active 상태인 모든 테마의 ID, 이름을 조회한다.") {
val endpoint = "/admin/themes/active"
context("권한이 없으면 접근할 수 없다.") {
test("비회원") {
runExceptionTest(
method = HttpMethod.GET,
requestBody = createRequest,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
)
}
test("회원") {
runExceptionTest(
token = testAuthUtil.defaultUserLogin(),
method = HttpMethod.GET,
requestBody = createRequest,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
)
}
}
test("정상 응답") {
val createdThemes = initialize("Active 상태 테마 2개 / Inactive 상태 테마 1개 생성") {
val token = testAuthUtil.defaultHqAdminLogin()
listOf(
dummyInitializer.createTheme(token, createRequest.copy(name = "test1", isActive = true)),
dummyInitializer.createTheme(token, createRequest.copy(name = "test2", isActive = false)),
dummyInitializer.createTheme(token, createRequest.copy(name = "test3", isActive = true))
)
}
runTest(
token = testAuthUtil.defaultStoreAdminLogin(),
on = {
get(endpoint)
},
expect = {
statusCode(200)
body("data.themes.size()", equalTo(createdThemes.filter { it.isActive }.size))
assertProperties(
props = setOf("id", "name"),
propsNameIfList = "themes"
)
},
)
}
}
context("테마 요약 목록을 조회한다.") {
val endpoint = "/admin/themes"
@ -361,14 +413,19 @@ class HQAdminThemeApiTest(
},
expect = {
statusCode(HttpStatus.OK.value())
body("data.id", equalTo(createdTheme.id))
body("data.theme.id", equalTo(createdTheme.id))
assertProperties(props = setOf("theme", "isActive", "audit"))
assertProperties(
props = setOf(
"id", "name", "description", "thumbnailUrl", "difficulty", "price", "isActive",
"id", "name", "description", "thumbnailUrl", "difficulty", "price",
"minParticipants", "maxParticipants",
"availableMinutes", "expectedMinutesFrom", "expectedMinutesTo",
"createdAt", "createdBy", "updatedAt", "updatedBy"
),
propsNameIfList = "theme"
)
assertProperties(
props = setOf("createdAt", "createdBy", "updatedAt", "updatedBy"),
propsNameIfList = "audit"
)
}
)

View File

@ -1,67 +0,0 @@
package roomescape.theme
import org.hamcrest.CoreMatchers.equalTo
import org.springframework.http.HttpMethod
import roomescape.auth.exception.AuthErrorCode
import roomescape.supports.FunSpecSpringbootTest
import roomescape.supports.ThemeFixture.createRequest
import roomescape.supports.assertProperties
import roomescape.supports.initialize
import roomescape.supports.runExceptionTest
import roomescape.supports.runTest
class StoreAdminThemeApiTest : FunSpecSpringbootTest() {
init {
context("현재 active 상태인 모든 테마의 ID, 이름을 조회한다.") {
val endpoint = "/admin/themes/active"
context("권한이 없으면 접근할 수 없다.") {
test("비회원") {
runExceptionTest(
method = HttpMethod.GET,
requestBody = createRequest,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
)
}
test("회원") {
runExceptionTest(
token = testAuthUtil.defaultUserLogin(),
method = HttpMethod.GET,
requestBody = createRequest,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
)
}
}
test("정상 응답") {
val createdThemes = initialize("Active 상태 테마 2개 / Inactive 상태 테마 1개 생성") {
val token = testAuthUtil.defaultHqAdminLogin()
listOf(
dummyInitializer.createTheme(token, createRequest.copy(name = "test1", isActive = true)),
dummyInitializer.createTheme(token, createRequest.copy(name = "test2", isActive = false)),
dummyInitializer.createTheme(token, createRequest.copy(name = "test3", isActive = true))
)
}
runTest(
token = testAuthUtil.defaultStoreAdminLogin(),
on = {
get(endpoint)
},
expect = {
statusCode(200)
body("data.themes.size()", equalTo(createdThemes.filter { it.isActive }.size))
assertProperties(
props = setOf("id", "name"),
propsNameIfList = "themes"
)
},
)
}
}
}
}

View File

@ -9,7 +9,7 @@ import roomescape.theme.exception.ThemeErrorCode
import roomescape.theme.infrastructure.persistence.ThemeEntity
import roomescape.theme.web.ThemeIdListRequest
class PublicThemeApiTest : FunSpecSpringbootTest() {
class ThemeApiTest : FunSpecSpringbootTest() {
init {
context("입력된 모든 ID에 대한 테마를 조회한다.") {
test("정상 응답 + 없는 테마가 있으면 생략한다.") {
@ -38,7 +38,6 @@ class PublicThemeApiTest : FunSpecSpringbootTest() {
}
}
context("ID로 테마 정보를 조회한다.") {
test("정상 응답") {
val createdTheme: ThemeEntity = initialize("조회를 위한 테마 생성") {