test(creator-channel): 댓글 답글 후속 계약을 검증한다
This commit is contained in:
@@ -29,7 +29,6 @@ class CreatorChannelCommunityDetailReplyUiContractTest {
|
||||
val reply = inflateView(R.layout.activity_creator_channel_community_reply)
|
||||
|
||||
assertNotNull(detail.findViewById<ImageButton>(R.id.btn_creator_channel_community_detail_back))
|
||||
assertNotNull(detail.findViewById<TextView>(R.id.tv_creator_channel_community_detail_title))
|
||||
assertNotNull(detail.findViewById<TextView>(R.id.tv_creator_channel_community_detail_comment_header))
|
||||
assertNotNull(detail.findViewById<RecyclerView>(R.id.rv_creator_channel_community_detail_comments))
|
||||
assertNotNull(detail.findViewById<View>(R.id.layout_creator_channel_community_detail_paywall))
|
||||
@@ -37,14 +36,17 @@ class CreatorChannelCommunityDetailReplyUiContractTest {
|
||||
assertNotNull(detail.findViewById<View>(R.id.layout_creator_channel_community_detail_input_bar))
|
||||
assertNotNull(detail.findViewById<EditText>(R.id.et_creator_channel_community_detail_comment))
|
||||
assertNotNull(detail.findViewById<ImageButton>(R.id.btn_creator_channel_community_detail_send))
|
||||
assertNotNull(detail.findViewById<ImageButton>(R.id.btn_creator_channel_community_detail_edit_cancel))
|
||||
assertRemovedId("tv_creator_channel_community_detail_title")
|
||||
assertRemovedId("tv_creator_channel_community_detail_comment_unavailable")
|
||||
|
||||
assertNotNull(reply.findViewById<ImageButton>(R.id.btn_creator_channel_community_reply_back))
|
||||
assertNotNull(reply.findViewById<TextView>(R.id.tv_creator_channel_community_reply_title))
|
||||
assertNotNull(reply.findViewById<RecyclerView>(R.id.rv_creator_channel_community_reply))
|
||||
assertNotNull(reply.findViewById<View>(R.id.layout_creator_channel_community_reply_input_bar))
|
||||
assertNotNull(reply.findViewById<EditText>(R.id.et_creator_channel_community_reply))
|
||||
assertNotNull(reply.findViewById<ImageButton>(R.id.btn_creator_channel_community_reply_send))
|
||||
assertNotNull(reply.findViewById<ImageButton>(R.id.btn_creator_channel_community_reply_edit_cancel))
|
||||
assertRemovedId("tv_creator_channel_community_reply_title")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -62,13 +64,23 @@ class CreatorChannelCommunityDetailReplyUiContractTest {
|
||||
assertRemovedId("iv_creator_channel_community_reply_item_heart")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `댓글 답글 더보기 popup layout은 regular font를 사용한다`() {
|
||||
val popup = inflateView(R.layout.view_creator_channel_community_more_popup)
|
||||
val popupLayout = projectFile("app/src/main/res/layout/view_creator_channel_community_more_popup.xml").readText()
|
||||
|
||||
assertNotNull(popup.findViewById<TextView>(R.id.tv_creator_channel_community_more_edit))
|
||||
assertNotNull(popup.findViewById<TextView>(R.id.tv_creator_channel_community_more_delete))
|
||||
assertTrue(popupLayout.contains("android:fontFamily=\"@font/regular\""))
|
||||
assertTrue(popupLayout.contains("@string/creator_channel_fantalk_edit"))
|
||||
assertTrue(popupLayout.contains("@string/creator_channel_fantalk_delete"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `커뮤니티 상세 답글 문자열은 한국어 영어 일본어에 존재한다`() {
|
||||
listOf("values", "values-en", "values-ja").forEach { valuesDir ->
|
||||
val strings = projectFile("app/src/main/res/$valuesDir/strings.xml").readText()
|
||||
|
||||
assertTrue(strings.contains("name=\"creator_channel_community_detail_title\""))
|
||||
assertTrue(strings.contains("name=\"creator_channel_community_reply_title\""))
|
||||
assertTrue(strings.contains("name=\"creator_channel_community_comment_placeholder\""))
|
||||
assertTrue(strings.contains("name=\"creator_channel_community_reply_placeholder\""))
|
||||
assertTrue(strings.contains("name=\"creator_channel_community_comment_header\""))
|
||||
@@ -89,6 +101,65 @@ class CreatorChannelCommunityDetailReplyUiContractTest {
|
||||
assertTrue(manifest.contains("android:windowSoftInputMode=\"stateAlwaysHidden|adjustResize\""))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `댓글 더보기 메뉴는 수정하기 삭제하기 문구를 사용한다`() {
|
||||
val ownerMenu = projectFile("app/src/main/res/menu/content_comment_option_menu.xml").readText()
|
||||
val creatorMenu = projectFile("app/src/main/res/menu/content_comment_option_menu2.xml").readText()
|
||||
|
||||
assertTrue(ownerMenu.contains("@string/creator_channel_fantalk_edit"))
|
||||
assertTrue(ownerMenu.contains("@string/creator_channel_fantalk_delete"))
|
||||
assertTrue(creatorMenu.contains("@string/creator_channel_fantalk_delete"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `상세와 답글 Activity는 수정 Dialog 대신 입력창 수정 모드와 V2ModalDialog 삭제 확인을 사용한다`() {
|
||||
val detailActivity = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/" +
|
||||
"CreatorChannelCommunityDetailActivity.kt"
|
||||
).readText()
|
||||
val replyActivity = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/reply/" +
|
||||
"CreatorChannelCommunityReplyActivity.kt"
|
||||
).readText()
|
||||
|
||||
assertTrue(detailActivity.contains("V2ModalDialog"))
|
||||
assertTrue(replyActivity.contains("V2ModalDialog"))
|
||||
assertTrue(detailActivity.contains("startCommentEdit"))
|
||||
assertTrue(replyActivity.contains("startReplyEdit"))
|
||||
assertTrue(replyActivity.contains("startParentCommentEdit"))
|
||||
assertTrue(detailActivity.contains("btnCreatorChannelCommunityDetailEditCancel"))
|
||||
assertTrue(replyActivity.contains("btnCreatorChannelCommunityReplyEditCancel"))
|
||||
assertTrue(detailActivity.contains("showSoftInput"))
|
||||
assertTrue(detailActivity.contains("hideSoftInputFromWindow"))
|
||||
assertTrue(replyActivity.contains("showSoftInput"))
|
||||
assertTrue(replyActivity.contains("hideSoftInputFromWindow"))
|
||||
assertTrue(replyActivity.contains("replyWrittenEventLiveData.observe"))
|
||||
assertTrue(!detailActivity.contains("AlertDialog"))
|
||||
assertTrue(!replyActivity.contains("AlertDialog"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `댓글 답글 Adapter는 PopupMenu 대신 regular font popup을 사용한다`() {
|
||||
val commentAdapter = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/ui/" +
|
||||
"CreatorChannelCommunityCommentAdapter.kt"
|
||||
).readText()
|
||||
val replyAdapter = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/reply/ui/" +
|
||||
"CreatorChannelCommunityReplyAdapter.kt"
|
||||
).readText()
|
||||
val morePopup = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/ui/" +
|
||||
"CreatorChannelCommunityMorePopup.kt"
|
||||
).readText()
|
||||
|
||||
assertTrue(commentAdapter.contains("CreatorChannelCommunityMorePopup"))
|
||||
assertTrue(replyAdapter.contains("CreatorChannelCommunityMorePopup"))
|
||||
assertTrue(!commentAdapter.contains("PopupMenu"))
|
||||
assertTrue(!replyAdapter.contains("PopupMenu"))
|
||||
assertTrue(morePopup.contains("ViewCreatorChannelCommunityMorePopupBinding"))
|
||||
}
|
||||
|
||||
private fun inflateView(layoutId: Int): View {
|
||||
val context = ApplicationProvider.getApplicationContext<Application>()
|
||||
return LayoutInflater.from(context).inflate(layoutId, null, false)
|
||||
|
||||
@@ -277,6 +277,65 @@ class CreatorChannelCommunityDetailViewModelTest {
|
||||
verify(legacyRepository, never()).modifyComment(any(), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `댓글 수정 선택은 하단 입력창 수정 모드로 전환하고 취소 시 입력을 비운다`() {
|
||||
stubDetail(detailResponse(isCommentAvailable = true))
|
||||
viewModel.loadDetail(POST_ID)
|
||||
|
||||
viewModel.startCommentEdit(COMMENT_ID, "기존 댓글")
|
||||
|
||||
val editingState = viewModel.detailStateLiveData.requireValue() as CreatorChannelCommunityDetailUiState.Content
|
||||
assertEquals("기존 댓글", editingState.commentInput)
|
||||
assertEquals(COMMENT_ID, editingState.editingCommentId)
|
||||
|
||||
viewModel.cancelCommentEdit()
|
||||
|
||||
val canceledState = viewModel.detailStateLiveData.requireValue() as CreatorChannelCommunityDetailUiState.Content
|
||||
assertEquals("", canceledState.commentInput)
|
||||
assertEquals(null, canceledState.editingCommentId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `댓글 수정 모드 send는 수정 API를 호출하고 성공 시 수정 모드를 해제한다`() {
|
||||
whenever(repository.getCommunityPostDetail(POST_ID, AUTH_TOKEN))
|
||||
.thenReturn(
|
||||
Single.just(ApiResponse(true, detailResponse(isCommentAvailable = true, commentIds = listOf(11L)), null)),
|
||||
Single.just(ApiResponse(true, detailResponse(isCommentAvailable = true, commentIds = listOf(12L)), null))
|
||||
)
|
||||
whenever(legacyRepository.modifyComment(any(), org.mockito.kotlin.eq(AUTH_TOKEN)))
|
||||
.thenReturn(Single.just(ApiResponse(true, Any(), null)))
|
||||
viewModel.loadDetail(POST_ID)
|
||||
|
||||
viewModel.startCommentEdit(COMMENT_ID, "기존 댓글")
|
||||
viewModel.updateCommentInput(" 수정 댓글 ")
|
||||
viewModel.submitComment()
|
||||
|
||||
val state = viewModel.detailStateLiveData.requireValue() as CreatorChannelCommunityDetailUiState.Content
|
||||
assertEquals("", state.commentInput)
|
||||
assertEquals(null, state.editingCommentId)
|
||||
assertEquals(listOf(12L), state.comments.map { it.commentId })
|
||||
verify(legacyRepository).modifyComment(
|
||||
argThat<ModifyCommentRequest> { commentId == COMMENT_ID && comment == "수정 댓글" && isActive == null },
|
||||
org.mockito.kotlin.eq(AUTH_TOKEN)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `댓글 수정 모드 send에서 내용이 같으면 변경 없음 toast를 노출하고 API를 호출하지 않는다`() {
|
||||
stubDetail(detailResponse(isCommentAvailable = true))
|
||||
viewModel.loadDetail(POST_ID)
|
||||
|
||||
viewModel.startCommentEdit(COMMENT_ID, "기존 댓글")
|
||||
viewModel.updateCommentInput(" 기존 댓글 ")
|
||||
viewModel.submitComment()
|
||||
|
||||
assertEquals(
|
||||
kr.co.vividnext.sodalive.R.string.audio_content_comment_no_change,
|
||||
viewModel.toastLiveData.requireValue()?.consume()?.resId
|
||||
)
|
||||
verify(legacyRepository, never()).modifyComment(any(), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `댓글 불가 게시물은 댓글 조회와 작성을 호출하지 않고 입력 숨김 상태를 노출한다`() {
|
||||
stubDetail(detailResponse(isCommentAvailable = false))
|
||||
|
||||
@@ -226,6 +226,72 @@ class CreatorChannelCommunityReplyViewModelTest {
|
||||
verify(legacyRepository, never()).modifyComment(any(), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `답글 수정 선택은 하단 입력창 수정 모드로 전환하고 취소 시 입력을 비운다`() {
|
||||
stubReplies(repliesResponse(ids = listOf(101L), hasNext = false))
|
||||
viewModel.loadReplies(POST_ID, parentComment())
|
||||
|
||||
viewModel.startReplyEdit(REPLY_ID, "기존 답글")
|
||||
|
||||
val editingState = viewModel.replyStateLiveData.requireValue() as CreatorChannelCommunityReplyUiState.Content
|
||||
assertEquals("기존 답글", editingState.replyInput)
|
||||
assertTrue(editingState.editingTarget != null)
|
||||
|
||||
viewModel.cancelReplyEdit()
|
||||
|
||||
val canceledState = viewModel.replyStateLiveData.requireValue() as CreatorChannelCommunityReplyUiState.Content
|
||||
assertEquals("", canceledState.replyInput)
|
||||
assertEquals(null, canceledState.editingTarget)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `답글 수정 모드 send는 수정 API를 호출하고 성공 시 수정 모드를 해제한다`() {
|
||||
whenever(
|
||||
repository.getCommunityCommentReplies(
|
||||
COMMENT_ID,
|
||||
0,
|
||||
CreatorChannelCommunityReplyViewModel.DEFAULT_PAGE_SIZE,
|
||||
AUTH_TOKEN
|
||||
)
|
||||
)
|
||||
.thenReturn(
|
||||
Single.just(ApiResponse(true, repliesResponse(ids = listOf(101L), hasNext = false), null)),
|
||||
Single.just(ApiResponse(true, repliesResponse(ids = listOf(102L), hasNext = false), null))
|
||||
)
|
||||
whenever(legacyRepository.modifyComment(any(), org.mockito.kotlin.eq(AUTH_TOKEN)))
|
||||
.thenReturn(Single.just(ApiResponse(true, Any(), null)))
|
||||
viewModel.loadReplies(POST_ID, parentComment())
|
||||
|
||||
viewModel.startReplyEdit(REPLY_ID, "기존 답글")
|
||||
viewModel.updateReplyInput(" 수정 답글 ")
|
||||
viewModel.submitReply()
|
||||
|
||||
val state = viewModel.replyStateLiveData.requireValue() as CreatorChannelCommunityReplyUiState.Content
|
||||
assertEquals("", state.replyInput)
|
||||
assertEquals(null, state.editingTarget)
|
||||
assertEquals(listOf(102L), state.replies.map { it.replyId })
|
||||
verify(legacyRepository).modifyComment(
|
||||
argThat<ModifyCommentRequest> { commentId == REPLY_ID && comment == "수정 답글" && isActive == null },
|
||||
org.mockito.kotlin.eq(AUTH_TOKEN)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `답글 수정 모드 send에서 내용이 같으면 변경 없음 toast를 노출하고 API를 호출하지 않는다`() {
|
||||
stubReplies(repliesResponse(ids = listOf(101L), hasNext = false))
|
||||
viewModel.loadReplies(POST_ID, parentComment())
|
||||
|
||||
viewModel.startReplyEdit(REPLY_ID, "기존 답글")
|
||||
viewModel.updateReplyInput(" 기존 답글 ")
|
||||
viewModel.submitReply()
|
||||
|
||||
assertEquals(
|
||||
kr.co.vividnext.sodalive.R.string.audio_content_comment_no_change,
|
||||
viewModel.toastLiveData.requireValue()?.consume()?.resId
|
||||
)
|
||||
verify(legacyRepository, never()).modifyComment(any(), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `답글 수정과 삭제는 legacy modifyComment를 호출하고 성공 시 답글을 새로고침한다`() {
|
||||
whenever(
|
||||
@@ -306,6 +372,28 @@ class CreatorChannelCommunityReplyViewModelTest {
|
||||
verify(legacyRepository, never()).modifyComment(any(), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `부모 댓글 수정 선택 후 send는 부모 댓글 수정 API를 호출하고 수정 모드를 해제한다`() {
|
||||
stubReplies(repliesResponse(ids = listOf(101L), hasNext = false))
|
||||
whenever(legacyRepository.modifyComment(any(), org.mockito.kotlin.eq(AUTH_TOKEN)))
|
||||
.thenReturn(Single.just(ApiResponse(true, Any(), null)))
|
||||
viewModel.loadReplies(POST_ID, parentComment())
|
||||
|
||||
viewModel.startParentCommentEdit("부모 댓글")
|
||||
viewModel.updateReplyInput(" 수정 부모 댓글 ")
|
||||
viewModel.submitReply()
|
||||
|
||||
val state = viewModel.replyStateLiveData.requireValue() as CreatorChannelCommunityReplyUiState.Content
|
||||
assertEquals("수정 부모 댓글", state.parentComment.comment)
|
||||
assertEquals("", state.replyInput)
|
||||
assertEquals(null, state.editingTarget)
|
||||
assertTrue(viewModel.parentCommentChangedEventLiveData.requireValue() == true)
|
||||
verify(legacyRepository).modifyComment(
|
||||
argThat<ModifyCommentRequest> { commentId == COMMENT_ID && comment == "수정 부모 댓글" && isActive == null },
|
||||
org.mockito.kotlin.eq(AUTH_TOKEN)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `부모 댓글 삭제는 legacy modifyComment를 호출하고 성공 시 삭제 이벤트만 노출한다`() {
|
||||
stubReplies(repliesResponse(ids = listOf(101L), hasNext = false))
|
||||
|
||||
Reference in New Issue
Block a user