Clean up LandingScreen tests (#322)

This commit is contained in:
Brian Yencho 2023-12-05 09:53:00 -06:00 committed by Álison Fernandes
parent cb932bda64
commit 0b1be57796

View file

@ -24,33 +24,47 @@ import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.verify import io.mockk.verify
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Assertions.assertTrue
class LandingScreenTest : BaseComposeTest() { class LandingScreenTest : BaseComposeTest() {
private var capturedEmail: String? = null
private var onNavigateToCreateAccountCalled = false
private var onNavigateToLoginCalled = false
private var onNavigateToEnvironmentCalled = false
private val mutableEventFlow = MutableSharedFlow<LandingEvent>(
extraBufferCapacity = Int.MAX_VALUE,
)
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
private val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns mutableEventFlow
every { stateFlow } returns mutableStateFlow
}
private val resources private val resources
get() = ApplicationProvider.getApplicationContext<Application>().resources get() = ApplicationProvider.getApplicationContext<Application>().resources
@Test @Before
fun `continue button should be enabled or disabled according to the state`() { fun setUp() {
val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns emptyFlow()
every { stateFlow } returns mutableStateFlow
}
composeTestRule.setContent { composeTestRule.setContent {
LandingScreen( LandingScreen(
onNavigateToCreateAccount = {}, onNavigateToCreateAccount = { onNavigateToCreateAccountCalled = true },
onNavigateToLogin = { _ -> }, onNavigateToLogin = { capturedEmail ->
onNavigateToEnvironment = {}, this.capturedEmail = capturedEmail
onNavigateToLoginCalled = true
},
onNavigateToEnvironment = { onNavigateToEnvironmentCalled = true },
viewModel = viewModel, viewModel = viewModel,
) )
} }
}
@Test
fun `continue button should be enabled or disabled according to the state`() {
composeTestRule.onNodeWithText("Continue").assertIsEnabled() composeTestRule.onNodeWithText("Continue").assertIsEnabled()
mutableStateFlow.update { it.copy(isContinueButtonEnabled = false) } mutableStateFlow.update { it.copy(isContinueButtonEnabled = false) }
@ -60,18 +74,6 @@ class LandingScreenTest : BaseComposeTest() {
@Test @Test
fun `continue button click should send ContinueButtonClick action`() { fun `continue button click should send ContinueButtonClick action`() {
val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns emptyFlow()
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE)
}
composeTestRule.setContent {
LandingScreen(
onNavigateToCreateAccount = {},
onNavigateToLogin = { _ -> },
onNavigateToEnvironment = {},
viewModel = viewModel,
)
}
composeTestRule.onNodeWithText("Continue").performScrollTo().performClick() composeTestRule.onNodeWithText("Continue").performScrollTo().performClick()
verify { verify {
viewModel.trySendAction(LandingAction.ContinueButtonClick) viewModel.trySendAction(LandingAction.ContinueButtonClick)
@ -80,19 +82,6 @@ class LandingScreenTest : BaseComposeTest() {
@Test @Test
fun `remember me should be toggled on or off according to the state`() { fun `remember me should be toggled on or off according to the state`() {
val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns emptyFlow()
every { stateFlow } returns mutableStateFlow
}
composeTestRule.setContent {
LandingScreen(
onNavigateToCreateAccount = {},
onNavigateToLogin = { _ -> },
onNavigateToEnvironment = {},
viewModel = viewModel,
)
}
composeTestRule.onNodeWithText("Remember me").assertIsOff() composeTestRule.onNodeWithText("Remember me").assertIsOff()
mutableStateFlow.update { it.copy(isRememberMeEnabled = true) } mutableStateFlow.update { it.copy(isRememberMeEnabled = true) }
@ -102,18 +91,6 @@ class LandingScreenTest : BaseComposeTest() {
@Test @Test
fun `remember me click should send RememberMeToggle action`() { fun `remember me click should send RememberMeToggle action`() {
val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns emptyFlow()
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE)
}
composeTestRule.setContent {
LandingScreen(
onNavigateToCreateAccount = {},
onNavigateToLogin = { _ -> },
onNavigateToEnvironment = {},
viewModel = viewModel,
)
}
composeTestRule composeTestRule
.onNodeWithText("Remember me") .onNodeWithText("Remember me")
.performClick() .performClick()
@ -124,18 +101,6 @@ class LandingScreenTest : BaseComposeTest() {
@Test @Test
fun `create account click should send CreateAccountClick action`() { fun `create account click should send CreateAccountClick action`() {
val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns emptyFlow()
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE)
}
composeTestRule.setContent {
LandingScreen(
onNavigateToCreateAccount = {},
onNavigateToLogin = { _ -> },
onNavigateToEnvironment = {},
viewModel = viewModel,
)
}
composeTestRule.onNodeWithText("Create account").performScrollTo().performClick() composeTestRule.onNodeWithText("Create account").performScrollTo().performClick()
verify { verify {
viewModel.trySendAction(LandingAction.CreateAccountClick) viewModel.trySendAction(LandingAction.CreateAccountClick)
@ -144,20 +109,6 @@ class LandingScreenTest : BaseComposeTest() {
@Test @Test
fun `email address should change according to state`() { fun `email address should change according to state`() {
val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns emptyFlow()
every { stateFlow } returns mutableStateFlow
}
composeTestRule.setContent {
LandingScreen(
onNavigateToCreateAccount = {},
onNavigateToLogin = { _ -> },
onNavigateToEnvironment = {},
viewModel = viewModel,
)
}
composeTestRule composeTestRule
.onNodeWithText("Email address") .onNodeWithText("Email address")
.assertTextEquals("Email address", "") .assertTextEquals("Email address", "")
@ -172,18 +123,6 @@ class LandingScreenTest : BaseComposeTest() {
@Test @Test
fun `email address change should send EmailInputChanged action`() { fun `email address change should send EmailInputChanged action`() {
val input = "email" val input = "email"
val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns emptyFlow()
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE)
}
composeTestRule.setContent {
LandingScreen(
onNavigateToCreateAccount = {},
onNavigateToLogin = { _ -> },
onNavigateToEnvironment = {},
viewModel = viewModel,
)
}
composeTestRule.onNodeWithText("Email address").performTextInput(input) composeTestRule.onNodeWithText("Email address").performTextInput(input)
verify { verify {
viewModel.trySendAction(LandingAction.EmailInputChanged(input)) viewModel.trySendAction(LandingAction.EmailInputChanged(input))
@ -192,19 +131,7 @@ class LandingScreenTest : BaseComposeTest() {
@Test @Test
fun `NavigateToCreateAccount event should call onNavigateToCreateAccount`() { fun `NavigateToCreateAccount event should call onNavigateToCreateAccount`() {
var onNavigateToCreateAccountCalled = false mutableEventFlow.tryEmit(LandingEvent.NavigateToCreateAccount)
val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns flowOf(LandingEvent.NavigateToCreateAccount)
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE)
}
composeTestRule.setContent {
LandingScreen(
onNavigateToCreateAccount = { onNavigateToCreateAccountCalled = true },
onNavigateToLogin = { _ -> },
onNavigateToEnvironment = {},
viewModel = viewModel,
)
}
assertTrue(onNavigateToCreateAccountCalled) assertTrue(onNavigateToCreateAccountCalled)
} }
@ -212,61 +139,21 @@ class LandingScreenTest : BaseComposeTest() {
fun `NavigateToLogin event should call onNavigateToLogin`() { fun `NavigateToLogin event should call onNavigateToLogin`() {
val testEmail = "test@test.com" val testEmail = "test@test.com"
var capturedEmail: String? = null mutableEventFlow.tryEmit(LandingEvent.NavigateToLogin(testEmail))
val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns flowOf(LandingEvent.NavigateToLogin(testEmail))
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE)
}
composeTestRule.setContent {
LandingScreen(
onNavigateToCreateAccount = { },
onNavigateToLogin = { email ->
capturedEmail = email
},
onNavigateToEnvironment = {},
viewModel = viewModel,
)
}
assertEquals(testEmail, capturedEmail) assertEquals(testEmail, capturedEmail)
assertTrue(onNavigateToLoginCalled)
} }
@Test @Test
fun `NavigateToEnvironment event should call onNavigateToEvent`() { fun `NavigateToEnvironment event should call onNavigateToEvent`() {
var onNavigateToEnvironmentCalled = false mutableEventFlow.tryEmit(LandingEvent.NavigateToEnvironment)
val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns flowOf(LandingEvent.NavigateToEnvironment)
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE)
}
composeTestRule.setContent {
LandingScreen(
onNavigateToCreateAccount = { },
onNavigateToLogin = { _ -> },
onNavigateToEnvironment = { onNavigateToEnvironmentCalled = true },
viewModel = viewModel,
)
}
assertTrue(onNavigateToEnvironmentCalled) assertTrue(onNavigateToEnvironmentCalled)
} }
@Test @Test
fun `selecting environment should send EnvironmentOptionSelect action`() { fun `selecting environment should send EnvironmentOptionSelect action`() {
val selectedEnvironment = Environment.Eu val selectedEnvironment = Environment.Eu
val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns emptyFlow()
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE)
}
composeTestRule.setContent {
LandingScreen(
onNavigateToCreateAccount = {},
onNavigateToLogin = { _ -> },
onNavigateToEnvironment = {},
viewModel = viewModel,
)
}
// Clicking to open dialog // Clicking to open dialog
composeTestRule composeTestRule
@ -291,20 +178,6 @@ class LandingScreenTest : BaseComposeTest() {
@Test @Test
fun `error dialog should be shown or hidden according to the state`() { fun `error dialog should be shown or hidden according to the state`() {
val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
val viewModel = mockk<LandingViewModel>(relaxed = true) {
every { eventFlow } returns emptyFlow()
every { stateFlow } returns mutableStateFlow
}
composeTestRule.setContent {
LandingScreen(
onNavigateToCreateAccount = {},
onNavigateToLogin = { _ -> },
onNavigateToEnvironment = {},
viewModel = viewModel,
)
}
composeTestRule.onNode(isDialog()).assertDoesNotExist() composeTestRule.onNode(isDialog()).assertDoesNotExist()
mutableStateFlow.update { mutableStateFlow.update {
@ -334,40 +207,27 @@ class LandingScreenTest : BaseComposeTest() {
@Test @Test
fun `error dialog OK click should send ErrorDialogDismiss action`() { fun `error dialog OK click should send ErrorDialogDismiss action`() {
val viewModel = mockk<LandingViewModel>(relaxed = true) { mutableStateFlow.update {
every { eventFlow } returns emptyFlow() DEFAULT_STATE.copy(
every { stateFlow } returns MutableStateFlow( errorDialogState = BasicDialogState.Shown(
DEFAULT_STATE.copy( title = "title".asText(),
errorDialogState = BasicDialogState.Shown( message = "message".asText(),
title = "title".asText(),
message = "message".asText(),
),
), ),
) )
every { trySendAction(LandingAction.ErrorDialogDismiss) } returns Unit
}
composeTestRule.setContent {
LandingScreen(
onNavigateToCreateAccount = {},
onNavigateToLogin = { _ -> },
onNavigateToEnvironment = {},
viewModel = viewModel,
)
} }
composeTestRule composeTestRule
.onAllNodesWithText("Ok") .onAllNodesWithText("Ok")
.filterToOne(hasAnyAncestor(isDialog())) .filterToOne(hasAnyAncestor(isDialog()))
.performClick() .performClick()
verify { viewModel.trySendAction(LandingAction.ErrorDialogDismiss) } verify { viewModel.trySendAction(LandingAction.ErrorDialogDismiss) }
} }
companion object {
val DEFAULT_STATE = LandingState(
emailInput = "",
isContinueButtonEnabled = true,
isRememberMeEnabled = false,
selectedEnvironmentType = Environment.Type.US,
errorDialogState = BasicDialogState.Hidden,
)
}
} }
private val DEFAULT_STATE = LandingState(
emailInput = "",
isContinueButtonEnabled = true,
isRememberMeEnabled = false,
selectedEnvironmentType = Environment.Type.US,
errorDialogState = BasicDialogState.Hidden,
)