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

grain.social/grain-android

1 collaborator
0
1
main
102 lines · 3.1 KB Raw History
package social.grain

import androidx.compose.ui.test.hasSetTextAction
import androidx.compose.ui.test.junit4.v2.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import social.grain.feature.login.LoginScreen
import social.grain.feature.login.LoginViewModel
import social.grain.support.stubSignIn
import social.grain.support.Harness
import social.grain.support.awaitContentDescription
import social.grain.support.awaitText
import social.grain.support.MainDispatcherRule
import social.grain.support.awaitCall

/**
 * The sign-in screen, which is the only screen a signed-out reader ever sees.
 *
 * It forces its own dark scheme over a photograph rather than following the
 * device, so it is also the one screen where a theme regression would be
 * invisible everywhere else.
 */
@RunWith(AndroidJUnit4::class)
class LoginScreenTest {

    @get:Rule
    val mainDispatcher = MainDispatcherRule()

    @get:Rule
    val composeRule = createComposeRule()

    private lateinit var harness: Harness

    @Before
    fun setUp() {
        harness = Harness(signedIn = false)
        harness.server
            .on(
                "social.grain.actor.searchActorsTypeahead",
                """{"actors":[{"did":"did:plc:alice","handle":"alice.grain.social"}]}""",
            )
        harness.server.stubSignIn(did = "did:plc:alice", handle = "alice.grain.social")
    }

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

    private fun show() {
        val model = LoginViewModel(harness.auth, harness.client)
        composeRule.setContent { LoginScreen(viewModel = model) }
        composeRule.waitForIdle()
    }

    @Test
    fun theScreenInvitesAnAtmosphereAccount() {
        show()

        composeRule.awaitText("Sign in with your atmosphere account")
        composeRule.awaitText("Handle")
        composeRule.awaitText("Sign in")
        composeRule.awaitText("Create account")
    }

    @Test
    fun typingAHandleOffersMatchesFromTheServer() {
        show()

        composeRule.onNode(hasSetTextAction()).performTextInput("ali")
        composeRule.waitUntil(10_000) { harness.server.countOf("social.grain.actor.searchActorsTypeahead") >= 1 }
        composeRule.waitForIdle()

        composeRule.awaitText("alice.grain.social", substring = true)
    }

    @Test
    fun signingInRunsThePushedAuthorizationRequest() {
        show()

        composeRule.onNode(hasSetTextAction()).performTextInput("alice.grain.social")
        composeRule.onNodeWithText("Sign in").performClick()

        composeRule.waitUntil(10_000) { harness.server.countOf("par") >= 1 }
    }

    @Test
    fun creatingAnAccountAsksForTheSignUpPage() {
        show()

        composeRule.onNodeWithText("Create account").performClick()

        composeRule.waitUntil(10_000) { harness.server.countOf("par") >= 1 }
        val par = harness.server.lastCall("par")
        assert(par.body.contains("prompt=create"))
    }
}