Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add activity test for Link Screen State
Browse files Browse the repository at this point in the history
toluo-stripe committed Jan 31, 2025

Verified

This commit was signed with the committer’s verified signature.
antonioribeiro Antonio Ribeiro
1 parent cc84e6e commit a03ee37
Showing 7 changed files with 166 additions and 24 deletions.
17 changes: 14 additions & 3 deletions paymentsheet/src/main/java/com/stripe/android/link/LinkActivity.kt
Original file line number Diff line number Diff line change
@@ -7,8 +7,10 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.core.os.bundleOf
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModelProvider
@@ -17,9 +19,11 @@ import com.stripe.android.link.ui.FullScreenContent
import com.stripe.android.link.ui.verification.VerificationDialog
import com.stripe.android.paymentsheet.BuildConfig
import com.stripe.android.uicore.utils.collectAsState
import kotlinx.coroutines.launch

internal class LinkActivity : ComponentActivity() {
@VisibleForTesting
internal var viewModelFactory: ViewModelProvider.Factory = LinkActivityViewModel.factory()

internal var viewModel: LinkActivityViewModel? = null

private var webLauncher: ActivityResultLauncher<LinkActivityContract.Args>? = null
@@ -28,7 +32,7 @@ internal class LinkActivity : ComponentActivity() {
super.onCreate(savedInstanceState)

try {
viewModel = ViewModelProvider(this, LinkActivityViewModel.factory())[LinkActivityViewModel::class.java]
viewModel = ViewModelProvider(this, viewModelFactory)[LinkActivityViewModel::class.java]
} catch (e: NoArgsException) {
Logger.getInstance(BuildConfig.DEBUG).error("Failed to create LinkActivityViewModel", e)
setResult(Activity.RESULT_CANCELED)
@@ -55,13 +59,17 @@ internal class LinkActivity : ComponentActivity() {
when (val state = screenState) {
ScreenState.FullScreen -> {
FullScreenContent(
modifier = Modifier
.testTag(FULL_SCREEN_CONTENT_TAG),
viewModel = vm,
onBackPressed = onBackPressedDispatcher::onBackPressed
)
}
ScreenState.Loading -> Unit
is ScreenState.VerificationDialog -> {
VerificationDialog(
modifier = Modifier
.testTag(VERIFICATION_DIALOG_CONTENT_TAG),
linkAccount = state.linkAccount,
onVerificationSucceeded = vm::onVerificationSucceeded,
onDismissClicked = vm::onDismissVerificationClicked
@@ -113,3 +121,6 @@ internal class LinkActivity : ComponentActivity() {
}
}
}

internal const val FULL_SCREEN_CONTENT_TAG = "full_screen_content_tag"
internal const val VERIFICATION_DIALOG_CONTENT_TAG = "verification_dialog_content_tag"
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.stripe.android.link.ui

import androidx.compose.foundation.layout.Box
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.ModalBottomSheetValue
import androidx.compose.material.rememberModalBottomSheetState
@@ -11,6 +12,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.navigation.compose.rememberNavController
import com.stripe.android.link.LinkActivityViewModel
import com.stripe.android.paymentsheet.utils.EventReporterProvider
@@ -20,6 +22,7 @@ import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterialApi::class)
@Composable
internal fun FullScreenContent(
modifier: Modifier,
viewModel: LinkActivityViewModel,
onBackPressed: () -> Unit
) {
@@ -38,21 +41,25 @@ internal fun FullScreenContent(
}
}

EventReporterProvider(
eventReporter = viewModel.eventReporter
Box(
modifier = modifier
) {
LinkContent(
viewModel = viewModel,
navController = navController,
appBarState = appBarState,
sheetState = sheetState,
bottomSheetContent = bottomSheetContent,
onUpdateSheetContent = {
bottomSheetContent = it
},
onBackPressed = onBackPressed,
moveToWeb = viewModel::moveToWeb
)
EventReporterProvider(
eventReporter = viewModel.eventReporter
) {
LinkContent(
viewModel = viewModel,
navController = navController,
appBarState = appBarState,
sheetState = sheetState,
bottomSheetContent = bottomSheetContent,
onUpdateSheetContent = {
bottomSheetContent = it
},
onBackPressed = onBackPressed,
moveToWeb = viewModel::moveToWeb
)
}
}

LaunchedEffect(Unit) {
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.stripe.android.link.ui.verification

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.stripe.android.link.linkViewModel
@@ -10,6 +12,7 @@ import com.stripe.android.link.theme.DefaultLinkTheme

@Composable
internal fun VerificationDialog(
modifier: Modifier,
linkAccount: LinkAccount,
onVerificationSucceeded: () -> Unit,
onDismissClicked: () -> Unit
@@ -25,13 +28,17 @@ internal fun VerificationDialog(
)
}

Dialog(
onDismissRequest = onDismissClicked
Box(
modifier = modifier
) {
DefaultLinkTheme(
contentShape = RoundedCornerShape(16.dp)
Dialog(
onDismissRequest = onDismissClicked
) {
VerificationScreen(viewModel)
DefaultLinkTheme(
contentShape = RoundedCornerShape(16.dp)
) {
VerificationScreen(viewModel)
}
}
}
}
111 changes: 111 additions & 0 deletions paymentsheet/src/test/java/com/stripe/android/link/LinkActivityTest.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,45 @@
package com.stripe.android.link

import android.app.Activity
import android.content.Context
import android.content.Intent
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.intent.Intents.assertNoUnverifiedIntents
import androidx.test.espresso.intent.rule.IntentsRule
import com.google.common.truth.Truth.assertThat
import com.stripe.android.link.account.FakeLinkAccountManager
import com.stripe.android.link.account.FakeLinkAuth
import com.stripe.android.link.account.LinkAccountManager
import com.stripe.android.link.gate.FakeLinkGate
import com.stripe.android.link.model.AccountStatus
import com.stripe.android.paymentelement.confirmation.FakeConfirmationHandler
import com.stripe.android.paymentsheet.analytics.FakeEventReporter
import com.stripe.android.testing.FakeErrorReporter
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner

@RunWith(RobolectricTestRunner::class)
internal class LinkActivityTest {

@get:Rule
val rule = InstantTaskExecutorRule()

@get:Rule
val composeTestRule = createAndroidComposeRule<LinkActivity>()

private val context = ApplicationProvider.getApplicationContext<Context>()

@get:Rule
val intentsTestRule = IntentsRule()

@@ -29,4 +54,90 @@ internal class LinkActivityTest {
.isEqualTo(Activity.RESULT_CANCELED)
assertNoUnverifiedIntents()
}

@Test
fun `verification dialog is displayed when link screen state is VerificationDialog`() {
val linkAccountManager = FakeLinkAccountManager()
linkAccountManager.setLinkAccount(TestFactory.LINK_ACCOUNT)
linkAccountManager.setAccountStatus(AccountStatus.NeedsVerification)

setupActivityController(
use2faDialog = true,
linkAccountManager = linkAccountManager
)

verificationDialog()
.assertExists()
fullScreenContent()
.assertDoesNotExist()
}

@Test
fun `full screen content is displayed when link screen state is FullScreen`() {
val linkAccountManager = FakeLinkAccountManager()
linkAccountManager.setLinkAccount(TestFactory.LINK_ACCOUNT)
linkAccountManager.setAccountStatus(AccountStatus.NeedsVerification)

setupActivityController(
use2faDialog = false,
linkAccountManager = linkAccountManager
)

verificationDialog()
.assertDoesNotExist()
fullScreenContent()
.assertIsDisplayed()
}

private fun verificationDialog() = composeTestRule
.onNodeWithTag(VERIFICATION_DIALOG_CONTENT_TAG)

private fun fullScreenContent() = composeTestRule
.onNodeWithTag(FULL_SCREEN_CONTENT_TAG)

private fun setupActivityController(
use2faDialog: Boolean = true,
linkAccountManager: LinkAccountManager = FakeLinkAccountManager()
): LinkActivity {
val intent = LinkActivity.createIntent(
context = context,
args = TestFactory.NATIVE_LINK_ARGS.copy(
startWithVerificationDialog = use2faDialog
)
)

val activityController = Robolectric.buildActivity(LinkActivity::class.java, intent)

activityController.get().viewModelFactory = linkViewModelFactory(
use2faDialog = use2faDialog,
linkAccountManager = linkAccountManager
)

return activityController
.create()
.start()
.resume()
.visible()
.get()
}

private fun linkViewModelFactory(
use2faDialog: Boolean = true,
linkAccountManager: LinkAccountManager = FakeLinkAccountManager()
): ViewModelProvider.Factory = viewModelFactory {
initializer {
LinkActivityViewModel(
activityRetainedComponent = FakeNativeLinkComponent(),
confirmationHandlerFactory = { FakeConfirmationHandler() },
linkAccountManager = linkAccountManager,
eventReporter = FakeEventReporter(),
integrityRequestManager = FakeIntegrityRequestManager(),
linkGate = FakeLinkGate(),
errorReporter = FakeErrorReporter(),
linkAuth = FakeLinkAuth(),
linkConfiguration = TestFactory.LINK_CONFIGURATION,
startWithVerificationDialog = use2faDialog
)
}
}
}
Original file line number Diff line number Diff line change
@@ -721,7 +721,7 @@ internal class LinkActivityViewModelTest {
}
}

private class FakeNativeLinkComponent(
internal class FakeNativeLinkComponent(
override val linkAccountManager: LinkAccountManager = FakeLinkAccountManager(),
override val configuration: LinkConfiguration = TestFactory.LINK_CONFIGURATION,
override val linkEventsReporter: LinkEventsReporter = FakeLinkEventsReporter(),
Original file line number Diff line number Diff line change
@@ -177,4 +177,11 @@ internal object TestFactory {
const val SESSION_ID = "element_sessions_123"
val EMAIL_SOURCE = EmailSource.CUSTOMER_OBJECT
val CONSENT_ACTION = ConsumerSignUpConsentAction.Checkbox

val NATIVE_LINK_ARGS = NativeLinkArgs(
configuration = LINK_CONFIGURATION,
publishableKey = "",
stripeAccountId = "",
startWithVerificationDialog = false
)
}
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@ import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import com.stripe.android.core.Logger
import com.stripe.android.core.strings.resolvableString
import com.stripe.android.link.LinkScreen
import com.stripe.android.link.TestFactory
import com.stripe.android.link.account.FakeLinkAccountManager
import com.stripe.android.link.account.LinkAccountManager

0 comments on commit a03ee37

Please sign in to comment.