Cover outgoing title and person Back ownership
This commit is contained in:
parent
c5dbe91076
commit
a27e922675
1 changed files with 107 additions and 0 deletions
|
|
@ -0,0 +1,107 @@
|
|||
package org.justinvisser.wolfskin.tv
|
||||
|
||||
import android.app.Application
|
||||
import android.os.Looper
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.snapshots.Snapshot
|
||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.github.damontecres.wholphin.data.ServerRepository
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.services.NavigationManager
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.mockk
|
||||
import java.util.UUID
|
||||
import kotlinx.coroutines.cancel
|
||||
import org.junit.After
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.justinvisser.wolfskin.conductarr.MemoryCacheStore
|
||||
import org.justinvisser.wolfskin.design.*
|
||||
import org.justinvisser.wolfskin.tv.read.PersonRead
|
||||
import org.justinvisser.wolfskin.tv.read.TitleReadFacade
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.Shadows
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
/** A loaded outgoing destination remains composed after pop but cannot consume the incoming Home Back. */
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi")
|
||||
class TitleEntryBackTest {
|
||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
private lateinit var viewModel: WolfskinTitleViewModel
|
||||
private lateinit var conductarr: ConductarrSession
|
||||
|
||||
@After fun dispose() {
|
||||
if (::viewModel.isInitialized) viewModel.viewModelScope.cancel()
|
||||
if (::conductarr.isInitialized) conductarr.close()
|
||||
}
|
||||
|
||||
@Test fun outgoingLoadedTitleCannotConsumeTheNextHomeBack() = verifyOutgoingBack(personPage = false)
|
||||
@Test fun outgoingLoadedPersonCannotConsumeTheNextHomeBack() = verifyOutgoingBack(personPage = true)
|
||||
|
||||
private fun verifyOutgoingBack(personPage: Boolean) {
|
||||
val activity = rule.activity
|
||||
val navigation = NavigationManager()
|
||||
val viewer = ShellPerson("justin", "Justin", "J", false)
|
||||
val shell = ShellState(listOf(viewer), viewer.key) {
|
||||
if (it == ShellAction.Exit) navigation.requestExit()
|
||||
}.apply { pickerVisible = false; pickerLaunch = false; navFocused = false }
|
||||
val id = UUID.fromString("00000000-0000-0000-0000-000000000031")
|
||||
val route = if (personPage) personRoute(id.toString()) else titleRoute(id.toString())
|
||||
val destination = Destination.Wolfskin(route)
|
||||
val facade = mockk<TitleReadFacade>()
|
||||
if (personPage) {
|
||||
coEvery { facade.readPersonSaved(id) } returns null
|
||||
coEvery { facade.readPerson(id, 0) } returns PersonRead(TitlePerson(id.toString(), "Outgoing actor"),
|
||||
listOf(TitleItem("credit", "Credit", "movie")))
|
||||
} else {
|
||||
coEvery { facade.readSaved(id, any()) } returns null
|
||||
coEvery { facade.read(id, any(), any()) } returns TitlePageData(TitleItem(id.toString(), "Outgoing film", "movie", held = true))
|
||||
}
|
||||
conductarr = ConductarrSession(MemoryCacheStore())
|
||||
viewModel = WolfskinTitleViewModel(activity, facade, mockk<TitleFixtureProvider>(), navigation, conductarr,
|
||||
mockk<ServerRepository>(relaxed = true))
|
||||
shell.enterDestination(route)
|
||||
navigation.navigateTo(destination)
|
||||
val home = HomeSnapshot(listOf(HomeRow("hero", HomeRowKind.Hero, cards = listOf(HomeTitle("home-film", "Home film", "movie")))))
|
||||
val preferences = UserPreferences(AppPreferences.getDefaultInstance(), null)
|
||||
rule.setContent {
|
||||
WolfskinTheme {
|
||||
rememberWolfskinBackHandler(shell, navigation)
|
||||
val current = navigation.backStack.last()
|
||||
LaunchedEffect(current) { if (current is Destination.Home) shell.enterDestination("home") }
|
||||
Box {
|
||||
ScreenEntry(shell, "home", current is Destination.Home) { HomeScreen(shell, home) {} }
|
||||
// Retain the real outgoing destination just as NavDisplay does during its exit animation.
|
||||
ScreenEntry(shell, route, current == destination) {
|
||||
TitleDestination(route, shell, preferences, viewModel = viewModel, fixtures = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rule.waitUntil(5_000) {
|
||||
Snapshot.sendApplyNotifications()
|
||||
Shadows.shadowOf(Looper.getMainLooper()).idle()
|
||||
(if (personPage) viewModel.person != null else viewModel.title?.data?.status == TitleReadStatus.Ready) && !shell.navFocused
|
||||
}
|
||||
rule.runOnIdle { activity.onBackPressedDispatcher.onBackPressed() }
|
||||
rule.waitForIdle()
|
||||
assertEquals(listOf(Destination.Home()), navigation.backStack.toList())
|
||||
assertFalse(shell.navFocused)
|
||||
rule.runOnIdle { activity.onBackPressedDispatcher.onBackPressed() }
|
||||
rule.mainClock.advanceTimeBy(16)
|
||||
assertTrue("The incoming Home must receive Back while the outgoing entry is retained", shell.navFocused)
|
||||
assertFalse("A second Back must not finish the task through the outgoing entry", activity.isFinishing)
|
||||
assertEquals(listOf(Destination.Home()), navigation.backStack.toList())
|
||||
rule.runOnIdle { activity.onBackPressedDispatcher.onBackPressed() }
|
||||
rule.mainClock.advanceTimeBy(16)
|
||||
assertTrue("Only the following Back from Home nav should exit", activity.isFinishing)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue