Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295package social.grain
import androidx.compose.ui.test.junit4.v2.createComposeRuleimport androidx.compose.ui.test.onNodeWithContentDescriptionimport androidx.compose.ui.test.onNodeWithTextimport androidx.compose.ui.test.performClickimport androidx.compose.ui.test.performTextInputimport androidx.compose.ui.test.requestFocusimport androidx.test.ext.junit.runners.AndroidJUnit4import org.junit.Afterimport org.junit.Assert.assertEqualsimport org.junit.Assert.assertTrueimport org.junit.Beforeimport org.junit.Ruleimport org.junit.Testimport org.junit.runner.RunWithimport social.grain.feature.explore.ExploreViewModelimport social.grain.feature.search.SearchScreenimport social.grain.feature.search.SearchViewModelimport social.grain.support.Fixturesimport social.grain.support.Harnessimport social.grain.support.awaitContentDescriptionimport social.grain.support.awaitTextimport social.grain.support.MainDispatcherRuleimport social.grain.support.awaitCallimport social.grain.support.jsonimport social.grain.ui.theme.GrainTheme
/** * Search: explore before anything is typed, recents while the field has focus, * and two tabs of results once it does. */@RunWith(AndroidJUnit4::class)class SearchScreenTest {
@get:Rule val mainDispatcher = MainDispatcherRule()
@get:Rule val composeRule = createComposeRule()
private lateinit var harness: Harness
@Before fun setUp() { harness = Harness() harness.recentSearches.switchAccount(harness.did) harness.recentSearches.clear() harness.server .on("dev.hatk.describeLabels", """{"definitions":[]}""") .on( "social.grain.unspecced.searchGalleries", """{"items":[${json(Fixtures.gallery(title = "Fog on the bay"))}]}""", ) .on( "social.grain.unspecced.searchProfiles", """{"items":[{"did":"did:plc:bob","handle":"bob.test","displayName":"Bob"}]}""", ) .on("dev.hatk.getFeed", """{"items":[${json(Fixtures.gallery(title = "Explore me"))}]}""") .on("social.grain.unspecced.getCameras", cameras(2)) .on( "social.grain.unspecced.getLocations", """{"locations":[{"name":"Lisbon, PT","h3Index":"85390cb7fffffff","galleryCount":3}]}""", ) }
/** An index of [count] cameras, "Camera 1" upward. */ private fun cameras(count: Int): String = (1..count).joinToString(",", prefix = """{"cameras":[""", postfix = "]}") { """{"camera":"Camera $it","photoCount":$it}""" }
@After fun tearDown() { harness.recentSearches.clear() harness.tearDown() }
private lateinit var model: SearchViewModel
private fun show( onOpenProfile: (String) -> Unit = {}, onOpenGallery: (String) -> Unit = {}, onOpenCamera: (String) -> Unit = {}, onOpenPlace: (String, String, Int) -> Unit = { _, _, _ -> }, onOpenCameras: () -> Unit = {}, onOpenLocations: () -> Unit = {}, ) { model = SearchViewModel( harness.client, harness.auth, harness.recentSearches, harness.labelDefinitions, ) val explore = ExploreViewModel(harness.client, harness.auth, harness.labelDefinitions) composeRule.setContent { GrainTheme { SearchScreen( onOpenProfile = onOpenProfile, onOpenFavorites = {}, onOpenPlace = onOpenPlace, onOpenGallery = onOpenGallery, onOpenCamera = onOpenCamera, onOpenCameras = onOpenCameras, onOpenLocations = onOpenLocations, viewModel = model, exploreViewModel = explore, ) } } composeRule.waitForIdle() }
/** Put the caret in the field, as a tap on it would. */ private fun focusTheField() { composeRule.onNodeWithText("Search galleries and profiles").requestFocus() composeRule.waitForIdle() }
@Test fun anUntouchedSearchIsTheExplorePage() { show()
composeRule.awaitText("Search galleries and profiles") composeRule.awaitText("CAMERAS") composeRule.awaitText("Camera 1") composeRule.awaitText("LOCATIONS") composeRule.awaitText("Lisbon, PT") composeRule.awaitContentDescription("Explore me") }
@Test fun aCameraChipOpensThatCamerasFeed() { var opened: String? = null show(onOpenCamera = { opened = it })
composeRule.awaitText("Camera 2") composeRule.onNodeWithText("Camera 2").performClick()
assertEquals("Camera 2", opened) }
@Test fun aLocationChipOpensTheMapOnThatPlace() { var opened: Triple<String, String, Int>? = null show(onOpenPlace = { cell, name, count -> opened = Triple(cell, name, count) })
composeRule.awaitText("Lisbon, PT") composeRule.onNodeWithText("Lisbon, PT").performClick()
assertEquals(Triple("85390cb7fffffff", "Lisbon, PT", 3), opened) }
@Test fun aThumbnailOpensItsGallery() { var opened: String? = null show(onOpenGallery = { opened = it })
composeRule.awaitContentDescription("Explore me") composeRule.onNodeWithContentDescription("Explore me").performClick()
assertEquals(Fixtures.gallery().uri, opened) }
@Test fun seeAllOnlyAppearsOnceTheChipsAreTheTopOfALongerList() { show()
composeRule.awaitText("Camera 2") composeRule.onNodeWithText("See all").assertDoesNotExist() }
@Test fun seeAllOpensTheIndexBehindTheChips() { harness.server.on("social.grain.unspecced.getCameras", cameras(11)) var openedCameras = false show(onOpenCameras = { openedCameras = true })
composeRule.awaitText("Camera 10") composeRule.onNodeWithText("Camera 11").assertDoesNotExist() composeRule.onNodeWithText("See all").performClick()
assertTrue(openedCameras) }
@Test fun typingRunsAGallerySearchAndDrawsTheCards() { show()
composeRule.onNodeWithText("Search galleries and profiles").performTextInput("fog") composeRule.waitUntil(10_000) { harness.server.countOf("social.grain.unspecced.searchGalleries") >= 1 } composeRule.waitForIdle()
composeRule.awaitText("Fog on the bay") }
@Test fun theProfilesTabRunsItsOwnSearch() { show()
composeRule.onNodeWithText("Search galleries and profiles").performTextInput("bob") composeRule.waitUntil(10_000) { harness.server.countOf("social.grain.unspecced.searchGalleries") >= 1 } composeRule.waitForIdle()
composeRule.onNodeWithText("Profiles").performClick() composeRule.waitUntil(10_000) { harness.server.countOf("social.grain.unspecced.searchProfiles") >= 1 } composeRule.waitForIdle()
composeRule.awaitText("Bob") }
@Test fun aSearchThatFindsNothingSaysSoForTheTabItIsOn() { harness.server.on("social.grain.unspecced.searchGalleries", """{"items":[]}""") show()
composeRule.onNodeWithText("Search galleries and profiles").performTextInput("nothing") composeRule.waitUntil(10_000) { harness.server.countOf("social.grain.unspecced.searchGalleries") >= 1 } composeRule.waitForIdle()
composeRule.awaitText("No galleries match that.") }
@Test fun clearingTheFieldPutsThePromptBack() { show()
composeRule.onNodeWithText("Search galleries and profiles").performTextInput("fog") composeRule.waitUntil(10_000) { harness.server.countOf("social.grain.unspecced.searchGalleries") >= 1 } composeRule.waitForIdle()
composeRule.onNodeWithContentDescription("Clear search").performClick() composeRule.waitForIdle()
composeRule.awaitText("Camera 1") }
@Test fun recentsShowWhileTheFieldHasFocusAndExploreOtherwise() { harness.recentSearches.addTerm("fog") show()
composeRule.awaitText("Camera 1") composeRule.onNodeWithText("Recent").assertDoesNotExist()
focusTheField()
composeRule.awaitText("Recent") composeRule.awaitText("fog") }
@Test fun rememberedTermsAreOfferedBackAndCanBeRemoved() { harness.recentSearches.addTerm("fog") show() focusTheField()
composeRule.awaitText("Recent") composeRule.awaitText("fog")
composeRule.onNodeWithContentDescription("Remove from recents").performClick() composeRule.waitForIdle()
composeRule.onNodeWithText("fog").assertDoesNotExist() }
@Test fun theWholeRecentsListCanBeCleared() { harness.recentSearches.addTerm("fog") harness.recentSearches.addTerm("mist") show() focusTheField()
composeRule.awaitText("Recent") composeRule.onNodeWithText("Clear").performClick() composeRule.waitForIdle()
composeRule.onNodeWithText("Recent").assertDoesNotExist() }
@Test fun tappingARememberedTermRunsItAgain() { harness.recentSearches.addTerm("fog") show() focusTheField()
composeRule.awaitText("fog") composeRule.onNodeWithText("fog").performClick() composeRule.waitUntil(10_000) { harness.server.countOf("social.grain.unspecced.searchGalleries") >= 1 } composeRule.waitForIdle()
composeRule.awaitText("Fog on the bay") }}