Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
Kotlin
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218package social.grain
import androidx.test.ext.junit.runners.AndroidJUnit4import org.junit.Afterimport org.junit.Assert.assertEqualsimport org.junit.Assert.assertFalseimport org.junit.Assert.assertNullimport org.junit.Assert.assertTrueimport org.junit.Beforeimport org.junit.Ruleimport org.junit.Testimport org.junit.runner.RunWithimport social.grain.feature.notifications.NotificationsViewModelimport social.grain.feature.notifications.UnseenNotificationCountimport social.grain.support.Fixturesimport social.grain.support.Harnessimport social.grain.support.MainDispatcherRuleimport social.grain.support.appContextimport social.grain.support.awaitCallimport social.grain.support.awaitValueimport social.grain.support.jsonimport social.grain.support.settle
/** * The notifications list and the badge that rides on it. * * Grouping is tested on its own elsewhere; what matters here is that a second * page is folded into the rows already on screen rather than regrouped from * scratch — regrouping reorders rows under the reader's thumb — and that the * badge is cleared optimistically but put back if the write fails. */@RunWith(AndroidJUnit4::class)class NotificationsViewModelTest {
@get:Rule val mainDispatcher = MainDispatcherRule()
private lateinit var harness: Harness private lateinit var unseen: UnseenNotificationCount
private val nsid = "social.grain.unspecced.getNotifications"
private fun page(vararg items: String, cursor: String? = null, unseenCount: Int? = null) = """{"notifications":[${items.joinToString(",")}]""" + (cursor?.let { ""","cursor":"$it"""" } ?: "") + (unseenCount?.let { ""","unseenCount":$it""" } ?: "") + "}"
@Before fun setUp() { harness = Harness() unseen = UnseenNotificationCount(appContext, harness.client, harness.auth) harness.server.on(nsid, page(json(Fixtures.notification()), unseenCount = 2)) }
@After fun tearDown() = harness.tearDown()
private fun viewModel() = NotificationsViewModel(harness.client, harness.auth, unseen)
@Test fun theFirstPageLoadsAndSetsTheBadge() { val model = viewModel() val state = model.state.awaitValue("the first page") { it.hasLoaded }
assertEquals(1, state.groups.size) assertFalse(state.isLoading) assertNull(state.errorMessage) assertEquals(2, unseen.count.value) }
@Test fun favoritesOnTheSameGalleryCollapseIntoOneRow() { harness.server.on( nsid, page( json(Fixtures.notification(rkey = "n1")), json(Fixtures.notification(rkey = "n2", author = Fixtures.profile(did = "did:plc:bob"))), ), ) val model = viewModel() val state = model.state.awaitValue("the first page") { it.hasLoaded }
assertEquals(1, state.groups.size) assertEquals(2, state.groups.single().authorCount) assertTrue(state.groups.single().isGrouped) }
@Test fun commentsStayOnTheirOwnRows() { harness.server.on( nsid, page( json(Fixtures.notification(rkey = "n1", reason = "gallery-comment", commentText = "One")), json(Fixtures.notification(rkey = "n2", reason = "gallery-comment", commentText = "Two")), ), ) val model = viewModel() val state = model.state.awaitValue("the first page") { it.hasLoaded }
assertEquals(2, state.groups.size) }
@Test fun aFailedLoadReportsItsMessage() { harness.server.on(nsid, """{"error":"nope"}""", code = 500) val model = viewModel()
val state = model.state.awaitValue("the error") { it.errorMessage != null } assertEquals("HTTP error 500", state.errorMessage) assertTrue(state.hasLoaded)
model.dismissError() assertNull(model.state.value.errorMessage) }
@Test fun asecondPageIsMergedIntoTheRowsAlreadyShowing() { harness.server.on(nsid, page(json(Fixtures.notification(rkey = "n1")), cursor = "c1")) val model = viewModel() model.state.awaitValue("the first page") { it.hasLoaded }
harness.server.on( nsid, page(json(Fixtures.notification(rkey = "n2", author = Fixtures.profile(did = "did:plc:bob")))), ) model.loadMore()
val state = model.state.awaitValue("the merge") { it.groups.firstOrNull()?.isGrouped == true } assertEquals("Still one row, two faces", 1, state.groups.size) assertEquals(2, state.groups.single().authorCount) assertFalse(state.isLoadingMore) }
@Test fun aPageWithNoCursorIsTheEndOfTheList() { val model = viewModel() model.state.awaitValue("the first page") { it.hasLoaded } val before = harness.server.countOf(nsid)
model.loadMore() settle()
assertEquals(before, harness.server.countOf(nsid)) }
@Test fun refreshingStartsTheListOver() { val model = viewModel() model.state.awaitValue("the first page") { it.hasLoaded }
harness.server.on( nsid, page(json(Fixtures.notification(rkey = "fresh", reason = "follow"))), ) model.refresh()
model.state.awaitValue("the refreshed list") { it.groups.singleOrNull()?.notification?.reason == "follow" } }
@Test fun markingSeenClearsTheBadgeAndTellsTheServer() { val model = viewModel() model.state.awaitValue("the first page") { it.hasLoaded } assertEquals(2, unseen.count.value)
model.markSeen()
assertEquals(0, unseen.count.value) assertTrue( harness.server.awaitCall("dev.hatk.putPreference") .body.contains("lastSeenNotifications"), ) }
@Test fun aFailedSeenWritePutsTheBadgeBack() { harness.server.on("dev.hatk.putPreference", """{"error":"no"}""", code = 500) val model = viewModel() model.state.awaitValue("the first page") { it.hasLoaded }
model.markSeen()
val deadline = System.currentTimeMillis() + 5_000 while (unseen.count.value != 2 && System.currentTimeMillis() < deadline) Thread.sleep(10) assertEquals(2, unseen.count.value) }
@Test fun anAlreadyEmptyBadgeIsStillTakenDownWithoutWritingToTheServer() { harness.server.on(nsid, page(json(Fixtures.notification()), unseenCount = 0)) val model = viewModel() model.state.awaitValue("the first page") { it.hasLoaded }
model.markSeen() settle()
assertEquals(0, unseen.count.value) assertEquals(0, harness.server.countOf("dev.hatk.putPreference")) }
@Test fun theCheapPollUpdatesTheBadgeOnItsOwn() { harness.server.on(nsid, page(unseenCount = 7)) kotlinx.coroutines.runBlocking { unseen.refresh() }
assertEquals(7, unseen.count.value) assertEquals("true", harness.server.lastCall(nsid).params["countOnly"]) }
@Test fun theBadgeNeverGoesNegative() { unseen.set(-3) assertEquals(0, unseen.count.value) }}