mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-23 20:48:43 +00:00
MessageBackupsCheckoutFlow free tier happy path.
This commit is contained in:
committed by
Greyson Parrelli
parent
bc09df97b0
commit
4c72a88a50
@@ -0,0 +1,118 @@
|
||||
package org.thoughtcrime.securesms.backup.v2.ui.subscription
|
||||
|
||||
import android.content.ClipboardManager
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsEnabled
|
||||
import androidx.compose.ui.test.assertIsNotEnabled
|
||||
import androidx.compose.ui.test.hasText
|
||||
import androidx.compose.ui.test.junit4.createEmptyComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollToNode
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import assertk.assertions.isNull
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
import io.mockk.mockkStatic
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.signal.core.util.billing.BillingProduct
|
||||
import org.signal.core.util.billing.BillingPurchaseResult
|
||||
import org.signal.core.util.money.FiatMoney
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.testing.InAppPaymentsRule
|
||||
import org.thoughtcrime.securesms.testing.SignalActivityRule
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import java.math.BigDecimal
|
||||
import java.util.Currency
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class MessageBackupsCheckoutActivityTest {
|
||||
|
||||
@get:Rule val activityRule = SignalActivityRule()
|
||||
|
||||
@get:Rule val iapRule = InAppPaymentsRule()
|
||||
|
||||
@get:Rule val composeTestRule = createEmptyComposeRule()
|
||||
|
||||
private val purchaseResults = MutableSharedFlow<BillingPurchaseResult>()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
every { AppDependencies.billingApi.getBillingPurchaseResults() } returns purchaseResults
|
||||
coEvery { AppDependencies.billingApi.queryProduct() } returns BillingProduct(price = FiatMoney(BigDecimal.ONE, Currency.getInstance("USD")))
|
||||
|
||||
mockkStatic(RemoteConfig::class)
|
||||
every { RemoteConfig.messageBackups } returns true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun e2e_happy_path() {
|
||||
val scenario = launchCheckoutFlow()
|
||||
val context = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
|
||||
assertThat(SignalStore.backup.backupTier).isNull()
|
||||
|
||||
// Backup education screen
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.RemoteBackupsSettingsFragment__signal_backups)).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsEducationScreen__enable_backups)).performClick()
|
||||
|
||||
// Key education screen
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsKeyEducationScreen__your_backup_key)).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsKeyRecordScreen__next)).performClick()
|
||||
|
||||
// Key record screen
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsKeyRecordScreen__record_your_backup_key)).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag("message-backups-key-record-screen-lazy-column")
|
||||
.performScrollToNode(hasText(context.getString(R.string.MessageBackupsKeyRecordScreen__copy_to_clipboard)))
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsKeyRecordScreen__copy_to_clipboard)).performClick()
|
||||
|
||||
scenario.onActivity {
|
||||
val backupKeyString = SignalStore.account.accountEntropyPool.value.chunked(4).joinToString(" ")
|
||||
val clipboardManager = ContextCompat.getSystemService(context, ClipboardManager::class.java)
|
||||
assertThat(clipboardManager?.primaryClip?.getItemAt(0)?.coerceToText(context)).isEqualTo(backupKeyString)
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsKeyRecordScreen__next)).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsKeyRecordScreen__next)).performClick()
|
||||
|
||||
// Key record bottom sheet
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsKeyRecordScreen__keep_your_key_safe)).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag("message-backups-key-record-screen-sheet-content")
|
||||
.performScrollToNode(hasText(context.getString(R.string.MessageBackupsKeyRecordScreen__continue)))
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsKeyRecordScreen__continue)).assertIsNotEnabled()
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsKeyRecordScreen__ive_recorded_my_key)).performClick()
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsKeyRecordScreen__continue)).assertIsEnabled()
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsKeyRecordScreen__continue)).performClick()
|
||||
|
||||
// Type selection screen
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessagesBackupsTypeSelectionScreen__choose_your_backup_plan)).assertIsDisplayed()
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsTypeSelectionScreen__next)).assertIsNotEnabled()
|
||||
composeTestRule.onNodeWithTag("message-backups-type-selection-screen-lazy-column")
|
||||
.performScrollToNode(hasText(context.getString(R.string.MessageBackupsTypeSelectionScreen__free)))
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsTypeSelectionScreen__free)).performClick()
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsTypeSelectionScreen__next)).assertIsEnabled()
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsTypeSelectionScreen__next)).performClick()
|
||||
composeTestRule.waitForIdle()
|
||||
|
||||
assertThat(SignalStore.backup.backupTier).isEqualTo(MessageBackupTier.FREE)
|
||||
}
|
||||
|
||||
private fun launchCheckoutFlow(tier: MessageBackupTier? = null): ActivityScenario<MessageBackupsCheckoutActivity> {
|
||||
return ActivityScenario.launch(
|
||||
MessageBackupsCheckoutActivity.Contract().createIntent(InstrumentationRegistry.getInstrumentation().targetContext, tier)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -24,13 +24,12 @@ import org.thoughtcrime.securesms.dependencies.InstrumentationApplicationDepende
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.testing.Delete
|
||||
import org.thoughtcrime.securesms.testing.Get
|
||||
import org.thoughtcrime.securesms.testing.InAppPaymentsRule
|
||||
import org.thoughtcrime.securesms.testing.SignalActivityRule
|
||||
import org.thoughtcrime.securesms.testing.actions.RecyclerViewScrollToBottomAction
|
||||
import org.thoughtcrime.securesms.testing.success
|
||||
import org.thoughtcrime.securesms.util.JsonUtils
|
||||
import org.whispersystems.signalservice.api.subscriptions.ActiveSubscription
|
||||
import org.whispersystems.signalservice.api.subscriptions.SubscriberId
|
||||
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration
|
||||
import java.math.BigDecimal
|
||||
import java.util.Currency
|
||||
import kotlin.time.Duration.Companion.days
|
||||
@@ -42,6 +41,9 @@ class CheckoutFlowActivityTest__RecurringDonations {
|
||||
@get:Rule
|
||||
val harness = SignalActivityRule(othersCount = 10)
|
||||
|
||||
@get:Rule
|
||||
val iapRule = InAppPaymentsRule()
|
||||
|
||||
private val intent = CheckoutFlowActivity.createIntent(InstrumentationRegistry.getInstrumentation().targetContext, InAppPaymentType.RECURRING_DONATION)
|
||||
|
||||
@Test
|
||||
@@ -59,7 +61,6 @@ class CheckoutFlowActivityTest__RecurringDonations {
|
||||
|
||||
@Test
|
||||
fun givenACurrentDonation_whenILoadScreen_thenIExpectUpgradeButton() {
|
||||
initialiseConfigurationResponse()
|
||||
initialiseActiveSubscription()
|
||||
|
||||
ActivityScenario.launch<CheckoutFlowActivity>(intent)
|
||||
@@ -71,7 +72,6 @@ class CheckoutFlowActivityTest__RecurringDonations {
|
||||
|
||||
@Test
|
||||
fun givenACurrentDonation_whenIPressCancel_thenIExpectCancellationDialog() {
|
||||
initialiseConfigurationResponse()
|
||||
initialiseActiveSubscription()
|
||||
|
||||
ActivityScenario.launch<CheckoutFlowActivity>(intent)
|
||||
@@ -85,7 +85,6 @@ class CheckoutFlowActivityTest__RecurringDonations {
|
||||
|
||||
@Test
|
||||
fun givenAPendingRecurringDonation_whenILoadScreen_thenIExpectDisabledUpgradeButton() {
|
||||
initialiseConfigurationResponse()
|
||||
initialisePendingSubscription()
|
||||
|
||||
ActivityScenario.launch<CheckoutFlowActivity>(intent)
|
||||
@@ -94,17 +93,6 @@ class CheckoutFlowActivityTest__RecurringDonations {
|
||||
onView(withText(R.string.SubscribeFragment__update_subscription)).check(matches(isNotEnabled()))
|
||||
}
|
||||
|
||||
private fun initialiseConfigurationResponse() {
|
||||
InstrumentationApplicationDependencyProvider.addMockWebRequestHandlers(
|
||||
Get("/v1/subscription/configuration") {
|
||||
val assets = InstrumentationRegistry.getInstrumentation().context.resources.assets
|
||||
assets.open("inAppPaymentsTests/configuration.json").use { stream ->
|
||||
MockResponse().success(JsonUtils.fromJson(stream, SubscriptionsConfiguration::class.java))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun initialiseActiveSubscription() {
|
||||
val currency = Currency.getInstance("USD")
|
||||
val subscriber = InAppPaymentSubscriberRecord(
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.testing
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
import org.junit.rules.ExternalResource
|
||||
import org.thoughtcrime.securesms.dependencies.InstrumentationApplicationDependencyProvider
|
||||
import org.thoughtcrime.securesms.util.JsonUtils
|
||||
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration
|
||||
|
||||
/**
|
||||
* Sets up some common infrastructure for on-device InAppPayment testing
|
||||
*/
|
||||
class InAppPaymentsRule : ExternalResource() {
|
||||
override fun before() {
|
||||
initialiseConfigurationResponse()
|
||||
}
|
||||
|
||||
private fun initialiseConfigurationResponse() {
|
||||
InstrumentationApplicationDependencyProvider.addMockWebRequestHandlers(
|
||||
Get("/v1/subscription/configuration") {
|
||||
val assets = InstrumentationRegistry.getInstrumentation().context.resources.assets
|
||||
assets.open("inAppPaymentsTests/configuration.json").use { stream ->
|
||||
MockResponse().success(JsonUtils.fromJson(stream, SubscriptionsConfiguration::class.java))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user