~ knotless Search/
↑↓ move↵ open⇧↵ all results

grain.social/grain-android

1 collaborator
0
1
main
237 lines · 8.1 KB Raw History
package social.grain

import androidx.compose.ui.test.junit4.v2.createComposeRule
import androidx.lifecycle.SavedStateHandle
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import okhttp3.OkHttpClient
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import social.grain.data.location.LocationServices
import social.grain.feature.explore.CamerasScreen
import social.grain.feature.explore.CamerasViewModel
import social.grain.feature.explore.LocationsScreen
import social.grain.feature.explore.LocationsViewModel
import social.grain.feature.feed.CameraFeedScreen
import social.grain.feature.feed.CameraFeedViewModel
import social.grain.support.Fixtures
import social.grain.support.Harness
import social.grain.support.MainDispatcherRule
import social.grain.support.awaitContentDescription
import social.grain.support.awaitText
import social.grain.support.json
import social.grain.support.testJson
import social.grain.ui.theme.GrainTheme

/** The screens behind explore: the two indexes, a tile per entry, and the camera feed. */
@RunWith(AndroidJUnit4::class)
class ExploreScreensTest {

    @get:Rule
    val mainDispatcher = MainDispatcherRule()

    @get:Rule
    val composeRule = createComposeRule()

    private lateinit var harness: Harness

    @Before
    fun setUp() {
        harness = Harness()
        harness.server
            .on(
                "social.grain.gallery.getCameras",
                """{"cameras":[
                    {"camera":"Leica M6","photoCount":120,"thumbs":["https://cdn.grain.test/thumb/1.jpg"]},
                    {"camera":"Ricoh GR III","photoCount":1}
                ]}""",
            )
            .on(
                "social.grain.gallery.getLocations",
                """{"locations":[{"name":"Lisbon, PT","h3Index":"85390cb7fffffff","galleryCount":3}]}""",
            )
    }

    @After
    fun tearDown() = harness.tearDown()

    @Test
    fun theCamerasIndexDrawsATilePerCameraWithItsCount() {
        var opened: String? = null
        composeRule.setContent {
            GrainTheme {
                CamerasScreen(
                    onBack = {},
                    onOpenCamera = { opened = it },
                    viewModel = CamerasViewModel(harness.client, harness.auth),
                )
            }
        }

        composeRule.awaitText("Cameras")
        composeRule.awaitText("Leica M6")
        composeRule.awaitText("120 photos")
        composeRule.awaitText("1 photo")

        composeRule.onNodeWithText("Ricoh GR III").performClick()
        assertEquals("Ricoh GR III", opened)
    }

    @Test
    fun aCameraFeedIsTitledByTheCameraAndDrawsItsCards() {
        harness.server
            .on("social.grain.feed.getFeed", """{"items":[${json(Fixtures.gallery(title = "Shot on film"))}]}""")
        composeRule.setContent {
            GrainTheme {
                CameraFeedScreen(
                    onBack = {},
                    onOpenProfile = {},
                    onOpenHashtag = {},
                    viewModel = CameraFeedViewModel(
                        client = harness.client,
                        auth = harness.auth,
                        labelDefsCache = harness.labelDefinitions,
                        savedStateHandle = SavedStateHandle(mapOf("name" to "Leica M6")),
                    ),
                )
            }
        }

        composeRule.awaitText("Leica M6")
        composeRule.awaitText("Shot on film")
        assertEquals("Leica M6", harness.server.lastCall("social.grain.feed.getFeed").params["camera"])
    }

    @Test
    fun anEmptyCameraFeedSaysSo() {
        harness.server
            .on("social.grain.feed.getFeed", """{"items":[]}""")
        composeRule.setContent {
            GrainTheme {
                CameraFeedScreen(
                    onBack = {},
                    onOpenProfile = {},
                    onOpenHashtag = {},
                    viewModel = CameraFeedViewModel(
                        client = harness.client,
                        auth = harness.auth,
                        labelDefsCache = harness.labelDefinitions,
                        savedStateHandle = SavedStateHandle(mapOf("name" to "Leica M6")),
                    ),
                )
            }
        }

        composeRule.awaitText("No galleries from this camera yet")
    }

    @Test
    fun anEmptyCamerasIndexSaysSo() {
        harness.server.on("social.grain.gallery.getCameras", """{"cameras":[]}""")
        composeRule.setContent {
            GrainTheme {
                CamerasScreen(
                    onBack = {},
                    onOpenCamera = {},
                    viewModel = CamerasViewModel(harness.client, harness.auth),
                )
            }
        }

        composeRule.awaitText("No cameras yet.")
    }

    @Test
    fun pickingAPlaceSwapsTheSheetToItsGalleriesAndBackAgain() {
        harness.server
            .on("social.grain.feed.getFeed", """{"items":[${json(Fixtures.gallery(title = "By the river"))}]}""")
        var opened: String? = null
        composeRule.setContent {
            GrainTheme {
                LocationsScreen(
                    onBack = {},
                    onOpenGallery = { opened = it },
                    viewModel = LocationsViewModel(
                        harness.client,
                        harness.auth,
                        LocationServices(OkHttpClient(), testJson),
                        harness.labelDefinitions,
                        SavedStateHandle(),
                    ),
                )
            }
        }

        composeRule.awaitText("Locations")
        composeRule.awaitText("Lisbon, PT")
        composeRule.awaitText("3 galleries")

        composeRule.onNodeWithText("Lisbon, PT").performClick()

        // The place's galleries arrive in the sheet; the screen was not left.
        composeRule.awaitContentDescription("By the river")
        composeRule.awaitContentDescription("All locations")
        assertEquals("85390cb7fffffff", harness.server.lastCall("social.grain.feed.getFeed").params["location"])

        composeRule.onNodeWithContentDescription("By the river").performClick()
        assertEquals(Fixtures.gallery().uri, opened)

        composeRule.onNodeWithContentDescription("All locations").performClick()
        composeRule.awaitText("Locations")
        composeRule.onNodeWithContentDescription("By the river").assertDoesNotExist()
    }

    @Test
    fun anEmptyLocationsIndexSaysSo() {
        harness.server.on("social.grain.gallery.getLocations", """{"locations":[]}""")
        composeRule.setContent {
            GrainTheme {
                LocationsScreen(
                    onBack = {},
                    onOpenGallery = {},
                    viewModel = LocationsViewModel(
                        harness.client,
                        harness.auth,
                        LocationServices(OkHttpClient(), testJson),
                        harness.labelDefinitions,
                        SavedStateHandle(),
                    ),
                )
            }
        }

        composeRule.awaitText("No locations yet.")
    }

    @Test
    fun aPlaceWithNoGalleriesSaysSoInItsSheet() {
        harness.server
            .on("social.grain.feed.getFeed", """{"items":[]}""")
        composeRule.setContent {
            GrainTheme {
                LocationsScreen(
                    onBack = {},
                    onOpenGallery = {},
                    viewModel = LocationsViewModel(
                        harness.client,
                        harness.auth,
                        LocationServices(OkHttpClient(), testJson),
                        harness.labelDefinitions,
                        SavedStateHandle(),
                    ),
                )
            }
        }

        composeRule.awaitText("Lisbon, PT")
        composeRule.onNodeWithText("Lisbon, PT").performClick()

        composeRule.awaitText("No galleries here yet.")
    }
}