Skip to content

Commit

Permalink
Add screenshot tests for add screens. (stripe#9167)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaynewstrom-stripe authored Sep 3, 2024
1 parent 504a714 commit 1f2f3a5
Show file tree
Hide file tree
Showing 19 changed files with 263 additions and 123 deletions.
1 change: 1 addition & 0 deletions bitrise.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ workflows:
- opts:
is_expand: false
NEEDS_ROBOLECTRIC: true
- INCLUDE_PAPARAZZI_ON_FAILURE: true
before_run:
- prepare_all
after_run:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ package com.stripe.android.testing
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.junit.rules.TestWatcher
import org.junit.runner.Description

@ExperimentalCoroutinesApi
class CoroutineTestRule(
private val testDispatcher: TestDispatcher,
private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(),
) : TestWatcher() {

override fun starting(description: Description) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.stripe.android.paymentsheet.navigation

import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.stripe.android.core.strings.resolvableString
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadataFactory
import com.stripe.android.paymentsheet.navigation.PaymentSheetScreen.AddAnotherPaymentMethod
import com.stripe.android.paymentsheet.ui.FakeAddPaymentMethodInteractor
import com.stripe.android.paymentsheet.ui.FakeAddPaymentMethodInteractor.Companion.createState
import com.stripe.android.paymentsheet.ui.PaymentSheetFlowType
import com.stripe.android.paymentsheet.ui.PaymentSheetScreen
import com.stripe.android.paymentsheet.utils.ViewModelStoreOwnerContext
import com.stripe.android.paymentsheet.viewmodels.FakeBaseSheetViewModel
import com.stripe.android.screenshottesting.PaparazziRule
import com.stripe.android.testing.CoroutineTestRule
import org.junit.Rule
import org.junit.Test

internal class PaymentSheetScreenAddAnotherPaymentMethodScreenshotTest {
@get:Rule
val paparazziRule = PaparazziRule(
boxModifier = Modifier
.padding(16.dp)
)

@get:Rule
val coroutineRule = CoroutineTestRule()

@Test
fun displaysCard() {
val metadata = PaymentMethodMetadataFactory.create()
val interactor = FakeAddPaymentMethodInteractor(initialState = createState())
val initialScreen = AddAnotherPaymentMethod(interactor)
val viewModel = FakeBaseSheetViewModel.create(metadata, initialScreen)

paparazziRule.snapshot {
ViewModelStoreOwnerContext {
PaymentSheetScreen(viewModel = viewModel, type = PaymentSheetFlowType.Complete)
}
}
}

@Test
fun displaysError() {
val metadata = PaymentMethodMetadataFactory.create()
val interactor = FakeAddPaymentMethodInteractor(initialState = createState())
val initialScreen = AddAnotherPaymentMethod(interactor)
val viewModel = FakeBaseSheetViewModel.create(metadata, initialScreen)
viewModel.onError("An error occurred.".resolvableString)

paparazziRule.snapshot {
ViewModelStoreOwnerContext {
PaymentSheetScreen(viewModel = viewModel, type = PaymentSheetFlowType.Complete)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,24 @@ package com.stripe.android.paymentsheet.navigation
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import com.stripe.android.core.strings.resolvableString
import com.stripe.android.lpmfoundations.luxe.LpmRepositoryTestHelpers
import com.stripe.android.lpmfoundations.luxe.SupportedPaymentMethod
import com.stripe.android.model.PaymentMethod
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadataFactory
import com.stripe.android.model.PaymentIntentFixtures
import com.stripe.android.paymentsheet.R
import com.stripe.android.paymentsheet.ui.AddPaymentMethodInteractor
import com.stripe.android.uicore.utils.stateFlowOf
import com.stripe.android.paymentsheet.ui.FakeAddPaymentMethodInteractor
import com.stripe.android.paymentsheet.ui.FakeAddPaymentMethodInteractor.Companion.createState
import com.stripe.android.testing.CoroutineTestRule
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
import org.mockito.kotlin.mock
import com.stripe.android.R as PaymentsCoreR

internal class PaymentSheetScreenAddAnotherPaymentMethodTest {
@get:Rule
val coroutineRule = CoroutineTestRule()

@Test
fun `title returns null when isWalletEnabled`() = runTest {
val interactor = FakeAddPaymentMethodInteractor(stateFlowOf(createState()))
val interactor = FakeAddPaymentMethodInteractor(createState())
PaymentSheetScreen.AddAnotherPaymentMethod(interactor)
.title(isCompleteFlow = false, isWalletEnabled = true).test {
assertThat(awaitItem()).isNull()
Expand All @@ -27,7 +29,7 @@ internal class PaymentSheetScreenAddAnotherPaymentMethodTest {

@Test
fun `title returns null when isCompleteFlow`() = runTest {
val interactor = FakeAddPaymentMethodInteractor(stateFlowOf(createState()))
val interactor = FakeAddPaymentMethodInteractor(createState())
PaymentSheetScreen.AddAnotherPaymentMethod(interactor)
.title(isCompleteFlow = true, isWalletEnabled = false).test {
assertThat(awaitItem()).isNull()
Expand All @@ -36,8 +38,14 @@ internal class PaymentSheetScreenAddAnotherPaymentMethodTest {

@Test
fun `title returns add card with one supported payment method`() = runTest {
val state = createState(supportedPaymentMethods = listOf(LpmRepositoryTestHelpers.card))
val interactor = FakeAddPaymentMethodInteractor(stateFlowOf(state))
val state = createState(
metadata = PaymentMethodMetadataFactory.create(
stripeIntent = PaymentIntentFixtures.PI_REQUIRES_PAYMENT_METHOD.copy(
paymentMethodTypes = listOf("card")
)
)
)
val interactor = FakeAddPaymentMethodInteractor(state)
PaymentSheetScreen.AddAnotherPaymentMethod(interactor)
.title(isCompleteFlow = false, isWalletEnabled = false).test {
assertThat(awaitItem()).isEqualTo(PaymentsCoreR.string.stripe_title_add_a_card.resolvableString)
Expand All @@ -46,8 +54,15 @@ internal class PaymentSheetScreenAddAnotherPaymentMethodTest {

@Test
fun `title returns choose payment method with non card one supported payment method`() = runTest {
val state = createState(supportedPaymentMethods = listOf(LpmRepositoryTestHelpers.usBankAccount))
val interactor = FakeAddPaymentMethodInteractor(stateFlowOf(state))
val state = createState(
metadata = PaymentMethodMetadataFactory.create(
stripeIntent = PaymentIntentFixtures.PI_REQUIRES_PAYMENT_METHOD.copy(
paymentMethodTypes = listOf("us_bank_account"),
clientSecret = null,
),
)
)
val interactor = FakeAddPaymentMethodInteractor(state)
PaymentSheetScreen.AddAnotherPaymentMethod(interactor)
.title(isCompleteFlow = false, isWalletEnabled = false).test {
assertThat(awaitItem()).isEqualTo(R.string.stripe_paymentsheet_choose_payment_method.resolvableString)
Expand All @@ -56,27 +71,10 @@ internal class PaymentSheetScreenAddAnotherPaymentMethodTest {

@Test
fun `title returns choose payment method with more than one supported payment method`() = runTest {
val interactor = FakeAddPaymentMethodInteractor(stateFlowOf(createState()))
val interactor = FakeAddPaymentMethodInteractor(createState())
PaymentSheetScreen.AddAnotherPaymentMethod(interactor)
.title(isCompleteFlow = false, isWalletEnabled = false).test {
assertThat(awaitItem()).isEqualTo(R.string.stripe_paymentsheet_choose_payment_method.resolvableString)
}
}

private fun createState(
supportedPaymentMethods: List<SupportedPaymentMethod> = listOf(
LpmRepositoryTestHelpers.card,
LpmRepositoryTestHelpers.usBankAccount,
),
): AddPaymentMethodInteractor.State {
return AddPaymentMethodInteractor.State(
selectedPaymentMethodCode = PaymentMethod.Type.Card.code,
supportedPaymentMethods = supportedPaymentMethods,
arguments = mock(),
formElements = emptyList(),
paymentSelection = null,
processing = false,
usBankAccountFormArguments = mock(),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.stripe.android.paymentsheet.navigation

import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.stripe.android.core.strings.resolvableString
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadataFactory
import com.stripe.android.paymentsheet.navigation.PaymentSheetScreen.AddFirstPaymentMethod
import com.stripe.android.paymentsheet.ui.FakeAddPaymentMethodInteractor
import com.stripe.android.paymentsheet.ui.FakeAddPaymentMethodInteractor.Companion.createState
import com.stripe.android.paymentsheet.ui.PaymentSheetFlowType
import com.stripe.android.paymentsheet.ui.PaymentSheetScreen
import com.stripe.android.paymentsheet.utils.ViewModelStoreOwnerContext
import com.stripe.android.paymentsheet.viewmodels.FakeBaseSheetViewModel
import com.stripe.android.screenshottesting.PaparazziRule
import com.stripe.android.testing.CoroutineTestRule
import org.junit.Rule
import org.junit.Test

internal class PaymentSheetScreenAddFirstPaymentMethodScreenshotTest {
@get:Rule
val paparazziRule = PaparazziRule(
boxModifier = Modifier
.padding(16.dp)
)

@get:Rule
val coroutineRule = CoroutineTestRule()

@Test
fun displaysCard() {
val metadata = PaymentMethodMetadataFactory.create()
val interactor = FakeAddPaymentMethodInteractor(initialState = createState())
val initialScreen = AddFirstPaymentMethod(interactor)
val viewModel = FakeBaseSheetViewModel.create(metadata, initialScreen)

paparazziRule.snapshot {
ViewModelStoreOwnerContext {
PaymentSheetScreen(viewModel = viewModel, type = PaymentSheetFlowType.Complete)
}
}
}

@Test
fun displaysError() {
val metadata = PaymentMethodMetadataFactory.create()
val interactor = FakeAddPaymentMethodInteractor(initialState = createState())
val initialScreen = AddFirstPaymentMethod(interactor)
val viewModel = FakeBaseSheetViewModel.create(metadata, initialScreen)
viewModel.onError("An error occurred.".resolvableString)

paparazziRule.snapshot {
ViewModelStoreOwnerContext {
PaymentSheetScreen(viewModel = viewModel, type = PaymentSheetFlowType.Complete)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,24 @@ package com.stripe.android.paymentsheet.navigation
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import com.stripe.android.core.strings.resolvableString
import com.stripe.android.lpmfoundations.luxe.LpmRepositoryTestHelpers
import com.stripe.android.lpmfoundations.luxe.SupportedPaymentMethod
import com.stripe.android.model.PaymentMethod
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadataFactory
import com.stripe.android.model.PaymentIntentFixtures
import com.stripe.android.paymentsheet.R
import com.stripe.android.paymentsheet.ui.AddPaymentMethodInteractor
import com.stripe.android.uicore.utils.stateFlowOf
import com.stripe.android.paymentsheet.ui.FakeAddPaymentMethodInteractor
import com.stripe.android.paymentsheet.ui.FakeAddPaymentMethodInteractor.Companion.createState
import com.stripe.android.testing.CoroutineTestRule
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
import org.mockito.kotlin.mock
import com.stripe.android.R as PaymentsCoreR

internal class PaymentSheetScreenAddFirstPaymentMethodTest {
@get:Rule
val coroutineRule = CoroutineTestRule()

@Test
fun `title returns null when isWalletEnabled`() = runTest {
val interactor = FakeAddPaymentMethodInteractor(stateFlowOf(createState()))
val interactor = FakeAddPaymentMethodInteractor(createState())
PaymentSheetScreen.AddFirstPaymentMethod(interactor)
.title(isCompleteFlow = false, isWalletEnabled = true).test {
assertThat(awaitItem()).isNull()
Expand All @@ -27,7 +29,7 @@ internal class PaymentSheetScreenAddFirstPaymentMethodTest {

@Test
fun `title returns add payment method when isCompleteFlow`() = runTest {
val interactor = FakeAddPaymentMethodInteractor(stateFlowOf(createState()))
val interactor = FakeAddPaymentMethodInteractor(createState())
PaymentSheetScreen.AddFirstPaymentMethod(interactor)
.title(isCompleteFlow = true, isWalletEnabled = false).test {
assertThat(awaitItem())
Expand All @@ -37,8 +39,14 @@ internal class PaymentSheetScreenAddFirstPaymentMethodTest {

@Test
fun `title returns add card with one supported payment method`() = runTest {
val state = createState(supportedPaymentMethods = listOf(LpmRepositoryTestHelpers.card))
val interactor = FakeAddPaymentMethodInteractor(stateFlowOf(state))
val state = createState(
metadata = PaymentMethodMetadataFactory.create(
stripeIntent = PaymentIntentFixtures.PI_REQUIRES_PAYMENT_METHOD.copy(
paymentMethodTypes = listOf("card")
)
)
)
val interactor = FakeAddPaymentMethodInteractor(state)
PaymentSheetScreen.AddFirstPaymentMethod(interactor)
.title(isCompleteFlow = false, isWalletEnabled = false).test {
assertThat(awaitItem()).isEqualTo(PaymentsCoreR.string.stripe_title_add_a_card.resolvableString)
Expand All @@ -47,8 +55,15 @@ internal class PaymentSheetScreenAddFirstPaymentMethodTest {

@Test
fun `title returns choose payment method with non card one supported payment method`() = runTest {
val state = createState(supportedPaymentMethods = listOf(LpmRepositoryTestHelpers.usBankAccount))
val interactor = FakeAddPaymentMethodInteractor(stateFlowOf(state))
val state = createState(
metadata = PaymentMethodMetadataFactory.create(
stripeIntent = PaymentIntentFixtures.PI_REQUIRES_PAYMENT_METHOD.copy(
paymentMethodTypes = listOf("us_bank_account"),
clientSecret = null,
),
)
)
val interactor = FakeAddPaymentMethodInteractor(state)
PaymentSheetScreen.AddFirstPaymentMethod(interactor)
.title(isCompleteFlow = false, isWalletEnabled = false).test {
assertThat(awaitItem()).isEqualTo(R.string.stripe_paymentsheet_choose_payment_method.resolvableString)
Expand All @@ -57,27 +72,10 @@ internal class PaymentSheetScreenAddFirstPaymentMethodTest {

@Test
fun `title returns choose payment method with more than one supported payment method`() = runTest {
val interactor = FakeAddPaymentMethodInteractor(stateFlowOf(createState()))
val interactor = FakeAddPaymentMethodInteractor(createState())
PaymentSheetScreen.AddFirstPaymentMethod(interactor)
.title(isCompleteFlow = false, isWalletEnabled = false).test {
assertThat(awaitItem()).isEqualTo(R.string.stripe_paymentsheet_choose_payment_method.resolvableString)
}
}

private fun createState(
supportedPaymentMethods: List<SupportedPaymentMethod> = listOf(
LpmRepositoryTestHelpers.card,
LpmRepositoryTestHelpers.usBankAccount,
),
): AddPaymentMethodInteractor.State {
return AddPaymentMethodInteractor.State(
selectedPaymentMethodCode = PaymentMethod.Type.Card.code,
supportedPaymentMethods = supportedPaymentMethods,
arguments = mock(),
formElements = emptyList(),
paymentSelection = null,
processing = false,
usBankAccountFormArguments = mock(),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import com.stripe.android.paymentsheet.viewmodels.FakeBaseSheetViewModel
import com.stripe.android.screenshottesting.PaparazziRule
import com.stripe.android.testing.CoroutineTestRule
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import org.junit.Rule
import org.junit.Test

Expand All @@ -23,7 +22,7 @@ internal class PaymentSheetScreenLoadingScreenshotTest {
)

@get:Rule
val coroutineRule = CoroutineTestRule(UnconfinedTestDispatcher())
val coroutineRule = CoroutineTestRule()

@Test
fun displaysLoading() {
Expand Down
Loading

0 comments on commit 1f2f3a5

Please sign in to comment.