0.2.60 - Improvments to Requests, placeholders

This commit is contained in:
ponzischeme89
2026-08-12 16:54:41 +12:00
parent 4fb68f4bbc
commit a0b84dfc37
12 changed files with 778 additions and 177 deletions
@@ -17,13 +17,17 @@ class HomeGreetingTest {
}
@Test
fun `greeting is shown after hero through continue watching`() {
fun `greeting is shown from the hero through continue watching`() {
val rows = listOf("featured", "continue", "latest")
// Null is the hero: the featured card is not a row, so nothing in the list holds
// focus while somebody is on it — and that is the frame every launch opens with.
assertTrue(shouldShowHomeGreeting(true, null, rows))
assertTrue(shouldShowHomeGreeting(true, "featured", rows))
assertTrue(shouldShowHomeGreeting(true, "continue", rows))
assertFalse(shouldShowHomeGreeting(true, "latest", rows))
assertFalse(shouldShowHomeGreeting(true, null, rows))
assertFalse(shouldShowHomeGreeting(false, "continue", rows))
// No hero means no greeting even on the opening frame: the header is a row title.
assertFalse(shouldShowHomeGreeting(false, null, rows))
}
}
@@ -91,16 +91,60 @@ class RequestPresentationTest {
assertEquals("2 of 5 ready to watch", requestSummaryLabel(5, 2))
}
/**
* A short query is affordable again now that a lookup happens on a press rather than on
* a keystroke: it is one deliberate call to Radarr and Sonarr, not the first of eight.
*/
@Test
fun `the lookup threshold is stricter than the library search's`() {
// Every keystroke here reaches Radarr and Sonarr rather than a local index.
assertFalse(shouldLookup("du"))
assertFalse(shouldLookup("dune"))
assertTrue(shouldLookup("dunes"))
fun `two characters is enough to look something up`() {
assertFalse(shouldLookup("d"))
assertTrue(shouldLookup("up"))
assertTrue(shouldLookup("dune"))
assertFalse(shouldLookup(" a "))
assertTrue(shouldLookup(" dune part two "))
}
/**
* The three quiet states are the ones worth pinning: "not enough yet", "enough, and
* waiting for you to ask" and "asked, and nothing matched" read almost the same on
* screen and mean quite different things.
*/
@Test
fun `the results pane says which of the quiet states it is in`() {
fun phase(
query: String,
searched: String? = null,
searching: Boolean = false,
failed: Boolean = false,
count: Int = 0,
) = requestsSearchPhase(query, searched, searching, failed, count)
assertEquals(RequestsSearchPhase.IDLE, phase(""))
assertEquals(RequestsSearchPhase.TOO_SHORT, phase("d"))
assertEquals(RequestsSearchPhase.READY, phase("dune"))
assertEquals(RequestsSearchPhase.SEARCHING, phase("dune", searching = true))
assertEquals(RequestsSearchPhase.RESULTS, phase("dune", searched = "dune", count = 3))
assertEquals(RequestsSearchPhase.NO_MATCHES, phase("dune", searched = "dune"))
assertEquals(RequestsSearchPhase.FAILED, phase("dune", searched = "dune", failed = true))
}
/**
* Typing after a search means the cards on screen answer something else, so the pane
* asks to be run again rather than presenting them as the answer.
*/
@Test
fun `editing after a search returns the pane to press-search`() {
assertEquals(
RequestsSearchPhase.READY,
requestsSearchPhase("dune p", searchedTerm = "dune", searching = false, failed = false, candidateCount = 3),
)
// And the whitespace either side of a query is not an edit.
assertEquals(
RequestsSearchPhase.RESULTS,
requestsSearchPhase(" dune ", searchedTerm = "dune", searching = false, failed = false, candidateCount = 3),
)
}
@Test
fun `the switcher's action count matches the rows actually drawn`() {
assertEquals(2, userSwitcherActionCount(showRequests = false))
@@ -77,7 +77,10 @@ class RequestsScreenshotTest {
RequestsUiState(
tab = RequestsTab.DISCOVER,
loadingRequests = false,
// searchedTerm matching the query is what makes these cards *the answer*
// rather than results the viewer has since typed past.
query = "dune",
searchedTerm = "dune",
hasSearched = true,
candidates = sampleCandidates,
),
@@ -92,7 +95,10 @@ class RequestsScreenshotTest {
RequestsUiState(
tab = RequestsTab.DISCOVER,
loadingRequests = false,
// searchedTerm matching the query is what makes these cards *the answer*
// rather than results the viewer has since typed past.
query = "dune",
searchedTerm = "dune",
hasSearched = true,
candidates = sampleCandidates,
submitting = setOf(candidateKey("movie", 693134)),
@@ -109,6 +115,37 @@ class RequestsScreenshotTest {
)
}
/**
* Typed, and not looked up yet — the state this page spends most of its time in now
* that nothing reaches Radarr or Sonarr until somebody asks. The capture is here to
* check the one thing a unit test cannot: that the Search key reads as the next step
* from across a room, and that the pane beside it says so in the same breath.
*/
@Test
fun `typed but not yet searched`() {
capture(
"requests-discover-ready",
RequestsUiState(
tab = RequestsTab.DISCOVER,
loadingRequests = false,
query = "dune",
),
)
}
/** Below the minimum: the Search key is drawn, reachable, and visibly not yet usable. */
@Test
fun `too little typed to search`() {
capture(
"requests-discover-too-short",
RequestsUiState(
tab = RequestsTab.DISCOVER,
loadingRequests = false,
query = "d",
),
)
}
@Test
fun `a search that found nothing`() {
capture(
@@ -117,6 +154,7 @@ class RequestsScreenshotTest {
tab = RequestsTab.DISCOVER,
loadingRequests = false,
query = "qqqqq",
searchedTerm = "qqqqq",
hasSearched = true,
),
)
@@ -183,6 +221,7 @@ class RequestsScreenshotTest {
onAppendToQuery = {},
onBackspace = {},
onClearQuery = {},
onSubmitSearch = {},
onRequest = {},
onRemove = {},
onOpenItem = {},