test(home): FIRST 오디오 홈 테스트를 정리한다

This commit is contained in:
2026-06-29 17:40:00 +09:00
parent ed2e478291
commit bc5814b7c5
3 changed files with 9 additions and 172 deletions

View File

@@ -35,14 +35,12 @@ import kr.co.vividnext.sodalive.v2.main.home.data.HomeActiveCreatorItem
import kr.co.vividnext.sodalive.v2.main.home.data.HomeAiCharacterItem import kr.co.vividnext.sodalive.v2.main.home.data.HomeAiCharacterItem
import kr.co.vividnext.sodalive.v2.main.home.data.HomeBannerItem import kr.co.vividnext.sodalive.v2.main.home.data.HomeBannerItem
import kr.co.vividnext.sodalive.v2.main.home.data.HomeCreatorItem import kr.co.vividnext.sodalive.v2.main.home.data.HomeCreatorItem
import kr.co.vividnext.sodalive.v2.main.home.data.HomeFirstAudioContentItem
import kr.co.vividnext.sodalive.v2.main.home.data.HomeGenreCreatorGroupItem import kr.co.vividnext.sodalive.v2.main.home.data.HomeGenreCreatorGroupItem
import kr.co.vividnext.sodalive.v2.main.home.data.HomeLiveItem import kr.co.vividnext.sodalive.v2.main.home.data.HomeLiveItem
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationBannerSection import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationBannerSection
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationBannerRoute import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationBannerRoute
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationBannerUiModel import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationBannerUiModel
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationAiCharacterRoute import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationAiCharacterRoute
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationFirstAudioContentUiModel
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationCreatorUiModel import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationCreatorUiModel
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationGenreCreatorGroupUiModel import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationGenreCreatorGroupUiModel
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationGenreCreatorSection import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationGenreCreatorSection
@@ -66,7 +64,6 @@ import kr.co.vividnext.sodalive.v2.main.home.ui.HomeAiCharacterAdapter
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeBannerBinder import kr.co.vividnext.sodalive.v2.main.home.ui.HomeBannerBinder
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeBusinessInfoBinder import kr.co.vividnext.sodalive.v2.main.home.ui.HomeBusinessInfoBinder
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeCheerCreatorAdapter import kr.co.vividnext.sodalive.v2.main.home.ui.HomeCheerCreatorAdapter
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFirstAudioAdapter
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFollowAllButtonBinder import kr.co.vividnext.sodalive.v2.main.home.ui.HomeFollowAllButtonBinder
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeGenreCreatorAdapter import kr.co.vividnext.sodalive.v2.main.home.ui.HomeGenreCreatorAdapter
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeLiveAdapter import kr.co.vividnext.sodalive.v2.main.home.ui.HomeLiveAdapter
@@ -74,7 +71,6 @@ import kr.co.vividnext.sodalive.v2.main.home.ui.HomePopularCommunityAdapter
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeRecentDebutCreatorAdapter import kr.co.vividnext.sodalive.v2.main.home.ui.HomeRecentDebutCreatorAdapter
import kr.co.vividnext.sodalive.v2.main.home.ui.homeCreatorProfileImageTransformations import kr.co.vividnext.sodalive.v2.main.home.ui.homeCreatorProfileImageTransformations
import kr.co.vividnext.sodalive.v2.widget.AudioContentCardView import kr.co.vividnext.sodalive.v2.widget.AudioContentCardView
import kr.co.vividnext.sodalive.v2.widget.AudioContentTag
import kr.co.vividnext.sodalive.v2.widget.TextTabBarView import kr.co.vividnext.sodalive.v2.widget.TextTabBarView
import kr.co.vividnext.sodalive.v2.widget.banner.BannerView import kr.co.vividnext.sodalive.v2.widget.banner.BannerView
import kr.co.vividnext.sodalive.v2.widget.feed.FeedItem import kr.co.vividnext.sodalive.v2.widget.feed.FeedItem
@@ -122,7 +118,6 @@ class HomeMainFragmentLayoutTest {
R.id.ll_home_banner_section, R.id.ll_home_banner_section,
R.id.ll_home_recent_activity_section, R.id.ll_home_recent_activity_section,
R.id.ll_home_recent_debut_section, R.id.ll_home_recent_debut_section,
R.id.ll_home_first_audio_section,
R.id.ll_home_ai_character_section, R.id.ll_home_ai_character_section,
R.id.ll_home_genre_creator_section, R.id.ll_home_genre_creator_section,
R.id.ll_home_cheer_creator_section, R.id.ll_home_cheer_creator_section,
@@ -132,7 +127,6 @@ class HomeMainFragmentLayoutTest {
R.id.rv_home_lives, R.id.rv_home_lives,
R.id.rv_home_recent_activity_creators, R.id.rv_home_recent_activity_creators,
R.id.rv_home_recent_debut_creators, R.id.rv_home_recent_debut_creators,
R.id.rv_home_first_audio_contents,
R.id.rv_home_ai_characters, R.id.rv_home_ai_characters,
R.id.rv_home_genre_creators, R.id.rv_home_genre_creators,
R.id.rv_home_cheer_creators R.id.rv_home_cheer_creators
@@ -256,39 +250,6 @@ class HomeMainFragmentLayoutTest {
assertNotNull(viewHolder.itemView.outlineProvider) assertNotNull(viewHolder.itemView.outlineProvider)
} }
@Test
fun `first audio item matches figma card dimensions`() {
val firstAudio = inflateViewWithParent(R.layout.item_home_first_audio_content)
val thumbnailContainer = firstAudio.findViewById<View>(R.id.fl_home_first_audio_thumbnail_container)
val thumbnail = firstAudio.findViewById<ImageView>(R.id.iv_home_first_audio_thumbnail)
val creatorProfile = firstAudio.findViewById<ImageView>(R.id.iv_home_first_audio_creator_profile)
val creatorName = firstAudio.findViewById<TextView>(R.id.tv_home_first_audio_creator_nickname)
assertEquals(185.dpToPx(), firstAudio.layoutParams.width)
assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, firstAudio.layoutParams.height)
assertEquals(185.dpToPx(), thumbnail.layoutParams.width)
assertEquals(185.dpToPx(), thumbnail.layoutParams.height)
assertNotNull(thumbnailContainer)
assertEquals(42.dpToPx(), creatorProfile.layoutParams.width)
assertEquals(42.dpToPx(), creatorProfile.layoutParams.height)
assertEquals(14f, creatorName.textSize / creatorName.resources.displayMetrics.scaledDensity)
}
@Test
fun `home first audio section matches figma list spacing`() {
val root = inflateView(R.layout.fragment_v2_main_home)
val firstAudioList = root.findViewById<RecyclerView>(R.id.rv_home_first_audio_contents)
val context = ApplicationProvider.getApplicationContext<Context>()
val parent = RecyclerView(context)
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
val viewHolder = HomeFirstAudioAdapter().onCreateViewHolder(parent, 0)
val layoutParams = viewHolder.itemView.layoutParams as ViewGroup.MarginLayoutParams
assertEquals(14.dpToPx(), firstAudioList.paddingStart)
assertEquals(14.dpToPx(), (firstAudioList.layoutParams as ViewGroup.MarginLayoutParams).topMargin)
assertEquals(4.dpToPx(), layoutParams.marginEnd)
}
@Test @Test
fun `character chat thumbnail preserves figma root dimensions`() { fun `character chat thumbnail preserves figma root dimensions`() {
val thumbnail = inflateViewWithParent(R.layout.view_character_chat_thumbnail) val thumbnail = inflateViewWithParent(R.layout.view_character_chat_thumbnail)
@@ -614,55 +575,6 @@ class HomeMainFragmentLayoutTest {
assertEquals(emptyList<HomeRecommendationGenreCreatorGroupUiModel>(), section.visibleHomeGenreCreatorGroups()) assertEquals(emptyList<HomeRecommendationGenreCreatorGroupUiModel>(), section.visibleHomeGenreCreatorGroups())
} }
@Test
fun `first audio adapter clips thumbnail container`() {
val context = ApplicationProvider.getApplicationContext<Context>()
val parent = RecyclerView(context)
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
val viewHolder = HomeFirstAudioAdapter().onCreateViewHolder(parent, 0)
val thumbnailContainer = viewHolder.itemView.findViewById<View>(R.id.fl_home_first_audio_thumbnail_container)
assertEquals(true, thumbnailContainer.clipToOutline)
assertNotNull(thumbnailContainer.outlineProvider)
}
@Test
fun `first audio adapter binds tag visibility`() {
val context = ApplicationProvider.getApplicationContext<Context>()
val parent = RecyclerView(context)
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
val adapter = HomeFirstAudioAdapter()
adapter.submitItems(listOf(firstAudioItem()))
val viewHolder = adapter.onCreateViewHolder(parent, 0)
adapter.onBindViewHolder(viewHolder, 0)
assertEquals(View.VISIBLE, viewHolder.itemView.findViewById<View>(R.id.ll_home_first_audio_tag_top).visibility)
assertEquals(View.VISIBLE, viewHolder.itemView.findViewById<View>(R.id.ll_home_first_audio_tag_bottom).visibility)
assertEquals(View.VISIBLE, viewHolder.itemView.findViewById<View>(R.id.ll_home_first_audio_tag_first).visibility)
assertEquals(View.VISIBLE, viewHolder.itemView.findViewById<View>(R.id.iv_home_first_audio_tag_point).visibility)
assertEquals(View.VISIBLE, viewHolder.itemView.findViewById<View>(R.id.tv_home_first_audio_tag_free).visibility)
}
@Test
fun `first audio adapter clears nullable images`() {
val context = ApplicationProvider.getApplicationContext<Context>()
val parent = RecyclerView(context)
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
val adapter = HomeFirstAudioAdapter()
adapter.submitItems(listOf(firstAudioItem()))
val viewHolder = adapter.onCreateViewHolder(parent, 0)
val thumbnail = viewHolder.itemView.findViewById<ImageView>(R.id.iv_home_first_audio_thumbnail)
val creatorProfile = viewHolder.itemView.findViewById<ImageView>(R.id.iv_home_first_audio_creator_profile)
thumbnail.setImageResource(R.drawable.ic_launcher_background)
creatorProfile.setImageResource(R.drawable.ic_launcher_background)
adapter.onBindViewHolder(viewHolder, 0)
assertEquals(null, thumbnail.drawable)
assertEquals(null, creatorProfile.drawable)
}
@Test @Test
fun `audio content card clips image area and overlay tags together`() { fun `audio content card clips image area and overlay tags together`() {
val card = inflateView(R.layout.view_audio_content_card) as AudioContentCardView val card = inflateView(R.layout.view_audio_content_card) as AudioContentCardView
@@ -672,40 +584,6 @@ class HomeMainFragmentLayoutTest {
assertNotNull(thumbnailContainer.outlineProvider) assertNotNull(thumbnailContainer.outlineProvider)
} }
@Test
fun `audio content card tag attributes match first audio item`() {
val card = inflateView(R.layout.view_audio_content_card) as AudioContentCardView
val firstAudio = inflateView(R.layout.item_home_first_audio_content)
card.setTags(setOf(AudioContentTag.Original, AudioContentTag.First, AudioContentTag.Point, AudioContentTag.Free))
val topTagContainer = card.findViewById<LinearLayout>(R.id.ll_audio_content_tag_top)
val bottomTagContainer = card.findViewById<LinearLayout>(R.id.ll_audio_content_tag_bottom)
val expectedFirstTag = firstAudio.findViewById<LinearLayout>(R.id.ll_home_first_audio_tag_first)
val expectedFreeTag = firstAudio.findViewById<TextView>(R.id.tv_home_first_audio_tag_free)
val originalTag = card.findViewById<ImageView>(R.id.iv_audio_content_tag_original)
val firstTag = card.findViewById<LinearLayout>(R.id.ll_audio_content_tag_first)
val firstIcon = firstTag.getChildAt(0) as ImageView
val firstText = firstTag.getChildAt(1) as TextView
val pointTag = card.findViewById<ImageView>(R.id.iv_audio_content_tag_point)
val freeTag = card.findViewById<TextView>(R.id.tv_audio_content_tag_free)
assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, topTagContainer.layoutParams.height)
assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, bottomTagContainer.layoutParams.height)
assertEquals(24.dpToPx(), originalTag.layoutParams.width)
assertEquals(24.dpToPx(), originalTag.layoutParams.height)
assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, firstTag.layoutParams.width)
assertEquals(expectedFirstTag.layoutParams.height, firstTag.layoutParams.height)
assertEquals(expectedFirstTag.paddingStart, firstTag.paddingStart)
assertEquals(expectedFirstTag.paddingTop, firstTag.paddingTop)
assertEquals(17.dpToPx(), firstIcon.layoutParams.width)
assertEquals(17.dpToPx(), firstIcon.layoutParams.height)
assertEquals(2.dpToPx(), (firstText.layoutParams as ViewGroup.MarginLayoutParams).marginStart)
assertEquals(true, firstText.includeFontPadding)
assertEquals(24.dpToPx(), pointTag.layoutParams.width)
assertEquals(24.dpToPx(), pointTag.layoutParams.height)
assertEquals(expectedFreeTag.layoutParams.height, freeTag.layoutParams.height)
assertEquals(expectedFreeTag.paddingStart, freeTag.paddingStart)
}
@Test @Test
fun `home ranking layout contains ranking list below text tab bar`() { fun `home ranking layout contains ranking list below text tab bar`() {
val root = inflateView(R.layout.fragment_v2_main_home) val root = inflateView(R.layout.fragment_v2_main_home)
@@ -861,16 +739,6 @@ class HomeMainFragmentLayoutTest {
creatorNickname = "추천 크리에이터", creatorNickname = "추천 크리에이터",
creatorProfileImage = "https://example.com/creator.png" creatorProfileImage = "https://example.com/creator.png"
).toUiModel() ).toUiModel()
val firstAudio = HomeFirstAudioContentItem(
contentId = 70L,
creatorId = 80L,
creatorNickname = "오디오 크리에이터",
creatorProfileImage = "https://example.com/audio-creator.png",
title = "첫 오디오",
price = 0,
coverImage = "https://example.com/cover.png",
isPointAvailable = true
).toUiModel()
val genreGroup = HomeGenreCreatorGroupItem( val genreGroup = HomeGenreCreatorGroupItem(
genreName = "로맨스", genreName = "로맨스",
creators = listOf( creators = listOf(
@@ -895,8 +763,6 @@ class HomeMainFragmentLayoutTest {
assertEquals(50L, activeCreator.targetId) assertEquals(50L, activeCreator.targetId)
assertEquals("추천 크리에이터", creator.nickname) assertEquals("추천 크리에이터", creator.nickname)
assertEquals("https://example.com/creator.png", creator.profileImage) assertEquals("https://example.com/creator.png", creator.profileImage)
assertEquals("https://example.com/audio-creator.png", firstAudio.creatorProfileImage)
assertEquals(setOf(AudioContentTag.First, AudioContentTag.Point, AudioContentTag.Free), firstAudio.tags)
assertEquals("로맨스", genreGroup.genre) assertEquals("로맨스", genreGroup.genre)
assertEquals("장르 크리에이터", genreGroup.creators.first().nickname) assertEquals("장르 크리에이터", genreGroup.creators.first().nickname)
} }
@@ -1199,14 +1065,12 @@ class HomeMainFragmentLayoutTest {
val sectionTitleIds = listOf( val sectionTitleIds = listOf(
R.id.view_home_recent_activity_title, R.id.view_home_recent_activity_title,
R.id.view_home_recent_debut_title, R.id.view_home_recent_debut_title,
R.id.view_home_first_audio_title,
R.id.view_home_ai_character_title, R.id.view_home_ai_character_title,
R.id.view_home_cheer_creator_title, R.id.view_home_cheer_creator_title,
R.id.view_home_popular_community_title R.id.view_home_popular_community_title
) )
val moreTitleIds = listOf( val moreTitleIds = listOf(
R.id.view_home_recent_debut_title, R.id.view_home_recent_debut_title,
R.id.view_home_first_audio_title,
R.id.view_home_ai_character_title R.id.view_home_ai_character_title
) )
@@ -1497,19 +1361,6 @@ class HomeMainFragmentLayoutTest {
) )
} }
private fun firstAudioItem(): HomeRecommendationFirstAudioContentUiModel {
return HomeRecommendationFirstAudioContentUiModel(
contentId = 1L,
creatorId = 1L,
creatorNickname = "크리에이터 이름",
creatorProfileImage = "",
title = "콘텐츠 제목",
price = 0,
coverImage = null,
tags = setOf(AudioContentTag.First, AudioContentTag.Point, AudioContentTag.Free)
)
}
private fun homeBanner( private fun homeBanner(
creatorId: Long? = null, creatorId: Long? = null,
seriesId: Long? = null, seriesId: Long? = null,

View File

@@ -23,7 +23,6 @@ class HomeMainFragmentLoginGuardSourceTest {
) )
assertGuardedStartActivity(source, "private fun onAiCharacterClick(item: HomeRecommendationAiCharacterUiModel)") assertGuardedStartActivity(source, "private fun onAiCharacterClick(item: HomeRecommendationAiCharacterUiModel)")
assertGuardedStartActivity(source, "private fun openCreatorProfile(creatorId: Long)") assertGuardedStartActivity(source, "private fun openCreatorProfile(creatorId: Long)")
assertGuardedStartActivity(source, "private fun openAudioContentDetail(item: HomeRecommendationFirstAudioContentUiModel)")
assertGuardedStartActivity(source, "private fun openPopularCommunityPost(item: FeedItem.Community)") assertGuardedStartActivity(source, "private fun openPopularCommunityPost(item: FeedItem.Community)")
} }

View File

@@ -1,6 +1,7 @@
package kr.co.vividnext.sodalive.v2.main.home package kr.co.vividnext.sodalive.v2.main.home
import android.app.Application import android.app.Application
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@@ -13,32 +14,18 @@ import java.io.File
class HomeMainFragmentSourceTest { class HomeMainFragmentSourceTest {
@Test @Test
fun `홈 FIRST 오디오 섹션 타이틀 chevron은 신규 전체보기로 이동한다`() { fun `홈 추천 탭에서 처음부터 함께 성장 섹션 코드는 제거되어 있다`() {
val source = projectFile( val source = projectFile(
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt" "app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/HomeMainFragment.kt"
).readText() ).readText()
assertTrue(source.contains("binding.viewHomeFirstAudioTitle.setTitle(")) assertFalse(source.contains("HomeFirstAudioAdapter"))
assertTrue( assertFalse(source.contains("HomeRecommendationFirstAudioContent"))
"FIRST audio title must show the section chevron in Phase 2.", assertFalse(source.contains("firstAudio"))
source.contains( assertFalse(source.contains("FirstAudio"))
"binding.viewHomeFirstAudioTitle.setTitle(\n" + assertFalse(source.contains("rvHomeFirstAudioContents"))
" R.string.home_recommendation_section_first_audio_contents,\n" + assertFalse(source.contains("viewHomeFirstAudioTitle"))
" showMore = true" assertFalse(source.contains("ContentOverviewType.FIRST_AUDIO_CONTENT"))
)
)
assertTrue(source.contains("import kr.co.vividnext.sodalive.v2.main.content.overview.ContentOverviewActivity"))
assertTrue(source.contains("import kr.co.vividnext.sodalive.v2.main.content.overview.data.ContentOverviewType"))
assertTrue(source.contains("binding.viewHomeFirstAudioTitle.ivSectionTitleChevron.setOnClickListener"))
val functionSource = source.substringFrom("private fun openFirstAudioOverview()")
assertTrue(functionSource.contains("ensureMainV2NavigationAllowed"))
assertTrue(functionSource.contains("startActivity("))
assertTrue(functionSource.contains("ContentOverviewActivity.newIntent(requireContext(),"))
assertTrue(functionSource.contains("ContentOverviewType.FIRST_AUDIO_CONTENT"))
assertTrue(
functionSource.indexOf("ensureMainV2NavigationAllowed") <
functionSource.indexOf("startActivity(")
)
} }
private fun String.substringFrom(marker: String): String { private fun String.substringFrom(marker: String): String {