final merge dup-lazy-key
All checks were successful
gate/round2-candidate full make test 1016/1016 (7m43s, no retries), Opt build versionCode 68 signer ok
All checks were successful
gate/round2-candidate full make test 1016/1016 (7m43s, no retries), Opt build versionCode 68 signer ok
This commit is contained in:
commit
5fb37886bb
8 changed files with 148 additions and 10 deletions
|
|
@ -0,0 +1,103 @@
|
|||
package org.justinvisser.wolfskin.design
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.foundation.layout.requiredSize
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onAllNodesWithTag
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
/**
|
||||
* Lazy lists throw "Key ... was already used" in measure when two items share an id. Server lists can repeat one:
|
||||
* a Jellyfin person is credited once per role, so the title page crashed on a cast with the same person twice.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi")
|
||||
class DuplicateLazyKeysTest {
|
||||
@get:Rule val rule = createComposeRule()
|
||||
private val viewer = ShellPerson("justin", "Justin", "J", false)
|
||||
private fun shell(route: String) = ShellState(listOf(viewer), viewer.key).apply { pickerVisible = false; pickerLaunch = false; enterDestination(route) }
|
||||
private fun repeated(id: String, name: String = id) = TitleItem(id, name, "movie", held = true)
|
||||
|
||||
@Test fun repeatedKeysKeepTheFirstAndSuffixTheRest() {
|
||||
assertEquals(listOf("a", "b", "a#1", "a#2", "a#1#1"), listOf("a", "b", "a", "a", "a#1").uniqueKeys())
|
||||
assertEquals(listOf("a", "b"), listOf("a", "b").uniqueKeys())
|
||||
}
|
||||
|
||||
@Test fun castCreditedForTwoRolesComposes() {
|
||||
val state = TitleState(TitlePageData(repeated("film"), cast = listOf(
|
||||
TitlePerson("person", "Actor", "Hero"), TitlePerson("other", "Other", "Friend"), TitlePerson("person", "Actor", "Villain"))), viewer) {}
|
||||
rule.setContent { WolfskinTheme { TitleCast(state, active = false) } }
|
||||
rule.waitForIdle()
|
||||
assertEquals(2, rule.onAllNodesWithTag("title-cast-person").fetchSemanticsNodes().size)
|
||||
rule.onNodeWithTag("title-cast-other").assertExists()
|
||||
}
|
||||
|
||||
@Test fun relatedTitleListedTwiceComposes() {
|
||||
val state = TitleState(TitlePageData(repeated("film"), related = listOf(repeated("same"), repeated("other"), repeated("same"))), viewer) {}
|
||||
rule.setContent { WolfskinTheme { TitleMediaShelf(state, episodes = false, active = false) } }
|
||||
rule.waitForIdle()
|
||||
rule.onNodeWithTag("title-shelf:related").assertExists()
|
||||
}
|
||||
|
||||
@Test fun episodeListedTwiceComposes() {
|
||||
val series = TitleItem("series", "A series", "tv", seasons = 1, held = true)
|
||||
val episode = TitleItem("episode", "Pilot", "episode", held = true, season = 1, episode = 1)
|
||||
val state = TitleState(TitlePageData(series, playTarget = episode, episodes = listOf(episode, episode), connection = TitleConnection.SignedIn), viewer) {}
|
||||
rule.setContent { WolfskinTheme { TitleMediaShelf(state, episodes = true, active = false) } }
|
||||
rule.waitForIdle()
|
||||
rule.onNodeWithTag("title-shelf:episodes").assertExists()
|
||||
}
|
||||
|
||||
@Test fun repeatedSeasonNumberComposes() {
|
||||
val series = TitleItem("series", "A series", "tv", seasons = 2, held = true)
|
||||
val state = TitleState(TitlePageData(series, seasonNumbers = listOf(1, 1, 2)), viewer) {}
|
||||
rule.setContent { WolfskinTheme { TitleSurface(state, shell("title/series"), Modifier.requiredSize(960.dp, 540.dp)) } }
|
||||
rule.waitForIdle()
|
||||
rule.onNodeWithTag("title-shelf:episodes").assertDoesNotExist()
|
||||
assertTrue(state.rows.contains("seasons"))
|
||||
}
|
||||
|
||||
@Test fun filmographyWithARepeatedCreditComposes() {
|
||||
val state = PersonState(TitlePerson("person", "Actor"), List(WolfskinTokens.Behaviour.gridColumns.toInt() + 1) { repeated("credit") }, {})
|
||||
rule.setContent { WolfskinTheme { PersonSurface(state, shell("title/person"), Modifier.requiredSize(960.dp, 540.dp)) } }
|
||||
rule.waitForIdle()
|
||||
rule.onNodeWithTag("person-page").assertExists()
|
||||
}
|
||||
|
||||
@Test fun homeShelfWithARepeatedCardComposes() {
|
||||
val card = HomeTitle("episode", "Pilot", "episode")
|
||||
val snapshot = HomeSnapshot(listOf(HomeRow("cw", HomeRowKind.Shelf, "Continue watching", listOf(card, HomeTitle("other", "Other", "movie"), card), HomeCardKind.Wide)), HomeAvailability.Ready)
|
||||
val shell = shell("home")
|
||||
rule.setContent { WolfskinTheme { ShellSurface(shell) { modifier -> HomeScreen(shell, snapshot, modifier) {} } } }
|
||||
rule.waitForIdle()
|
||||
rule.onNodeWithTag("home-card:cw:0").assertExists()
|
||||
rule.onNodeWithTag("home-card:cw:2").assertExists()
|
||||
}
|
||||
|
||||
@Test fun libraryGridWithARepeatedTitleComposes() {
|
||||
val columns = WolfskinTokens.Behaviour.gridColumns.toInt()
|
||||
val titles = List(columns * 2) { LibraryTitle("same", "Same title", "movie") }
|
||||
val shell = shell("movies")
|
||||
val grid = LibraryGridState("Movies", titles)
|
||||
rule.setContent { WolfskinTheme { ShellSurface(shell) { modifier -> LibraryScreen(shell, grid, modifier) } } }
|
||||
rule.waitForIdle()
|
||||
rule.onNodeWithTag("library-grid").assertExists()
|
||||
}
|
||||
|
||||
@Test fun requestListedTwiceComposes() {
|
||||
val request = ComingInRequest("r1", "movie", 1, "A film", "justin", "Justin", null, null, ComingInStage.Waiting)
|
||||
val shell = shell("settings").apply { requests.update(ComingInSnapshot(listOf(request, request.copy(id = "r2"), request), ComingInStatus.Ready, signedIn = true)); openRequests() }
|
||||
rule.setContent { WolfskinTheme { ShellSurface(shell) } }
|
||||
rule.waitForIdle()
|
||||
rule.onNodeWithTag("wolfskin-shell").assertExists()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue