Fix message backup checkout e2e tests.

This commit is contained in:
Alex Hart
2025-03-13 11:11:24 -03:00
committed by Cody Henthorne
parent fff74256b5
commit 8d53c1b384
7 changed files with 529 additions and 158 deletions

View File

@@ -20,9 +20,12 @@ import assertk.assertions.isEqualTo
import assertk.assertions.isNull
import io.mockk.coEvery
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.mockkStatic
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.StandardTestDispatcher
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -38,9 +41,12 @@ import org.thoughtcrime.securesms.database.InAppPaymentTable
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.net.SignalNetwork
import org.thoughtcrime.securesms.testing.CoroutineDispatcherRule
import org.thoughtcrime.securesms.testing.InAppPaymentsRule
import org.thoughtcrime.securesms.testing.SignalActivityRule
import org.thoughtcrime.securesms.util.RemoteConfig
import org.whispersystems.signalservice.api.NetworkResult
import java.math.BigDecimal
import java.util.Currency
@@ -53,6 +59,10 @@ class MessageBackupsCheckoutActivityTest {
@get:Rule val composeTestRule = createEmptyComposeRule()
private val testDispatcher = StandardTestDispatcher()
@get:Rule val coroutineDispatcherRule = CoroutineDispatcherRule(testDispatcher)
private val purchaseResults = MutableSharedFlow<BillingPurchaseResult>()
@Before
@@ -61,6 +71,11 @@ class MessageBackupsCheckoutActivityTest {
coEvery { AppDependencies.billingApi.queryProduct() } returns BillingProduct(price = FiatMoney(BigDecimal.ONE, Currency.getInstance("USD")))
coEvery { AppDependencies.billingApi.launchBillingFlow(any()) } returns Unit
mockkObject(SignalNetwork)
every { SignalNetwork.archive } returns mockk {
every { triggerBackupIdReservation(any(), any(), any()) } returns NetworkResult.Success(Unit)
}
mockkStatic(RemoteConfig::class)
every { RemoteConfig.messageBackups } returns true
}
@@ -79,6 +94,8 @@ class MessageBackupsCheckoutActivityTest {
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsTypeSelectionScreen__next)).performClick()
composeTestRule.waitForIdle()
testDispatcher.scheduler.advanceUntilIdle()
runBlocking {
purchaseResults.emit(
BillingPurchaseResult.Success(
@@ -94,6 +111,8 @@ class MessageBackupsCheckoutActivityTest {
composeTestRule.waitForIdle()
composeTestRule.onNodeWithTag("dialog-circular-progress-indicator").assertIsDisplayed()
testDispatcher.scheduler.advanceUntilIdle()
val iap = SignalDatabase.inAppPayments.getLatestInAppPaymentByType(InAppPaymentType.RECURRING_BACKUP)
assertThat(iap?.state).isEqualTo(InAppPaymentTable.State.PENDING)
@@ -162,8 +181,11 @@ class MessageBackupsCheckoutActivityTest {
}
private fun launchCheckoutFlow(tier: MessageBackupTier? = null): ActivityScenario<MessageBackupsCheckoutActivity> {
return ActivityScenario.launch(
val scenario = ActivityScenario.launch<MessageBackupsCheckoutActivity>(
MessageBackupsCheckoutActivity.Contract().createIntent(InstrumentationRegistry.getInstrumentation().targetContext, tier)
)
testDispatcher.scheduler.advanceUntilIdle()
return scenario
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.testing
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.test.TestDispatcher
import org.junit.rules.ExternalResource
import org.signal.core.util.concurrent.SignalDispatchers
/**
* Rule that allows for injection of test dispatchers when operating with ViewModels.
*/
class CoroutineDispatcherRule(
defaultDispatcher: TestDispatcher,
mainDispatcher: TestDispatcher = defaultDispatcher,
ioDispatcher: TestDispatcher = defaultDispatcher,
unconfinedDispatcher: TestDispatcher = defaultDispatcher
) : ExternalResource() {
private val testDispatcherProvider = TestDispatcherProvider(
main = mainDispatcher,
io = ioDispatcher,
default = defaultDispatcher,
unconfined = unconfinedDispatcher
)
override fun before() {
SignalDispatchers.setDispatcherProvider(testDispatcherProvider)
}
override fun after() {
SignalDispatchers.setDispatcherProvider()
}
private class TestDispatcherProvider(
override val main: CoroutineDispatcher,
override val io: CoroutineDispatcher,
override val default: CoroutineDispatcher,
override val unconfined: CoroutineDispatcher
) : SignalDispatchers.DispatcherProvider
}