Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FC] Reload Auth Session instead of entire PartnerAuth Pane on cancellations #6837

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import kotlinx.coroutines.launch
import java.util.Date
import javax.inject.Inject
import javax.inject.Named

@Suppress("LongParameterList")
internal class PartnerAuthViewModel @Inject constructor(
private val completeAuthorizationSession: CompleteAuthorizationSession,
Expand All @@ -56,9 +55,14 @@ internal class PartnerAuthViewModel @Inject constructor(
private val logger: Logger,
initialState: PartnerAuthState
) : MavericksViewModel<PartnerAuthState>(initialState) {

init {
logErrors()
observePayload()
createAuthSession()
}

private fun createAuthSession() {
suspend {
val launchedEvent = Launched(Date())
val manifest: FinancialConnectionsSessionManifest = getManifest()
Expand All @@ -78,9 +82,7 @@ internal class PartnerAuthViewModel @Inject constructor(
listOfNotNull(launchedEvent, loadedEvent)
)
}
}.execute {
copy(payload = it)
}
}.execute { copy(payload = it) }
}

private fun observePayload() {
Expand Down Expand Up @@ -182,12 +184,10 @@ internal class PartnerAuthViewModel @Inject constructor(
logger.debug("Creating a new session for this OAuth institution")
// Send retry event as we're presenting the prepane again.
postAuthSessionEvent(authSession.id, AuthSessionEvent.Retry(Date()))
val manifest = getManifest()
val newSession = createAuthorizationSession(
institution = requireNotNull(manifest.activeInstitution),
allowManualEntry = manifest.allowManualEntry
)
goNext(newSession.nextPane)
// for OAuth institutions, we remain on the pre-pane,
// but create a brand new auth session
setState { copy(authenticationStatus = Uninitialized) }
createAuthSession()
} else {
// For OAuth institutions, navigate to Session cancellation's next pane.
postAuthSessionEvent(authSession.id, AuthSessionEvent.Cancel(Date()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ package com.stripe.android.financialconnections.features.partnerauth

import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.test.MvRxTestRule
import com.airbnb.mvrx.test.MavericksTestRule
import com.stripe.android.core.Logger
import com.stripe.android.financialconnections.ApiKeyFixtures.authorizationSession
import com.stripe.android.financialconnections.ApiKeyFixtures.institution
import com.stripe.android.financialconnections.ApiKeyFixtures.sessionManifest
import com.stripe.android.financialconnections.analytics.AuthSessionEvent
import com.stripe.android.financialconnections.domain.CancelAuthorizationSession
import com.stripe.android.financialconnections.domain.CompleteAuthorizationSession
import com.stripe.android.financialconnections.domain.GetManifest
import com.stripe.android.financialconnections.domain.GoNext
import com.stripe.android.financialconnections.domain.PollAuthorizationSessionOAuthResults
import com.stripe.android.financialconnections.domain.PostAuthSessionEvent
import com.stripe.android.financialconnections.domain.PostAuthorizationSession
import com.stripe.android.financialconnections.exception.WebAuthFlowCancelledException
import com.stripe.android.financialconnections.model.MixedOAuthParams
import com.stripe.android.financialconnections.utils.UriUtils
Expand All @@ -23,21 +26,25 @@ import org.junit.Test
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoInteractions
import org.mockito.kotlin.whenever

@OptIn(ExperimentalCoroutinesApi::class)
internal class PartnerAuthViewModelTest {

@get:Rule
val mvrxRule = MvRxTestRule(testDispatcher = UnconfinedTestDispatcher())
val mvrxRule = MavericksTestRule(testDispatcher = UnconfinedTestDispatcher())

private val applicationId = "com.sample.applicationid"
private val getManifest = mock<GetManifest>()
private val postAuthSessionEvent = mock<PostAuthSessionEvent>()
private val pollAuthorizationSessionOAuthResults = mock<PollAuthorizationSessionOAuthResults>()
private val completeAuthorizationSession = mock<CompleteAuthorizationSession>()
private val cancelAuthorizationSession = mock<CancelAuthorizationSession>()
private val goNext = mock<GoNext>()
private val createAuthorizationSession = mock<PostAuthorizationSession>()

@Test
fun `onWebAuthFlowFinished - when webStatus Success, polls accounts and authorizes with token`() =
Expand Down Expand Up @@ -86,27 +93,38 @@ internal class PartnerAuthViewModelTest {
}

@Test
fun `onWebAuthFlowFinished - when webStatus Cancelled, cancels fires retry event (OAuth)`() = runTest {
val activeAuthSession = authorizationSession()
val viewModel = createViewModel()

whenever(getManifest())
.thenReturn(
sessionManifest().copy(
activeAuthSession = activeAuthSession.copy(_isOAuth = true)
)
fun `onWebAuthFlowFinished - when webStatus Cancelled, cancels, reloads session and fires retry event (OAuth)`() =
runTest {
val activeAuthSession = authorizationSession()
val activeInstitution = institution()
val manifest = sessionManifest().copy(
activeAuthSession = activeAuthSession.copy(_isOAuth = true),
activeInstitution = activeInstitution
)

viewModel.onWebAuthFlowFinished(Fail(WebAuthFlowCancelledException()))
whenever(getManifest()).thenReturn(manifest)
whenever(createAuthorizationSession.invoke(any(), any())).thenReturn(activeAuthSession)

verify(cancelAuthorizationSession).invoke(
eq(activeAuthSession.id),
)
verify(postAuthSessionEvent).invoke(
eq(activeAuthSession.id),
any<AuthSessionEvent.Retry>()
)
}
val viewModel = createViewModel()
viewModel.onWebAuthFlowFinished(Fail(WebAuthFlowCancelledException()))

verify(cancelAuthorizationSession).invoke(eq(activeAuthSession.id),)

// stays in partner auth pane
verifyNoInteractions(goNext)

// creates two sessions (initial and retry)
verify(createAuthorizationSession, times(2)).invoke(
eq(activeInstitution),
eq(manifest.allowManualEntry)
)

// sends retry event
verify(postAuthSessionEvent).invoke(
eq(activeAuthSession.id),
any<AuthSessionEvent.Retry>()
)
}

@Test
fun `onWebAuthFlowFinished - when webStatus Cancelled, cancels and fires cancel event (Legacy)`() =
Expand Down Expand Up @@ -137,12 +155,12 @@ internal class PartnerAuthViewModelTest {
): PartnerAuthViewModel {
return PartnerAuthViewModel(
completeAuthorizationSession = completeAuthorizationSession,
createAuthorizationSession = mock(),
createAuthorizationSession = createAuthorizationSession,
cancelAuthorizationSession = cancelAuthorizationSession,
eventTracker = mock(),
postAuthSessionEvent = postAuthSessionEvent,
getManifest = getManifest,
goNext = mock(),
goNext = goNext,
navigationManager = mock(),
pollAuthorizationSessionOAuthResults = pollAuthorizationSessionOAuthResults,
logger = mock(),
Expand Down