feat(community): 게시물 상세 API 엔드포인트를 추가한다
This commit is contained in:
@@ -33,6 +33,53 @@ class CreatorChannelCommunityController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/community-posts/{postId}")
|
||||||
|
fun getCommunityPostDetail(
|
||||||
|
@PathVariable postId: Long,
|
||||||
|
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||||
|
) = run {
|
||||||
|
ApiResponse.ok(
|
||||||
|
creatorChannelCommunityFacade.getCommunityPostDetail(
|
||||||
|
postId = postId,
|
||||||
|
viewer = requireMember(member)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/community-posts/{postId}/comments")
|
||||||
|
fun getCommunityComments(
|
||||||
|
@PathVariable postId: Long,
|
||||||
|
@RequestParam(required = false) page: Int?,
|
||||||
|
@RequestParam(required = false) size: Int?,
|
||||||
|
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||||
|
) = run {
|
||||||
|
ApiResponse.ok(
|
||||||
|
creatorChannelCommunityFacade.getCommunityComments(
|
||||||
|
postId = postId,
|
||||||
|
viewer = requireMember(member),
|
||||||
|
page = page,
|
||||||
|
size = size
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/community-comments/{commentId}/replies")
|
||||||
|
fun getCommunityReplies(
|
||||||
|
@PathVariable commentId: Long,
|
||||||
|
@RequestParam(required = false) page: Int?,
|
||||||
|
@RequestParam(required = false) size: Int?,
|
||||||
|
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||||
|
) = run {
|
||||||
|
ApiResponse.ok(
|
||||||
|
creatorChannelCommunityFacade.getCommunityReplies(
|
||||||
|
commentId = commentId,
|
||||||
|
viewer = requireMember(member),
|
||||||
|
page = page,
|
||||||
|
size = size
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun requireMember(member: Member?): Member {
|
private fun requireMember(member: Member?): Member {
|
||||||
return member ?: throw SodaException(messageKey = "common.error.bad_credentials")
|
return member ?: throw SodaException(messageKey = "common.error.bad_credentials")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package kr.co.vividnext.sodalive.v2.api.creator.channel.community.application
|
package kr.co.vividnext.sodalive.v2.api.creator.channel.community.application
|
||||||
|
|
||||||
import kr.co.vividnext.sodalive.member.Member
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityCommentsResponse
|
||||||
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityPostDetailResponse
|
||||||
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityRepliesResponse
|
||||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityTabResponse
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityTabResponse
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.application.CreatorChannelCommunityQueryService
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.application.CreatorChannelCommunityQueryService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
@@ -29,4 +32,54 @@ class CreatorChannelCommunityFacade(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getCommunityPostDetail(
|
||||||
|
postId: Long,
|
||||||
|
viewer: Member,
|
||||||
|
now: LocalDateTime = LocalDateTime.now()
|
||||||
|
): CreatorChannelCommunityPostDetailResponse {
|
||||||
|
return CreatorChannelCommunityPostDetailResponse.from(
|
||||||
|
creatorChannelCommunityQueryService.getCommunityPostDetail(
|
||||||
|
postId = postId,
|
||||||
|
viewer = viewer,
|
||||||
|
now = now
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCommunityComments(
|
||||||
|
postId: Long,
|
||||||
|
viewer: Member,
|
||||||
|
page: Int?,
|
||||||
|
size: Int?,
|
||||||
|
now: LocalDateTime = LocalDateTime.now()
|
||||||
|
): CreatorChannelCommunityCommentsResponse {
|
||||||
|
return CreatorChannelCommunityCommentsResponse.from(
|
||||||
|
creatorChannelCommunityQueryService.getCommunityComments(
|
||||||
|
postId = postId,
|
||||||
|
viewer = viewer,
|
||||||
|
page = page,
|
||||||
|
size = size,
|
||||||
|
now = now
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCommunityReplies(
|
||||||
|
commentId: Long,
|
||||||
|
viewer: Member,
|
||||||
|
page: Int?,
|
||||||
|
size: Int?,
|
||||||
|
now: LocalDateTime = LocalDateTime.now()
|
||||||
|
): CreatorChannelCommunityRepliesResponse {
|
||||||
|
return CreatorChannelCommunityRepliesResponse.from(
|
||||||
|
creatorChannelCommunityQueryService.getCommunityReplies(
|
||||||
|
commentId = commentId,
|
||||||
|
viewer = viewer,
|
||||||
|
page = page,
|
||||||
|
size = size,
|
||||||
|
now = now
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,12 @@ import kr.co.vividnext.sodalive.member.Member
|
|||||||
import kr.co.vividnext.sodalive.member.MemberAdapter
|
import kr.co.vividnext.sodalive.member.MemberAdapter
|
||||||
import kr.co.vividnext.sodalive.member.MemberRole
|
import kr.co.vividnext.sodalive.member.MemberRole
|
||||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.application.CreatorChannelCommunityFacade
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.application.CreatorChannelCommunityFacade
|
||||||
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityCommentResponse
|
||||||
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityCommentsResponse
|
||||||
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityPostDetailResponse
|
||||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityPostResponse
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityPostResponse
|
||||||
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityRepliesResponse
|
||||||
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityReplyResponse
|
||||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityTabResponse
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityTabResponse
|
||||||
import org.junit.jupiter.api.DisplayName
|
import org.junit.jupiter.api.DisplayName
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
@@ -147,6 +152,147 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("커뮤니티 상세 조회는 비회원 요청을 거부한다")
|
||||||
|
fun shouldRejectAnonymousCommunityPostDetailRequest() {
|
||||||
|
mockMvc.perform(
|
||||||
|
get("/api/v2/creator-channels/community-posts/101")
|
||||||
|
.with(anonymous())
|
||||||
|
)
|
||||||
|
.andExpect(status().isUnauthorized)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("커뮤니티 상세 조회는 인증 회원에게 상세와 초기 댓글을 반환한다")
|
||||||
|
fun shouldReturnCommunityPostDetailForAuthenticatedMember() {
|
||||||
|
val viewer = createMember(id = 10L)
|
||||||
|
Mockito.doReturn(createDetailResponse()).`when`(facade).getCommunityPostDetail(
|
||||||
|
eqValue(101L),
|
||||||
|
eqValue(viewer),
|
||||||
|
anyValue(LocalDateTime.now())
|
||||||
|
)
|
||||||
|
|
||||||
|
mockMvc.perform(
|
||||||
|
get("/api/v2/creator-channels/community-posts/101")
|
||||||
|
.with(user(MemberAdapter(viewer)))
|
||||||
|
)
|
||||||
|
.andExpect(status().isOk)
|
||||||
|
.andExpect(jsonPath("$.data.postId").value(101))
|
||||||
|
.andExpect(jsonPath("$.data.isLiked").value(true))
|
||||||
|
.andExpect(jsonPath("$.data.comments.commentCount").value(1))
|
||||||
|
.andExpect(jsonPath("$.data.comments.comments[0].latestReply.commentId").value(202))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("커뮤니티 댓글 조회는 인증 회원에게 댓글 페이지를 반환한다")
|
||||||
|
fun shouldReturnCommunityCommentsForAuthenticatedMember() {
|
||||||
|
val viewer = createMember(id = 10L)
|
||||||
|
Mockito.doReturn(createCommentsResponse()).`when`(facade).getCommunityComments(
|
||||||
|
eqValue(101L),
|
||||||
|
eqValue(viewer),
|
||||||
|
eqValue(0),
|
||||||
|
eqValue(20),
|
||||||
|
anyValue(LocalDateTime.now())
|
||||||
|
)
|
||||||
|
|
||||||
|
mockMvc.perform(
|
||||||
|
get("/api/v2/creator-channels/community-posts/101/comments")
|
||||||
|
.param("page", "0")
|
||||||
|
.param("size", "20")
|
||||||
|
.with(user(MemberAdapter(viewer)))
|
||||||
|
)
|
||||||
|
.andExpect(status().isOk)
|
||||||
|
.andExpect(jsonPath("$.data.commentCount").value(1))
|
||||||
|
.andExpect(jsonPath("$.data.comments[0].latestReply.commentId").value(202))
|
||||||
|
.andExpect(jsonPath("$.data.hasNext").value(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("커뮤니티 댓글 조회는 raw page와 size를 facade에 전달한다")
|
||||||
|
fun shouldPassRawCommentPageAndSizeToFacade() {
|
||||||
|
val viewer = createMember(id = 10L)
|
||||||
|
Mockito.doReturn(createCommentsResponse(page = 0, size = 50)).`when`(facade).getCommunityComments(
|
||||||
|
eqValue(101L),
|
||||||
|
eqValue(viewer),
|
||||||
|
eqValue(-1),
|
||||||
|
eqValue(100),
|
||||||
|
anyValue(LocalDateTime.now())
|
||||||
|
)
|
||||||
|
|
||||||
|
mockMvc.perform(
|
||||||
|
get("/api/v2/creator-channels/community-posts/101/comments")
|
||||||
|
.param("page", "-1")
|
||||||
|
.param("size", "100")
|
||||||
|
.with(user(MemberAdapter(viewer)))
|
||||||
|
)
|
||||||
|
.andExpect(status().isOk)
|
||||||
|
.andExpect(jsonPath("$.data.page").value(0))
|
||||||
|
.andExpect(jsonPath("$.data.size").value(50))
|
||||||
|
|
||||||
|
Mockito.verify(facade).getCommunityComments(
|
||||||
|
eqValue(101L),
|
||||||
|
eqValue(viewer),
|
||||||
|
eqValue(-1),
|
||||||
|
eqValue(100),
|
||||||
|
anyValue(LocalDateTime.now())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("커뮤니티 답글 조회는 인증 회원에게 답글 페이지를 반환한다")
|
||||||
|
fun shouldReturnCommunityRepliesForAuthenticatedMember() {
|
||||||
|
val viewer = createMember(id = 10L)
|
||||||
|
Mockito.doReturn(createRepliesResponse()).`when`(facade).getCommunityReplies(
|
||||||
|
eqValue(201L),
|
||||||
|
eqValue(viewer),
|
||||||
|
eqValue(0),
|
||||||
|
eqValue(20),
|
||||||
|
anyValue(LocalDateTime.now())
|
||||||
|
)
|
||||||
|
|
||||||
|
mockMvc.perform(
|
||||||
|
get("/api/v2/creator-channels/community-comments/201/replies")
|
||||||
|
.param("page", "0")
|
||||||
|
.param("size", "20")
|
||||||
|
.with(user(MemberAdapter(viewer)))
|
||||||
|
)
|
||||||
|
.andExpect(status().isOk)
|
||||||
|
.andExpect(jsonPath("$.data.replyCount").value(1))
|
||||||
|
.andExpect(jsonPath("$.data.replies[0].commentId").value(202))
|
||||||
|
.andExpect(jsonPath("$.data.replies[0].latestReply").doesNotExist())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("커뮤니티 답글 조회는 raw page와 size를 facade에 전달한다")
|
||||||
|
fun shouldPassRawReplyPageAndSizeToFacade() {
|
||||||
|
val viewer = createMember(id = 10L)
|
||||||
|
Mockito.doReturn(createRepliesResponse(page = 0, size = 50)).`when`(facade).getCommunityReplies(
|
||||||
|
eqValue(201L),
|
||||||
|
eqValue(viewer),
|
||||||
|
eqValue(-1),
|
||||||
|
eqValue(100),
|
||||||
|
anyValue(LocalDateTime.now())
|
||||||
|
)
|
||||||
|
|
||||||
|
mockMvc.perform(
|
||||||
|
get("/api/v2/creator-channels/community-comments/201/replies")
|
||||||
|
.param("page", "-1")
|
||||||
|
.param("size", "100")
|
||||||
|
.with(user(MemberAdapter(viewer)))
|
||||||
|
)
|
||||||
|
.andExpect(status().isOk)
|
||||||
|
.andExpect(jsonPath("$.data.page").value(0))
|
||||||
|
.andExpect(jsonPath("$.data.size").value(50))
|
||||||
|
|
||||||
|
Mockito.verify(facade).getCommunityReplies(
|
||||||
|
eqValue(201L),
|
||||||
|
eqValue(viewer),
|
||||||
|
eqValue(-1),
|
||||||
|
eqValue(100),
|
||||||
|
anyValue(LocalDateTime.now())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun <T> eqValue(value: T): T {
|
private fun <T> eqValue(value: T): T {
|
||||||
return Mockito.eq(value) ?: value
|
return Mockito.eq(value) ?: value
|
||||||
}
|
}
|
||||||
@@ -194,4 +340,68 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
|||||||
hasNext = false
|
hasNext = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createDetailResponse(): CreatorChannelCommunityPostDetailResponse {
|
||||||
|
return CreatorChannelCommunityPostDetailResponse(
|
||||||
|
postId = 101L,
|
||||||
|
creatorId = 1L,
|
||||||
|
creatorNickname = "creator",
|
||||||
|
creatorProfileUrl = "https://cdn.test/profile.png",
|
||||||
|
createdAtUtc = "2026-06-21T03:30:00Z",
|
||||||
|
content = "content",
|
||||||
|
imageUrl = null,
|
||||||
|
audioUrl = null,
|
||||||
|
price = 100,
|
||||||
|
isCommentAvailable = true,
|
||||||
|
existOrdered = true,
|
||||||
|
likeCount = 7,
|
||||||
|
commentCount = 1,
|
||||||
|
isPinned = true,
|
||||||
|
isLiked = true,
|
||||||
|
comments = createCommentsResponse()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCommentsResponse(page: Int = 0, size: Int = 20): CreatorChannelCommunityCommentsResponse {
|
||||||
|
return CreatorChannelCommunityCommentsResponse(
|
||||||
|
commentCount = 1,
|
||||||
|
comments = listOf(
|
||||||
|
CreatorChannelCommunityCommentResponse(
|
||||||
|
commentId = 201L,
|
||||||
|
writerProfileImageUrl = "https://cdn.test/writer.png",
|
||||||
|
writerNickname = "writer",
|
||||||
|
content = "comment",
|
||||||
|
createdAtUtc = "2026-07-06T03:00:00Z",
|
||||||
|
latestReply = CreatorChannelCommunityReplyResponse(
|
||||||
|
commentId = 202L,
|
||||||
|
writerProfileImageUrl = "https://cdn.test/replier.png",
|
||||||
|
writerNickname = "replier",
|
||||||
|
content = "reply",
|
||||||
|
createdAtUtc = "2026-07-06T03:01:00Z"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
page = page,
|
||||||
|
size = size,
|
||||||
|
hasNext = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createRepliesResponse(page: Int = 0, size: Int = 20): CreatorChannelCommunityRepliesResponse {
|
||||||
|
return CreatorChannelCommunityRepliesResponse(
|
||||||
|
replyCount = 1,
|
||||||
|
replies = listOf(
|
||||||
|
CreatorChannelCommunityReplyResponse(
|
||||||
|
commentId = 202L,
|
||||||
|
writerProfileImageUrl = "https://cdn.test/replier.png",
|
||||||
|
writerNickname = "replier",
|
||||||
|
content = "reply",
|
||||||
|
createdAtUtc = "2026-07-06T03:01:00Z"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
page = page,
|
||||||
|
size = size,
|
||||||
|
hasNext = false
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,12 @@ import kr.co.vividnext.sodalive.member.Member
|
|||||||
import kr.co.vividnext.sodalive.member.MemberRole
|
import kr.co.vividnext.sodalive.member.MemberRole
|
||||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityTabResponse
|
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityTabResponse
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.application.CreatorChannelCommunityQueryService
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.application.CreatorChannelCommunityQueryService
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityComment
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityComments
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityPost
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityPost
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityPostDetail
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityReplies
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityReply
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityTab
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityTab
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.live.domain.CreatorChannelPage
|
import kr.co.vividnext.sodalive.v2.creator.channel.live.domain.CreatorChannelPage
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
@@ -87,6 +92,56 @@ class CreatorChannelCommunityFacadeTest {
|
|||||||
assertTrue(response.hasNext)
|
assertTrue(response.hasNext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("커뮤니티 상세 facade는 service 결과를 상세 응답 DTO로 변환한다")
|
||||||
|
fun shouldReturnCommunityPostDetailResponse() {
|
||||||
|
val service = Mockito.mock(CreatorChannelCommunityQueryService::class.java)
|
||||||
|
val facade = CreatorChannelCommunityFacade(service)
|
||||||
|
val viewer = createMember(id = 10L)
|
||||||
|
val now = LocalDateTime.of(2026, 7, 6, 12, 0)
|
||||||
|
Mockito.doReturn(createDetail()).`when`(service).getCommunityPostDetail(101L, viewer, now)
|
||||||
|
|
||||||
|
val response = facade.getCommunityPostDetail(101L, viewer, now)
|
||||||
|
|
||||||
|
assertEquals(101L, response.postId)
|
||||||
|
assertTrue(response.isLiked)
|
||||||
|
assertEquals(1, response.comments.commentCount)
|
||||||
|
assertEquals(201L, response.comments.comments.first().latestReply?.commentId)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("커뮤니티 댓글 facade는 raw page와 size를 service로 전달하고 응답 DTO로 변환한다")
|
||||||
|
fun shouldReturnCommunityCommentsResponse() {
|
||||||
|
val service = Mockito.mock(CreatorChannelCommunityQueryService::class.java)
|
||||||
|
val facade = CreatorChannelCommunityFacade(service)
|
||||||
|
val viewer = createMember(id = 10L)
|
||||||
|
val now = LocalDateTime.of(2026, 7, 6, 12, 0)
|
||||||
|
Mockito.doReturn(createComments()).`when`(service).getCommunityComments(101L, viewer, -1, 100, now)
|
||||||
|
|
||||||
|
val response = facade.getCommunityComments(101L, viewer, -1, 100, now)
|
||||||
|
|
||||||
|
assertEquals(1, response.commentCount)
|
||||||
|
assertEquals(0, response.page)
|
||||||
|
assertEquals(20, response.size)
|
||||||
|
assertEquals(201L, response.comments.first().latestReply?.commentId)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("커뮤니티 답글 facade는 raw page와 size를 service로 전달하고 응답 DTO로 변환한다")
|
||||||
|
fun shouldReturnCommunityRepliesResponse() {
|
||||||
|
val service = Mockito.mock(CreatorChannelCommunityQueryService::class.java)
|
||||||
|
val facade = CreatorChannelCommunityFacade(service)
|
||||||
|
val viewer = createMember(id = 10L)
|
||||||
|
val now = LocalDateTime.of(2026, 7, 6, 12, 0)
|
||||||
|
Mockito.doReturn(createReplies()).`when`(service).getCommunityReplies(201L, viewer, -1, 100, now)
|
||||||
|
|
||||||
|
val response = facade.getCommunityReplies(201L, viewer, -1, 100, now)
|
||||||
|
|
||||||
|
assertEquals(1, response.replyCount)
|
||||||
|
assertEquals(201L, response.replies.first().commentId)
|
||||||
|
assertTrue(response.hasNext)
|
||||||
|
}
|
||||||
|
|
||||||
private fun createMember(id: Long): Member {
|
private fun createMember(id: Long): Member {
|
||||||
return Member(
|
return Member(
|
||||||
email = "viewer$id@test.com",
|
email = "viewer$id@test.com",
|
||||||
@@ -139,4 +194,46 @@ class CreatorChannelCommunityFacadeTest {
|
|||||||
hasNext = true
|
hasNext = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createDetail(): CreatorChannelCommunityPostDetail {
|
||||||
|
return CreatorChannelCommunityPostDetail(
|
||||||
|
post = createTab().communityPosts.first(),
|
||||||
|
comments = createComments()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createComments(): CreatorChannelCommunityComments {
|
||||||
|
return CreatorChannelCommunityComments(
|
||||||
|
commentCount = 1,
|
||||||
|
comments = listOf(
|
||||||
|
CreatorChannelCommunityComment(
|
||||||
|
commentId = 200L,
|
||||||
|
writerProfileImageUrl = "https://cdn.test/writer.png",
|
||||||
|
writerNickname = "writer",
|
||||||
|
content = "comment",
|
||||||
|
createdAt = LocalDateTime.of(2026, 7, 6, 3, 0),
|
||||||
|
latestReply = createReplies().replies.first()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
page = CreatorChannelPage(page = 0, size = 20),
|
||||||
|
hasNext = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createReplies(): CreatorChannelCommunityReplies {
|
||||||
|
return CreatorChannelCommunityReplies(
|
||||||
|
replyCount = 1,
|
||||||
|
replies = listOf(
|
||||||
|
CreatorChannelCommunityReply(
|
||||||
|
commentId = 201L,
|
||||||
|
writerProfileImageUrl = "https://cdn.test/replier.png",
|
||||||
|
writerNickname = "replier",
|
||||||
|
content = "reply",
|
||||||
|
createdAt = LocalDateTime.of(2026, 7, 6, 3, 1)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
page = CreatorChannelPage(page = 0, size = 20),
|
||||||
|
hasNext = true
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user