test(home): 장르 크리에이터 페이지 검증을 추가한다
This commit is contained in:
@@ -2,24 +2,32 @@ package kr.co.vividnext.sodalive.v2.main.home
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.GridLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import kr.co.vividnext.sodalive.R
|
||||
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.HomeRecommendationGenreCreatorGroupUiModel
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationGenreCreatorSection
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationLiveUiModel
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.visibleHomeGenreCreatorGroups
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeAiCharacterAdapter
|
||||
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.HomeGenreCreatorAdapter
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeLiveAdapter
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeRecentDebutCreatorAdapter
|
||||
import kr.co.vividnext.sodalive.v2.widget.AudioContentCardView
|
||||
@@ -35,6 +43,7 @@ import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.Shadows.shadowOf
|
||||
import org.robolectric.annotation.Config
|
||||
import java.util.Locale
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [28], application = Application::class)
|
||||
@@ -263,6 +272,219 @@ class HomeMainFragmentLayoutTest {
|
||||
assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, viewHolder.itemView.layoutParams.height)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `genre creator group item matches figma snapping card structure`() {
|
||||
val group = inflateViewWithParent(R.layout.item_home_genre_creator_group)
|
||||
val titleGenre = group.findViewById<TextView>(R.id.tv_home_genre_creator_group_title_genre)
|
||||
val titleSuffix = group.findViewById<TextView>(R.id.tv_home_genre_creator_group_title_suffix)
|
||||
val creatorGrid = group.findViewById<GridLayout>(R.id.gl_home_genre_creator_profiles)
|
||||
val followAllButton = group.findViewById<View>(R.id.view_home_genre_group_follow_all)
|
||||
|
||||
assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, group.layoutParams.width)
|
||||
assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, group.layoutParams.height)
|
||||
assertEquals(R.drawable.bg_home_genre_creator_group, shadowOf(group.background).createdFromResId)
|
||||
assertEquals(14.dpToPx(), group.paddingStart)
|
||||
assertEquals(14.dpToPx(), group.paddingTop)
|
||||
assertEquals(14.dpToPx(), group.paddingEnd)
|
||||
assertEquals(14.dpToPx(), group.paddingBottom)
|
||||
assertNotNull(titleGenre)
|
||||
assertNotNull(titleSuffix)
|
||||
assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, creatorGrid.layoutParams.width)
|
||||
assertEquals(4, creatorGrid.columnCount)
|
||||
assertEquals(2, creatorGrid.rowCount)
|
||||
assertNotNull(followAllButton)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `genre creator adapter sizes group card to parent width minus horizontal padding`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
val parent = RecyclerView(context)
|
||||
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
parent.layout(0, 0, 402.dpToPx(), 600.dpToPx())
|
||||
|
||||
val viewHolder = HomeGenreCreatorAdapter(onFollowAllClick = {}).onCreateViewHolder(parent, 0)
|
||||
|
||||
assertEquals(374.dpToPx(), viewHolder.itemView.layoutParams.width)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `genre creator adapter sizes profile cells to fit four columns in card grid`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
val parent = RecyclerView(context)
|
||||
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
parent.layout(0, 0, 360.dpToPx(), 600.dpToPx())
|
||||
val adapter = HomeGenreCreatorAdapter(onFollowAllClick = {})
|
||||
adapter.submitGroups(listOf(genreGroup("genre", genreCreators(1L))))
|
||||
val viewHolder = adapter.onCreateViewHolder(parent, 0)
|
||||
|
||||
adapter.onBindViewHolder(viewHolder, 0)
|
||||
|
||||
val creatorGrid = viewHolder.itemView.findViewById<GridLayout>(R.id.gl_home_genre_creator_profiles)
|
||||
val firstProfile = creatorGrid.getChildAt(0)
|
||||
val expectedCellSize = ((360 - 28 - 28 - 14 * 3) / 4).dpToPx()
|
||||
|
||||
assertEquals(expectedCellSize, firstProfile.layoutParams.width)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `genre creator adapter uses recycler width when group width is not resolved`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
val parent = RecyclerView(context)
|
||||
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
parent.layout(0, 0, 360.dpToPx(), 600.dpToPx())
|
||||
val adapter = HomeGenreCreatorAdapter(onFollowAllClick = {})
|
||||
adapter.submitGroups(listOf(genreGroup("genre", genreCreators(1L))))
|
||||
val viewHolder = adapter.onCreateViewHolder(parent, 0)
|
||||
viewHolder.itemView.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
|
||||
adapter.onBindViewHolder(viewHolder, 0)
|
||||
|
||||
val creatorGrid = viewHolder.itemView.findViewById<GridLayout>(R.id.gl_home_genre_creator_profiles)
|
||||
val firstProfile = creatorGrid.getChildAt(0)
|
||||
val expectedCellSize = ((360 - 28 - 28 - 14 * 3) / 4).dpToPx()
|
||||
|
||||
assertEquals(expectedCellSize, firstProfile.layoutParams.width)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `genre creator adapter caps measured group width to recycler content width`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
val parent = RecyclerView(context)
|
||||
parent.setPadding(14.dpToPx(), 0, 14.dpToPx(), 0)
|
||||
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
parent.layout(0, 0, 402.dpToPx(), 600.dpToPx())
|
||||
val adapter = HomeGenreCreatorAdapter(onFollowAllClick = {})
|
||||
adapter.submitGroups(listOf(genreGroup("genre", genreCreators(1L))))
|
||||
val viewHolder = adapter.onCreateViewHolder(parent, 0)
|
||||
viewHolder.itemView.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
viewHolder.itemView.layout(0, 0, 402.dpToPx(), 300.dpToPx())
|
||||
|
||||
adapter.onBindViewHolder(viewHolder, 0)
|
||||
|
||||
val creatorGrid = viewHolder.itemView.findViewById<GridLayout>(R.id.gl_home_genre_creator_profiles)
|
||||
val firstProfile = creatorGrid.getChildAt(0)
|
||||
val expectedCellSize = ((402 - 28 - 28 - 14 * 3) / 4).dpToPx()
|
||||
|
||||
assertEquals(expectedCellSize, firstProfile.layoutParams.width)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `genre creator adapter uses measured grid width for profile cells`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
val parent = RecyclerView(context)
|
||||
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
parent.layout(0, 0, 402.dpToPx(), 600.dpToPx())
|
||||
val adapter = HomeGenreCreatorAdapter(onFollowAllClick = {})
|
||||
adapter.submitGroups(listOf(genreGroup("genre", genreCreators(1L))))
|
||||
val viewHolder = adapter.onCreateViewHolder(parent, 0)
|
||||
val creatorGrid = viewHolder.itemView.findViewById<GridLayout>(R.id.gl_home_genre_creator_profiles)
|
||||
viewHolder.itemView.layout(0, 0, 374.dpToPx(), 300.dpToPx())
|
||||
creatorGrid.layout(0, 0, 300.dpToPx(), 200.dpToPx())
|
||||
|
||||
adapter.onBindViewHolder(viewHolder, 0)
|
||||
|
||||
val firstProfile = creatorGrid.getChildAt(0)
|
||||
val expectedCellSize = ((300 - 14 * 3) / 4).dpToPx()
|
||||
|
||||
assertEquals(expectedCellSize, firstProfile.layoutParams.width)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `genre creator suffix preserves leading spaces only for spaced languages`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
val englishContext = context.createConfigurationContext(
|
||||
Configuration(context.resources.configuration).apply { setLocale(Locale.ENGLISH) }
|
||||
)
|
||||
val japaneseContext = context.createConfigurationContext(
|
||||
Configuration(context.resources.configuration).apply { setLocale(Locale.JAPANESE) }
|
||||
)
|
||||
|
||||
assertEquals(true, context.getString(R.string.home_recommendation_section_genre_creator_suffix).startsWith(" "))
|
||||
assertEquals(true, englishContext.getString(R.string.home_recommendation_section_genre_creator_suffix).startsWith(" "))
|
||||
assertEquals(false, japaneseContext.getString(R.string.home_recommendation_section_genre_creator_suffix).startsWith(" "))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `genre creator profile item uses parent cell width and square image ratio`() {
|
||||
val profile = inflateViewWithParent(R.layout.item_home_genre_creator_profile)
|
||||
val profileImage = profile.findViewById<ImageView>(R.id.iv_home_genre_creator_profile)
|
||||
val nickname = profile.findViewById<TextView>(R.id.tv_home_genre_creator_profile_nickname)
|
||||
val imageLayoutParams = profileImage.layoutParams as ConstraintLayout.LayoutParams
|
||||
|
||||
assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, profile.layoutParams.width)
|
||||
assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, profile.layoutParams.height)
|
||||
assertEquals(0, imageLayoutParams.width)
|
||||
assertEquals(0, imageLayoutParams.height)
|
||||
assertEquals("1:1", imageLayoutParams.dimensionRatio)
|
||||
assertEquals(6.dpToPx(), (nickname.layoutParams as ViewGroup.MarginLayoutParams).topMargin)
|
||||
assertEquals(14f, nickname.textSize / nickname.resources.displayMetrics.scaledDensity)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `home genre creator section uses pager snapping list`() {
|
||||
val root = inflateView(R.layout.fragment_v2_main_home)
|
||||
val genreList = root.findViewById<RecyclerView>(R.id.rv_home_genre_creators)
|
||||
|
||||
assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, genreList.layoutParams.height)
|
||||
assertEquals(14.dpToPx(), genreList.paddingStart)
|
||||
assertEquals(14.dpToPx(), genreList.paddingEnd)
|
||||
assertNotNull(genreList.onFlingListener)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `genre creator adapter renders max five non empty genre groups`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
val parent = RecyclerView(context)
|
||||
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
val adapter = HomeGenreCreatorAdapter(onFollowAllClick = {})
|
||||
|
||||
adapter.submitGroups(
|
||||
listOf(
|
||||
genreGroup("empty", emptyList()),
|
||||
genreGroup("genre1", genreCreators(1L)),
|
||||
genreGroup("genre2", genreCreators(11L)),
|
||||
genreGroup("genre3", genreCreators(21L)),
|
||||
genreGroup("genre4", genreCreators(31L)),
|
||||
genreGroup("genre5", genreCreators(41L)),
|
||||
genreGroup("genre6", genreCreators(51L))
|
||||
)
|
||||
)
|
||||
val viewHolder = adapter.onCreateViewHolder(parent, 0)
|
||||
adapter.onBindViewHolder(viewHolder, 0)
|
||||
|
||||
assertEquals(5, adapter.itemCount)
|
||||
assertEquals("genre1", viewHolder.itemView.findViewById<TextView>(R.id.tv_home_genre_creator_group_title_genre).text)
|
||||
assertEquals(8, viewHolder.itemView.findViewById<GridLayout>(R.id.gl_home_genre_creator_profiles).childCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `genre creator adapter follow all uses ids from its page group`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
val parent = RecyclerView(context)
|
||||
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
val clickedCreatorIds = mutableListOf<Long>()
|
||||
val adapter = HomeGenreCreatorAdapter(onFollowAllClick = { clickedCreatorIds.addAll(it) })
|
||||
adapter.submitGroups(listOf(genreGroup("genre", genreCreators(10L))))
|
||||
val viewHolder = adapter.onCreateViewHolder(parent, 0)
|
||||
|
||||
adapter.onBindViewHolder(viewHolder, 0)
|
||||
viewHolder.itemView.findViewById<View>(R.id.view_home_genre_group_follow_all).performClick()
|
||||
|
||||
assertEquals((10L..17L).toList(), clickedCreatorIds)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `genre creator visible groups hide all empty groups before fragment visibility`() {
|
||||
val section = HomeRecommendationGenreCreatorSection(
|
||||
listOf(
|
||||
genreGroup("empty1", emptyList()),
|
||||
genreGroup("empty2", emptyList())
|
||||
)
|
||||
)
|
||||
|
||||
assertEquals(emptyList<HomeRecommendationGenreCreatorGroupUiModel>(), section.visibleHomeGenreCreatorGroups())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `first audio adapter clips thumbnail container`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
@@ -414,7 +636,7 @@ class HomeMainFragmentLayoutTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `home layout uses section title components and custom genre title row`() {
|
||||
fun `home layout uses section title components and genre title inside page card`() {
|
||||
val root = inflateView(R.layout.fragment_v2_main_home)
|
||||
val sectionTitleIds = listOf(
|
||||
R.id.view_home_recent_activity_title,
|
||||
@@ -437,9 +659,10 @@ class HomeMainFragmentLayoutTest {
|
||||
|
||||
assertNotNull(chevron)
|
||||
}
|
||||
assertNotNull(root.findViewById<LinearLayout>(R.id.ll_home_genre_creator_title))
|
||||
assertNotNull(root.findViewById<TextView>(R.id.tv_home_genre_creator_title_genre))
|
||||
assertNotNull(root.findViewById<TextView>(R.id.tv_home_genre_creator_title_suffix))
|
||||
val genreGroup = inflateView(R.layout.item_home_genre_creator_group)
|
||||
|
||||
assertNotNull(genreGroup.findViewById<TextView>(R.id.tv_home_genre_creator_group_title_genre))
|
||||
assertNotNull(genreGroup.findViewById<TextView>(R.id.tv_home_genre_creator_group_title_suffix))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -512,4 +735,21 @@ class HomeMainFragmentLayoutTest {
|
||||
tags = setOf(AudioContentTag.First, AudioContentTag.Point, AudioContentTag.Free)
|
||||
)
|
||||
}
|
||||
|
||||
private fun genreGroup(
|
||||
genre: String,
|
||||
creators: List<HomeRecommendationCreatorUiModel>
|
||||
): HomeRecommendationGenreCreatorGroupUiModel {
|
||||
return HomeRecommendationGenreCreatorGroupUiModel(genre, creators)
|
||||
}
|
||||
|
||||
private fun genreCreators(startId: Long): List<HomeRecommendationCreatorUiModel> {
|
||||
return (startId until startId + 8L).map { creatorId ->
|
||||
HomeRecommendationCreatorUiModel(
|
||||
creatorId = creatorId,
|
||||
nickname = "크리에이터$creatorId",
|
||||
profileImage = null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user