Skip to content

Commit

Permalink
Correctly increment scan counters (#5251)
Browse files Browse the repository at this point in the history
  • Loading branch information
ccen-stripe committed Jul 6, 2022
1 parent 0259855 commit 06f1967
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 48 deletions.
Expand Up @@ -183,43 +183,43 @@ internal abstract class IdentityCameraScanFragment(
/**
* Start scanning for the required scan type.
*/
protected fun startScanning(scanType: IdentityScanState.ScanType) {
internal fun startScanning(scanType: IdentityScanState.ScanType) {
identityViewModel.updateAnalyticsState { oldState ->
when (scanType) {
IdentityScanState.ScanType.ID_FRONT -> {
oldState.copy(
docFrontRetryTimes =
oldState.docFrontRetryTimes?.let { it + 1 } ?: 0
oldState.docFrontRetryTimes?.let { it + 1 } ?: 1
)
}
IdentityScanState.ScanType.ID_BACK -> {
oldState.copy(
docFrontRetryTimes =
oldState.docFrontRetryTimes?.let { it + 1 } ?: 0
docBackRetryTimes =
oldState.docBackRetryTimes?.let { it + 1 } ?: 1
)
}
IdentityScanState.ScanType.DL_FRONT -> {
oldState.copy(
docFrontRetryTimes =
oldState.docFrontRetryTimes?.let { it + 1 } ?: 0
oldState.docFrontRetryTimes?.let { it + 1 } ?: 1
)
}
IdentityScanState.ScanType.DL_BACK -> {
oldState.copy(
docFrontRetryTimes =
oldState.docFrontRetryTimes?.let { it + 1 } ?: 0
docBackRetryTimes =
oldState.docBackRetryTimes?.let { it + 1 } ?: 1
)
}
IdentityScanState.ScanType.PASSPORT -> {
oldState.copy(
docFrontRetryTimes =
oldState.docFrontRetryTimes?.let { it + 1 } ?: 0
oldState.docFrontRetryTimes?.let { it + 1 } ?: 1
)
}
IdentityScanState.ScanType.SELFIE -> {
oldState.copy(
selfieRetryTimes =
oldState.selfieRetryTimes?.let { it + 1 } ?: 0
oldState.selfieRetryTimes?.let { it + 1 } ?: 1
)
}
}
Expand Down
Expand Up @@ -14,6 +14,7 @@ import androidx.navigation.testing.TestNavHostController
import androidx.test.core.app.ApplicationProvider
import com.google.common.truth.Truth.assertThat
import com.stripe.android.camera.Camera1Adapter
import com.stripe.android.camera.scanui.CameraView
import com.stripe.android.identity.R
import com.stripe.android.identity.SUCCESS_VERIFICATION_PAGE_NOT_REQUIRE_LIVE_CAPTURE
import com.stripe.android.identity.analytics.AnalyticsState
Expand Down Expand Up @@ -42,6 +43,7 @@ import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.robolectric.RobolectricTestRunner
Expand Down Expand Up @@ -161,55 +163,100 @@ class IdentityCameraScanFragmentTest {
}
}

private fun launchTestFragmentWithFinalResult(
finalResult: IdentityAggregator.FinalResult,
testBlock: () -> Unit
) =
launchFragmentInContainer(
themeResId = R.style.Theme_MaterialComponents
) {
TestFragment(
viewModelFactoryFor(mockIdentityScanViewModel),
viewModelFactoryFor(mockIdentityViewModel)
)
}.onFragment {
val navController = TestNavHostController(
ApplicationProvider.getApplicationContext()
@Test
fun `when startScanning update analytics`() {
launchTestFragment().onFragment {
it.startScanning(IdentityScanState.ScanType.ID_FRONT)

val updateBlockCaptor: KArgumentCaptor<(AnalyticsState) -> AnalyticsState> =
argumentCaptor()
verify(mockIdentityViewModel).updateAnalyticsState(
updateBlockCaptor.capture()
)
navController.setGraph(
R.navigation.identity_nav_graph
var analyticsState = updateBlockCaptor.lastValue(AnalyticsState())
assertThat(analyticsState.docFrontRetryTimes).isEqualTo(1)
assertThat(analyticsState.docBackRetryTimes).isNull()
assertThat(analyticsState.selfieRetryTimes).isNull()

it.startScanning(IdentityScanState.ScanType.ID_FRONT)
verify(mockIdentityViewModel, times(2)).updateAnalyticsState(
updateBlockCaptor.capture()
)
navController.setCurrentDestination(R.id.IDScanFragment)
Navigation.setViewNavController(
it.requireView(),
navController
analyticsState = updateBlockCaptor.lastValue(analyticsState)
assertThat(analyticsState.docFrontRetryTimes).isEqualTo(2)
assertThat(analyticsState.docBackRetryTimes).isNull()
assertThat(analyticsState.selfieRetryTimes).isNull()

it.startScanning(IdentityScanState.ScanType.ID_BACK)
verify(mockIdentityViewModel, times(3)).updateAnalyticsState(
updateBlockCaptor.capture()
)
analyticsState = updateBlockCaptor.lastValue(analyticsState)
assertThat(analyticsState.docFrontRetryTimes).isEqualTo(2)
assertThat(analyticsState.docBackRetryTimes).isEqualTo(1)
assertThat(analyticsState.selfieRetryTimes).isNull()

finalResultLiveData.postValue(
finalResult
it.startScanning(IdentityScanState.ScanType.SELFIE)
verify(mockIdentityViewModel, times(4)).updateAnalyticsState(
updateBlockCaptor.capture()
)
analyticsState = updateBlockCaptor.lastValue(analyticsState)
assertThat(analyticsState.docFrontRetryTimes).isEqualTo(2)
assertThat(analyticsState.docBackRetryTimes).isEqualTo(1)
assertThat(analyticsState.selfieRetryTimes).isEqualTo(1)
}
}

runBlocking {
verify(mockFPSTracker).reportAndReset(
if (finalResult.result is FaceDetectorOutput) {
eq(IdentityAnalyticsRequestFactory.TYPE_SELFIE)
} else {
eq(IdentityAnalyticsRequestFactory.TYPE_DOCUMENT)
}
)
}
private fun launchTestFragment() = launchFragmentInContainer(
themeResId = R.style.Theme_MaterialComponents
) {
TestFragment(
viewModelFactoryFor(mockIdentityScanViewModel),
viewModelFactoryFor(mockIdentityViewModel)
)
}

val successCaptor: KArgumentCaptor<(VerificationPage) -> Unit> = argumentCaptor()
verify(mockIdentityViewModel).observeForVerificationPage(
any(),
successCaptor.capture(),
any()
)
successCaptor.firstValue(SUCCESS_VERIFICATION_PAGE_NOT_REQUIRE_LIVE_CAPTURE)
private fun launchTestFragmentWithFinalResult(
finalResult: IdentityAggregator.FinalResult,
testBlock: () -> Unit
) = launchTestFragment().onFragment {
val navController = TestNavHostController(
ApplicationProvider.getApplicationContext()
)
navController.setGraph(
R.navigation.identity_nav_graph
)
navController.setCurrentDestination(R.id.IDScanFragment)
Navigation.setViewNavController(
it.requireView(),
navController
)

testBlock()
finalResultLiveData.postValue(
finalResult
)

runBlocking {
verify(mockFPSTracker).reportAndReset(
if (finalResult.result is FaceDetectorOutput) {
eq(IdentityAnalyticsRequestFactory.TYPE_SELFIE)
} else {
eq(IdentityAnalyticsRequestFactory.TYPE_DOCUMENT)
}
)
}

val successCaptor: KArgumentCaptor<(VerificationPage) -> Unit> = argumentCaptor()
verify(mockIdentityViewModel).observeForVerificationPage(
any(),
successCaptor.capture(),
any()
)
successCaptor.firstValue(SUCCESS_VERIFICATION_PAGE_NOT_REQUIRE_LIVE_CAPTURE)

testBlock()
}

internal class TestFragment(
identityScanViewModelFactory: ViewModelProvider.Factory,
identityViewModelFactory: ViewModelProvider.Factory
Expand All @@ -231,6 +278,9 @@ class IdentityCameraScanFragmentTest {
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
cameraView = mock<CameraView>().also {
whenever(it.viewFinderWindowView).thenReturn(mock())
}
return View(ApplicationProvider.getApplicationContext())
}

Expand Down

0 comments on commit 06f1967

Please sign in to comment.