Skip to content

Commit

Permalink
Merge pull request #2359 from HedvigInsurance/feature/addon-tests
Browse files Browse the repository at this point in the history
Feature/addon tests - UI
  • Loading branch information
panasetskaya authored Dec 18, 2024
2 parents 276a4f1 + ecb47d9 commit 69c7901
Show file tree
Hide file tree
Showing 7 changed files with 724 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ internal class CustomizeTravelAddonPresenter(
): CustomizeTravelAddonState {
var currentState by remember { mutableStateOf(lastState) }
var loadIteration by remember { mutableIntStateOf(0) }
var selectedOptionInDialog by remember { mutableStateOf<TravelAddonQuote?>(null) }
var selectedOptionInDialog by remember {
mutableStateOf<TravelAddonQuote?>(
if (lastState is CustomizeTravelAddonState.Success) {
lastState.currentlyChosenOptionInDialog
} else {
null
},
)
}
CollectEvents { event ->
when (event) {
CustomizeTravelAddonEvent.Reload -> loadIteration++
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ internal class AddonSummaryPresenter(
}
}

private fun getInitialState(summaryParameters: SummaryParameters): Content {
internal fun getInitialState(summaryParameters: SummaryParameters): Content {
val total = if (summaryParameters.currentTravelAddon == null) {
summaryParameters.quote.price
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package data

import assertk.assertThat
import assertk.assertions.isEqualTo
import assertk.assertions.prop
import com.apollographql.apollo.ApolloClient
import com.apollographql.apollo.annotations.ApolloExperimental
import com.apollographql.apollo.api.Error
import com.apollographql.apollo.testing.registerTestResponse
import com.hedvig.android.apollo.octopus.test.OctopusFakeResolver
import com.hedvig.android.apollo.test.TestApolloClientRule
import com.hedvig.android.apollo.test.TestNetworkTransportType
import com.hedvig.android.core.common.ErrorMessage
import com.hedvig.android.core.common.test.isLeft
import com.hedvig.android.core.common.test.isRight
import com.hedvig.android.feature.addon.purchase.data.SubmitAddonPurchaseUseCaseImpl
import com.hedvig.android.logger.TestLogcatLoggingRule
import kotlinx.coroutines.test.runTest
import octopus.UpsellTravelAddonActivateMutation
import octopus.type.buildUpsellTravelAddonActivationOutput
import octopus.type.buildUserError
import org.junit.Rule
import org.junit.Test

class SubmitAddonPurchaseUseCaseImplTest {
@get:Rule
val testLogcatLogger = TestLogcatLoggingRule()

@get:Rule
val testApolloClientRule = TestApolloClientRule(TestNetworkTransportType.MAP)

val testId = "jhjhjh"

@OptIn(ApolloExperimental::class)
private val apolloClientWithGoodResponseNullError: ApolloClient
get() = testApolloClientRule.apolloClient.apply {
registerTestResponse(
operation = UpsellTravelAddonActivateMutation(testId, testId),
data = UpsellTravelAddonActivateMutation.Data(OctopusFakeResolver) {
upsellTravelAddonActivate = buildUpsellTravelAddonActivationOutput {
userError = null
}
},
)
}

@OptIn(ApolloExperimental::class)
private val apolloClientWithUserError: ApolloClient
get() = testApolloClientRule.apolloClient.apply {
registerTestResponse(
operation = UpsellTravelAddonActivateMutation(testId, testId),
data = UpsellTravelAddonActivateMutation.Data(OctopusFakeResolver) {
upsellTravelAddonActivate = buildUpsellTravelAddonActivationOutput {
userError = buildUserError {
message = "Bad message"
}
}
},
)
}

@OptIn(ApolloExperimental::class)
private val apolloClientWithBadResponse: ApolloClient
get() = testApolloClientRule.apolloClient.apply {
registerTestResponse(
operation = UpsellTravelAddonActivateMutation(testId, testId),
data = null,
errors = listOf(Error.Builder(message = "Bad message").build()),
)
}

@Test
fun `if BE response is good return Unit`() = runTest {
val sut = SubmitAddonPurchaseUseCaseImpl(apolloClientWithGoodResponseNullError)
val result = sut.invoke(testId, testId)
assertThat(result)
.isRight().isEqualTo(Unit)
}

@Test
fun `if BE response is UserError return ErrorMessage with the msg from BE`() = runTest {
val sut = SubmitAddonPurchaseUseCaseImpl(apolloClientWithUserError)
val result = sut.invoke(testId, testId)
assertThat(result)
.isLeft().prop(ErrorMessage::message).isEqualTo("Bad message")
}

@Test
fun `if BE response is error return ErrorMessage with null message`() = runTest {
val sut = SubmitAddonPurchaseUseCaseImpl(apolloClientWithBadResponse)
val result = sut.invoke(testId, testId)
assertThat(result)
.isLeft().prop(ErrorMessage::message).isEqualTo(null)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package ui

import app.cash.turbine.Turbine
import arrow.core.Either
import arrow.core.left
import arrow.core.right
import assertk.assertThat
import assertk.assertions.isEqualTo
import assertk.assertions.isInstanceOf
import assertk.assertions.isNotNull
import assertk.assertions.isTrue
import assertk.assertions.prop
import com.hedvig.android.core.common.ErrorMessage
import com.hedvig.android.core.uidata.UiCurrencyCode
import com.hedvig.android.core.uidata.UiMoney
import com.hedvig.android.data.productvariant.InsuranceVariantDocument
import com.hedvig.android.feature.addon.purchase.data.AddonVariant
import com.hedvig.android.feature.addon.purchase.data.CurrentTravelAddon
import com.hedvig.android.feature.addon.purchase.data.SubmitAddonPurchaseUseCase
import com.hedvig.android.feature.addon.purchase.data.TravelAddonQuote
import com.hedvig.android.feature.addon.purchase.navigation.SummaryParameters
import com.hedvig.android.feature.addon.purchase.ui.summary.AddonSummaryEvent
import com.hedvig.android.feature.addon.purchase.ui.summary.AddonSummaryPresenter
import com.hedvig.android.feature.addon.purchase.ui.summary.AddonSummaryState
import com.hedvig.android.feature.addon.purchase.ui.summary.getInitialState
import com.hedvig.android.logger.TestLogcatLoggingRule
import com.hedvig.android.molecule.test.test
import kotlinx.coroutines.test.runTest
import kotlinx.datetime.LocalDate
import org.junit.Rule
import org.junit.Test

class AddonSummaryPresenterTest {
@get:Rule
val testLogcatLogger = TestLogcatLoggingRule()

@Test
fun `if receive error navigate to failure screen`() = runTest {
val useCase = FakeSubmitAddonPurchaseUseCase()
val presenter = AddonSummaryPresenter(
submitAddonPurchaseUseCase = useCase,
summaryParameters = testSummaryParametersWithCurrentAddon,
)
presenter.test(getInitialState(testSummaryParametersWithCurrentAddon)) {
skipItems(1)
sendEvent(AddonSummaryEvent.Submit)
useCase.turbine.add(ErrorMessage().left())
skipItems(1)
assertThat(awaitItem()).isInstanceOf(AddonSummaryState.Content::class)
.prop(AddonSummaryState.Content::navigateToFailure).isTrue()
}
}

@Test
fun `if receive no errors navigate to success screen with activationDate from previous parameters`() = runTest {
val useCase = FakeSubmitAddonPurchaseUseCase()
val presenter = AddonSummaryPresenter(
submitAddonPurchaseUseCase = useCase,
summaryParameters = testSummaryParametersWithCurrentAddon,
)
presenter.test(getInitialState(testSummaryParametersWithCurrentAddon)) {
skipItems(1)
sendEvent(AddonSummaryEvent.Submit)
useCase.turbine.add(Unit.right())
skipItems(1)
assertThat(awaitItem()).isInstanceOf(AddonSummaryState.Content::class)
.prop(AddonSummaryState.Content::activationDateForSuccessfullyPurchasedAddon)
.isNotNull()
.isEqualTo(testSummaryParametersWithCurrentAddon.activationDate)
}
}

@Test
fun `the difference between current addon price and new addon price is shown correctly`() = runTest {
val params = testSummaryParametersWithCurrentAddon
val diff = getInitialState(params).totalPriceChange
assertThat(diff).isEqualTo(UiMoney(11.0, testSummaryParametersWithCurrentAddon.quote.price.currencyCode))
val params2 = testSummaryParametersWithMoreExpensiveCurrentAddon
val diff2 = getInitialState(params2).totalPriceChange
assertThat(
diff2,
).isEqualTo(UiMoney(-19.0, testSummaryParametersWithMoreExpensiveCurrentAddon.quote.price.currencyCode))
}

@Test
fun `if there is no current addon, total price change should show the price of the quote`() = runTest {
val params = testSummaryParametersNoCurrentAddon
val diff = getInitialState(params).totalPriceChange
assertThat(diff).isEqualTo(testSummaryParametersNoCurrentAddon.quote.price)
}
}

private class FakeSubmitAddonPurchaseUseCase() : SubmitAddonPurchaseUseCase {
val turbine = Turbine<Either<ErrorMessage, Unit>>()

override suspend fun invoke(quoteId: String, addonId: String): Either<ErrorMessage, Unit> {
return turbine.awaitItem()
}
}

private val newQuote = TravelAddonQuote(
displayName = "60 days",
addonId = "addonId1",
quoteId = "id",
addonVariant = AddonVariant(
termsVersion = "terms",
displayDetails = listOf(
"Amount of insured people" to "You +1",
"Coverage" to "60 days",
),
documents = listOf(
InsuranceVariantDocument(
"Terms and Conditions",
"url",
InsuranceVariantDocument.InsuranceDocumentType.TERMS_AND_CONDITIONS,
),
),
),
price = UiMoney(
60.0,
UiCurrencyCode.SEK,
),
)

private val newQuote2 = TravelAddonQuote(
displayName = "60 days",
addonId = "addonId1",
quoteId = "id",
addonVariant = AddonVariant(
termsVersion = "terms",
displayDetails = listOf(
"Amount of insured people" to "You +1",
"Coverage" to "60 days",
),
documents = listOf(
InsuranceVariantDocument(
"Terms and Conditions",
"url",
InsuranceVariantDocument.InsuranceDocumentType.TERMS_AND_CONDITIONS,
),
),
),
price = UiMoney(
60.0,
UiCurrencyCode.NOK,
),
)

private val currentAddon = CurrentTravelAddon(
UiMoney(49.0, UiCurrencyCode.SEK),
listOf("Coverage" to "45 days", "Insured people" to "You+1"),
)

private val moreExpensiveCurrentAddon = CurrentTravelAddon(
UiMoney(79.0, UiCurrencyCode.SEK),
listOf("Coverage" to "45 days", "Insured people" to "You+1"),
)

private val testSummaryParametersWithCurrentAddon = SummaryParameters(
offerDisplayName = "fakeTravelOfferOnlyOneOption.title",
quote = newQuote,
activationDate = LocalDate(2024, 12, 30),
currentTravelAddon = currentAddon,
popCustomizeDestination = true,
)

private val testSummaryParametersWithMoreExpensiveCurrentAddon = SummaryParameters(
offerDisplayName = "fakeTravelOfferOnlyOneOption.title",
quote = newQuote2,
activationDate = LocalDate(2024, 12, 30),
currentTravelAddon = moreExpensiveCurrentAddon,
popCustomizeDestination = true,
)

private val testSummaryParametersNoCurrentAddon = SummaryParameters(
offerDisplayName = "fakeTravelOfferOnlyOneOption.title",
quote = newQuote,
activationDate = LocalDate(2024, 12, 30),
currentTravelAddon = null,
popCustomizeDestination = true,
)
Loading

0 comments on commit 69c7901

Please sign in to comment.