diff --git a/app/data/data-addons/src/test/kotlin/GetTravelAddonBannerInfoUseCaseImplTest.kt b/app/data/data-addons/src/test/kotlin/GetTravelAddonBannerInfoUseCaseImplTest.kt index 604d2afe41..0f33468198 100644 --- a/app/data/data-addons/src/test/kotlin/GetTravelAddonBannerInfoUseCaseImplTest.kt +++ b/app/data/data-addons/src/test/kotlin/GetTravelAddonBannerInfoUseCaseImplTest.kt @@ -1,15 +1,26 @@ +import arrow.core.nonEmptyListOf import arrow.core.raise.either import assertk.assertions.isEqualTo +import assertk.assertions.isNotNull +import assertk.assertions.isNull +import assertk.assertions.isTrue import com.apollographql.apollo.ApolloClient import com.apollographql.apollo.annotations.ApolloExperimental +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.data.addons.data.GetTravelAddonBannerInfoUseCaseImpl +import com.hedvig.android.data.addons.data.TravelAddonBannerInfo import com.hedvig.android.data.addons.data.TravelAddonBannerSource import com.hedvig.android.featureflags.flags.Feature import com.hedvig.android.featureflags.test.FakeFeatureManager2 import com.hedvig.android.logger.TestLogcatLoggingRule import kotlinx.coroutines.test.runTest +import octopus.TravelAddonBannerQuery +import octopus.type.UpsellTravelAddonFlow +import octopus.type.buildMember +import octopus.type.buildUpsellTravelAddonBanner import org.junit.Rule import org.junit.Test @@ -21,18 +32,171 @@ class GetTravelAddonBannerInfoUseCaseImplTest { val testApolloClientRule = TestApolloClientRule(TestNetworkTransportType.MAP) @OptIn(ApolloExperimental::class) - private val apolloClient: ApolloClient - get() = testApolloClientRule.apolloClient + private val apolloClientWithError: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = TravelAddonBannerQuery(UpsellTravelAddonFlow.APP_UPSELL_UPGRADE), + errors = listOf(com.apollographql.apollo.api.Error.Builder(message = "Bad message").build()), + ) + } + + @OptIn(ApolloExperimental::class) + private val apolloClientWithNullBannerData: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = TravelAddonBannerQuery(UpsellTravelAddonFlow.APP_UPSELL_UPGRADE), + data = TravelAddonBannerQuery.Data(OctopusFakeResolver) { + currentMember = buildMember { + upsellTravelAddonBanner = null + } + }, + ) + } + + @OptIn(ApolloExperimental::class) + private val apolloClientWithTwoFlows: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = TravelAddonBannerQuery(UpsellTravelAddonFlow.APP_UPSELL_UPGRADE), + data = TravelAddonBannerQuery.Data(OctopusFakeResolver) { + currentMember = buildMember { + upsellTravelAddonBanner = buildUpsellTravelAddonBanner { + badges = buildList { + add("60 days") + } + contractIds = buildList { + add("ContractId") + } + descriptionDisplayName = "Description" + titleDisplayName = "Title" + } + } + }, + ) + registerTestResponse( + operation = TravelAddonBannerQuery(UpsellTravelAddonFlow.APP_ONLY_UPSALE), + data = TravelAddonBannerQuery.Data(OctopusFakeResolver) { + currentMember = buildMember { + upsellTravelAddonBanner = null + } + }, + ) + } + + @OptIn(ApolloExperimental::class) + private val apolloClientWithEmptyContracts: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = TravelAddonBannerQuery(UpsellTravelAddonFlow.APP_UPSELL_UPGRADE), + data = TravelAddonBannerQuery.Data(OctopusFakeResolver) { + currentMember = buildMember { + upsellTravelAddonBanner = buildUpsellTravelAddonBanner { + badges = buildList { + add("60 days") + } + contractIds = listOf() + descriptionDisplayName = "Description" + titleDisplayName = "Title" + } + } + }, + ) + } + + @OptIn(ApolloExperimental::class) + private val apolloClientWithFullBannerData: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = TravelAddonBannerQuery(UpsellTravelAddonFlow.APP_UPSELL_UPGRADE), + data = TravelAddonBannerQuery.Data(OctopusFakeResolver) { + currentMember = buildMember { + upsellTravelAddonBanner = buildUpsellTravelAddonBanner { + badges = buildList { + add("60 days") + } + contractIds = buildList { + add("ContractId") + } + descriptionDisplayName = "Description" + titleDisplayName = "Title" + } + } + }, + ) + } @Test fun `if FF for addons is off return null`() = runTest { val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to false)) - val sut = GetTravelAddonBannerInfoUseCaseImpl(apolloClient, featureManager) - val resultFromInsurances = sut.invoke(TravelAddonBannerSource.INSURANCES_TAB) + val sut = GetTravelAddonBannerInfoUseCaseImpl(apolloClientWithFullBannerData, featureManager) + val resultFromInsurances = sut.invoke(TravelAddonBannerSource.TRAVEL_CERTIFICATES) assertk.assertThat(resultFromInsurances) .isEqualTo(either { null }) val resultFromTravel = sut.invoke(TravelAddonBannerSource.TRAVEL_CERTIFICATES) assertk.assertThat(resultFromTravel) .isEqualTo(either { null }) } + + @Test + fun `if get null bannerData from BE return null`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetTravelAddonBannerInfoUseCaseImpl(apolloClientWithNullBannerData, featureManager) + val result = sut.invoke(TravelAddonBannerSource.TRAVEL_CERTIFICATES) + assertk.assertThat(result) + .isEqualTo(either { null }) + } + + @Test + fun `the source is mapped to the correct flow for the query`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetTravelAddonBannerInfoUseCaseImpl(apolloClientWithTwoFlows, featureManager) + val resultFromTravelCertificates = sut.invoke(TravelAddonBannerSource.TRAVEL_CERTIFICATES).getOrNull() + assertk.assertThat(resultFromTravelCertificates).isNotNull() + val resultFromInsurances = sut.invoke(TravelAddonBannerSource.INSURANCES_TAB).getOrNull() + assertk.assertThat(resultFromInsurances).isNull() + } + + @Test + fun `if get bannerData from BE is not null but contractIds are empty return null`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetTravelAddonBannerInfoUseCaseImpl(apolloClientWithEmptyContracts, featureManager) + val result = sut.invoke(TravelAddonBannerSource.TRAVEL_CERTIFICATES) + assertk.assertThat(result) + .isEqualTo(either { null }) + } + + @Test + fun `if get error from BE return ErrorMessage`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetTravelAddonBannerInfoUseCaseImpl(apolloClientWithError, featureManager) + val resultFromTravels = sut.invoke(TravelAddonBannerSource.TRAVEL_CERTIFICATES).isLeft() + assertk.assertThat(resultFromTravels) + .isTrue() + } + + @Test + fun `if get full banner data from BE return TravelAddonBannerInfo`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetTravelAddonBannerInfoUseCaseImpl(apolloClientWithFullBannerData, featureManager) + val resultFromTravel = sut.invoke(TravelAddonBannerSource.TRAVEL_CERTIFICATES).getOrNull() + assertk.assertThat(resultFromTravel) + .isNotNull() + } + + @Test + fun `the received data is passed correctly and in full`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetTravelAddonBannerInfoUseCaseImpl(apolloClientWithFullBannerData, featureManager) + val resultFromTravel = sut.invoke(TravelAddonBannerSource.TRAVEL_CERTIFICATES).getOrNull() + assertk.assertThat(resultFromTravel) + .isEqualTo( + TravelAddonBannerInfo( + title = "Title", + description = "Description", + labels = listOf("60 days"), + eligibleInsurancesIds = nonEmptyListOf("ContractId"), + bannerSource = UpsellTravelAddonFlow.APP_UPSELL_UPGRADE, + ), + ) + } } diff --git a/app/feature/feature-addon-purchase/build.gradle.kts b/app/feature/feature-addon-purchase/build.gradle.kts index 70c8f45bca..fa7e7d44e5 100644 --- a/app/feature/feature-addon-purchase/build.gradle.kts +++ b/app/feature/feature-addon-purchase/build.gradle.kts @@ -43,4 +43,17 @@ dependencies { implementation(projects.navigationComposeTyped) implementation(projects.navigationCore) implementation(projects.uiTiersAndAddons) + + testImplementation(libs.apollo.testingSupport) + testImplementation(libs.assertK) + testImplementation(libs.coroutines.test) + testImplementation(libs.junit) + testImplementation(libs.turbine) + testImplementation(projects.apolloOctopusTest) + testImplementation(projects.apolloTest) + testImplementation(projects.coreCommonTest) + testImplementation(projects.featureFlagsTest) + testImplementation(projects.languageTest) + testImplementation(projects.loggingTest) + testImplementation(projects.moleculeTest) } diff --git a/app/feature/feature-addon-purchase/src/main/kotlin/com/hedvig/android/feature/addon/purchase/data/GetTravelAddonOfferUseCase.kt b/app/feature/feature-addon-purchase/src/main/kotlin/com/hedvig/android/feature/addon/purchase/data/GetTravelAddonOfferUseCase.kt index b35548cdf5..5b2219f72f 100644 --- a/app/feature/feature-addon-purchase/src/main/kotlin/com/hedvig/android/feature/addon/purchase/data/GetTravelAddonOfferUseCase.kt +++ b/app/feature/feature-addon-purchase/src/main/kotlin/com/hedvig/android/feature/addon/purchase/data/GetTravelAddonOfferUseCase.kt @@ -2,15 +2,12 @@ package com.hedvig.android.feature.addon.purchase.data import arrow.core.Either import arrow.core.NonEmptyList -import arrow.core.nonEmptyListOf import arrow.core.raise.either import arrow.core.toNonEmptyListOrNull import com.apollographql.apollo.ApolloClient import com.hedvig.android.apollo.safeExecute 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.Addon.TravelAddonOffer import com.hedvig.android.featureflags.FeatureManager import com.hedvig.android.featureflags.flags.Feature @@ -18,7 +15,6 @@ import com.hedvig.android.logger.LogPriority import com.hedvig.android.logger.logcat import kotlin.String import kotlinx.coroutines.flow.first -import kotlinx.datetime.LocalDate import octopus.UpsellAddonOfferMutation internal interface GetTravelAddonOfferUseCase { @@ -99,85 +95,3 @@ private fun UpsellAddonOfferMutation.Data.UpsellTravelAddonOffer.Offer.CurrentAd ) } } - -// todo: remove mocks when not needed -private val mockWithoutUpgrade = TravelAddonOffer( - addonOptions = nonEmptyListOf( - TravelAddonQuote( - quoteId = "id", - addonId = "addonId1", - displayName = "45 days", - addonVariant = AddonVariant( - termsVersion = "terms", - documents = listOf( - InsuranceVariantDocument( - "Terms and conditions", - "www.url.com", - InsuranceVariantDocument.InsuranceDocumentType.TERMS_AND_CONDITIONS, - ), - ), - displayDetails = listOf("Coverage" to "45 days", "Insured people" to "You+1"), - ), - price = UiMoney( - 49.0, - UiCurrencyCode.SEK, - ), - ), - TravelAddonQuote( - displayName = "60 days", - addonId = "addonId1", - quoteId = "id", - addonVariant = AddonVariant( - termsVersion = "terms", - documents = listOf( - InsuranceVariantDocument( - "Terms and conditions", - "www.url.com", - InsuranceVariantDocument.InsuranceDocumentType.TERMS_AND_CONDITIONS, - ), - ), - displayDetails = listOf("Coverage" to "60 days", "Insured people" to "You+1"), - ), - price = UiMoney( - 60.0, - UiCurrencyCode.SEK, - ), - ), - ), - title = "Travel plus", - description = "For those who travel often: luggage protection and 24/7 assistance worldwide", - activationDate = LocalDate(2025, 1, 1), - currentTravelAddon = null, -) - -private val mockWithUpgrade = TravelAddonOffer( - addonOptions = nonEmptyListOf( - TravelAddonQuote( - displayName = "60 days", - addonId = "addonId1", - quoteId = "id", - addonVariant = AddonVariant( - termsVersion = "terms", - documents = listOf( - InsuranceVariantDocument( - "Terms and conditions", - "www.url.com", - InsuranceVariantDocument.InsuranceDocumentType.TERMS_AND_CONDITIONS, - ), - ), - displayDetails = listOf("Coverage" to "60 days", "Insured people" to "You+1"), - ), - price = UiMoney( - 60.0, - UiCurrencyCode.SEK, - ), - ), - ), - title = "Travel plus", - description = "For those who travel often: luggage protection and 24/7 assistance worldwide", - activationDate = LocalDate(2025, 1, 1), - currentTravelAddon = CurrentTravelAddon( - UiMoney(49.0, UiCurrencyCode.SEK), - listOf("Coverage" to "45 days", "Insured people" to "You+1"), - ), -) diff --git a/app/feature/feature-addon-purchase/src/test/kotlin/data/GetInsuranceForTravelAddonUseCaseImplTest.kt b/app/feature/feature-addon-purchase/src/test/kotlin/data/GetInsuranceForTravelAddonUseCaseImplTest.kt new file mode 100644 index 0000000000..71a2def643 --- /dev/null +++ b/app/feature/feature-addon-purchase/src/test/kotlin/data/GetInsuranceForTravelAddonUseCaseImplTest.kt @@ -0,0 +1,155 @@ +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.data.contract.ContractGroup +import com.hedvig.android.feature.addon.purchase.data.GetInsuranceForTravelAddonUseCaseImpl +import com.hedvig.android.feature.addon.purchase.data.InsuranceForAddon +import com.hedvig.android.featureflags.flags.Feature +import com.hedvig.android.featureflags.test.FakeFeatureManager2 +import com.hedvig.android.logger.TestLogcatLoggingRule +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.runTest +import octopus.InsurancesForTravelAddonQuery +import octopus.type.buildAgreement +import octopus.type.buildContract +import octopus.type.buildMember +import octopus.type.buildProductVariant +import org.junit.Rule +import org.junit.Test + +class GetInsuranceForTravelAddonUseCaseImplTest { + @get:Rule + val testLogcatLogger = TestLogcatLoggingRule() + + @get:Rule + val testApolloClientRule = TestApolloClientRule(TestNetworkTransportType.MAP) + + val testIds = listOf("testId1") + + @OptIn(ApolloExperimental::class) + private val apolloClientWithGoodResponse: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = InsurancesForTravelAddonQuery(), + data = InsurancesForTravelAddonQuery.Data(OctopusFakeResolver) { + currentMember = buildMember { + activeContracts = buildList { + add( + buildContract { + id = testIds[0] + exposureDisplayName = "exposureDisplayName" + currentAgreement = buildAgreement { + productVariant = buildProductVariant { + displayName = "displayName" + typeOfContract = "SE_HOUSE" + } + } + }, + ) + add( + buildContract { + id = "anotherId" + exposureDisplayName = "exposureDisplayName" + currentAgreement = buildAgreement { + productVariant = buildProductVariant { + displayName = "displayName" + typeOfContract = "SE_HOUSE" + } + } + }, + ) + } + } + }, + ) + } + + @OptIn(ApolloExperimental::class) + private val apolloClientWithGoodButEmptyResponse: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = InsurancesForTravelAddonQuery(), + data = InsurancesForTravelAddonQuery.Data(OctopusFakeResolver) { + currentMember = buildMember { + activeContracts = listOf() + } + }, + ) + } + + @OptIn(ApolloExperimental::class) + private val apolloClientWithError: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = InsurancesForTravelAddonQuery(), + errors = listOf(Error.Builder(message = "Bad message").build()), + ) + } + + @Test + fun `if FF for addons is off return ErrorMessage`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to false)) + val sut = GetInsuranceForTravelAddonUseCaseImpl(apolloClientWithGoodResponse, featureManager) + val result = sut.invoke(testIds).first() + assertThat(result) + .isLeft() + } + + @Test + fun `if quotes list is empty return ErrorMessage with null message`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetInsuranceForTravelAddonUseCaseImpl(apolloClientWithGoodButEmptyResponse, featureManager) + val result = sut.invoke(testIds).first() + assertThat(result) + .isLeft() + .prop(ErrorMessage::message) + } + + @Test + fun `if BE gives error return ErrorMessage`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetInsuranceForTravelAddonUseCaseImpl(apolloClientWithError, featureManager) + val result = sut.invoke(testIds).first() + assertThat(result) + .isLeft() + } + + @Test + fun `if BE gives correct response but the required ids are not there return ErrorMessage`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetInsuranceForTravelAddonUseCaseImpl(apolloClientWithGoodResponse, featureManager) + val result = sut.invoke(listOf("someotherid")).first() + assertThat(result) + .isLeft() + } + + @Test + fun `if BE gives correct response and required ids are not there return correctly mapped list`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetInsuranceForTravelAddonUseCaseImpl(apolloClientWithGoodResponse, featureManager) + val result = sut.invoke(testIds).first() + assertThat(result) + .isRight().isEqualTo( + listOf( + InsuranceForAddon( + id = testIds[0], + displayName = "displayName", + contractExposure = "exposureDisplayName", + contractGroup = ContractGroup.HOUSE, + ), + ), + ) + } +} diff --git a/app/feature/feature-addon-purchase/src/test/kotlin/data/GetTravelAddonOfferUseCaseImplTest.kt b/app/feature/feature-addon-purchase/src/test/kotlin/data/GetTravelAddonOfferUseCaseImplTest.kt new file mode 100644 index 0000000000..eb36f1b4f3 --- /dev/null +++ b/app/feature/feature-addon-purchase/src/test/kotlin/data/GetTravelAddonOfferUseCaseImplTest.kt @@ -0,0 +1,343 @@ +package data + +import arrow.core.nonEmptyListOf +import arrow.core.raise.either +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.isNull +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.uidata.UiCurrencyCode +import com.hedvig.android.core.uidata.UiMoney +import com.hedvig.android.feature.addon.purchase.data.Addon.TravelAddonOffer +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.GetTravelAddonOfferUseCaseImpl +import com.hedvig.android.feature.addon.purchase.data.TravelAddonQuote +import com.hedvig.android.featureflags.flags.Feature +import com.hedvig.android.featureflags.test.FakeFeatureManager2 +import com.hedvig.android.logger.TestLogcatLoggingRule +import kotlinx.coroutines.test.runTest +import kotlinx.datetime.LocalDate +import octopus.UpsellAddonOfferMutation +import octopus.type.CurrencyCode +import octopus.type.buildMoney +import octopus.type.buildUpsellTravelAddonCurrentAddon +import octopus.type.buildUpsellTravelAddonDisplayItem +import octopus.type.buildUpsellTravelAddonOffer +import octopus.type.buildUpsellTravelAddonOfferOutput +import octopus.type.buildUpsellTravelAddonQuote +import octopus.type.buildUserError +import org.junit.Rule +import org.junit.Test + +class GetTravelAddonOfferUseCaseImplTest { + @get:Rule + val testLogcatLogger = TestLogcatLoggingRule() + + @get:Rule + val testApolloClientRule = TestApolloClientRule(TestNetworkTransportType.MAP) + + val testId = "testId" + + @OptIn(ApolloExperimental::class) + private val apolloClientWithError: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = UpsellAddonOfferMutation(testId), + errors = listOf(Error.Builder(message = "Bad message").build()), + ) + } + + @OptIn(ApolloExperimental::class) + private val apolloClientWithNullData: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = UpsellAddonOfferMutation(testId), + data = UpsellAddonOfferMutation.Data(OctopusFakeResolver) { + upsellTravelAddonOffer = buildUpsellTravelAddonOfferOutput { + offer = null + userError = null + } + }, + ) + } + + @OptIn(ApolloExperimental::class) + private val apolloClientWithFullResponseEmptyQuotes: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = UpsellAddonOfferMutation(testId), + data = UpsellAddonOfferMutation.Data(OctopusFakeResolver) { + upsellTravelAddonOffer = buildUpsellTravelAddonOfferOutput { + offer = buildUpsellTravelAddonOffer { + activationDate = mockWithoutUpgrade.activationDate + descriptionDisplayName = mockWithoutUpgrade.description + titleDisplayName = mockWithoutUpgrade.title + currentAddon = null + quotes = listOf() + } + userError = null + } + }, + ) + } + + @OptIn(ApolloExperimental::class) + private val apolloClientWithUserError: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = UpsellAddonOfferMutation(testId), + data = UpsellAddonOfferMutation.Data(OctopusFakeResolver) { + upsellTravelAddonOffer = buildUpsellTravelAddonOfferOutput { + userError = buildUserError { + message = "You have 2 insurances" + } + } + }, + ) + } + + @OptIn(ApolloExperimental::class) + private val apolloClientWithFullResponseNoCurrentAddon: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = UpsellAddonOfferMutation(testId), + data = UpsellAddonOfferMutation.Data(OctopusFakeResolver) { + upsellTravelAddonOffer = buildUpsellTravelAddonOfferOutput { + offer = buildUpsellTravelAddonOffer { + activationDate = mockWithoutUpgrade.activationDate + descriptionDisplayName = mockWithoutUpgrade.description + titleDisplayName = mockWithoutUpgrade.title + currentAddon = null + quotes = buildList { + add( + buildUpsellTravelAddonQuote { + addonId = mockWithoutUpgrade.addonOptions[0].addonId + displayName = mockWithoutUpgrade.addonOptions[0].displayName + quoteId = mockWithoutUpgrade.addonOptions[0].quoteId + displayItems = buildList { + add( + buildUpsellTravelAddonDisplayItem { + displayTitle = mockWithoutUpgrade.addonOptions[0].addonVariant.displayDetails[0].first + displayValue = mockWithoutUpgrade.addonOptions[0].addonVariant.displayDetails[0].second + }, + ) + } + premium = buildMoney { + amount = mockWithoutUpgrade.addonOptions[0].price.amount + currencyCode = CurrencyCode.SEK + } + }, + ) + + add( + buildUpsellTravelAddonQuote { + addonId = mockWithoutUpgrade.addonOptions[1].addonId + displayName = mockWithoutUpgrade.addonOptions[1].displayName + quoteId = mockWithoutUpgrade.addonOptions[1].quoteId + displayItems = buildList { + add( + buildUpsellTravelAddonDisplayItem { + displayTitle = mockWithoutUpgrade.addonOptions[1].addonVariant.displayDetails[0].first + displayValue = mockWithoutUpgrade.addonOptions[1].addonVariant.displayDetails[0].second + }, + ) + } + premium = buildMoney { + amount = mockWithoutUpgrade.addonOptions[1].price.amount + currencyCode = CurrencyCode.SEK + } + }, + ) + } + } + userError = null + } + }, + ) + } + + @OptIn(ApolloExperimental::class) + private val apolloClientWithFullResponseWithCurrentAddon: ApolloClient + get() = testApolloClientRule.apolloClient.apply { + registerTestResponse( + operation = UpsellAddonOfferMutation(testId), + data = UpsellAddonOfferMutation.Data(OctopusFakeResolver) { + upsellTravelAddonOffer = buildUpsellTravelAddonOfferOutput { + offer = buildUpsellTravelAddonOffer { + activationDate = mockWithUpgrade.activationDate + descriptionDisplayName = mockWithUpgrade.description + titleDisplayName = mockWithUpgrade.title + currentAddon = buildUpsellTravelAddonCurrentAddon { + displayItems = buildList { + add( + buildUpsellTravelAddonDisplayItem { + displayTitle = mockWithUpgrade.currentTravelAddon!!.displayDetails[0].first + displayValue = mockWithUpgrade.currentTravelAddon.displayDetails[0].second + }, + ) + } + premium = buildMoney { + amount = mockWithUpgrade.currentTravelAddon!!.price.amount + currencyCode = CurrencyCode.SEK + } + } + quotes = buildList { + add( + buildUpsellTravelAddonQuote { + addonId = mockWithUpgrade.addonOptions[0].addonId + displayName = mockWithUpgrade.addonOptions[0].displayName + quoteId = mockWithUpgrade.addonOptions[0].quoteId + displayItems = buildList { + add( + buildUpsellTravelAddonDisplayItem { + displayTitle = mockWithUpgrade.addonOptions[0].addonVariant.displayDetails[0].first + displayValue = mockWithUpgrade.addonOptions[0].addonVariant.displayDetails[0].second + }, + ) + } + premium = buildMoney { + amount = mockWithUpgrade.addonOptions[0].price.amount + currencyCode = CurrencyCode.SEK + } + }, + ) + } + } + userError = null + } + }, + ) + } + + @Test + fun `if FF for addons is off return ErrorMessage with null message`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to false)) + val sut = GetTravelAddonOfferUseCaseImpl(apolloClientWithFullResponseWithCurrentAddon, featureManager) + val result = sut.invoke(testId) + assertThat(result) + .isLeft().prop(ErrorMessage::message).isNull() + } + + @Test + fun `if quotes list is empty return ErrorMessage with null message`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetTravelAddonOfferUseCaseImpl(apolloClientWithFullResponseEmptyQuotes, featureManager) + val result = sut.invoke(testId) + assertThat(result) + .isLeft() + .prop(ErrorMessage::message).isEqualTo(null) + } + + @Test + fun `if BE gives error return ErrorMessage with null message`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetTravelAddonOfferUseCaseImpl(apolloClientWithError, featureManager) + val result = sut.invoke(testId) + assertThat(result) + .isLeft().prop(ErrorMessage::message).isEqualTo(null) + } + + @Test + fun `if BE gives UserError return ErrorMessage with proper message`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetTravelAddonOfferUseCaseImpl(apolloClientWithUserError, featureManager) + val result = sut.invoke(testId) + assertThat(result) + .isLeft().prop(ErrorMessage::message).isEqualTo("You have 2 insurances") + } + + @Test + fun `if BE gives data but it's null return ErrorMessage with null message`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut = GetTravelAddonOfferUseCaseImpl(apolloClientWithNullData, featureManager) + val result = sut.invoke(testId).leftOrNull().toString() + assertThat(result) + .isEqualTo("ErrorMessage(message=null, throwable=null)") + } + + @Test + fun `if BE gives full data map it correctly`() = runTest { + val featureManager = FakeFeatureManager2(fixedMap = mapOf(Feature.TRAVEL_ADDON to true)) + val sut1 = GetTravelAddonOfferUseCaseImpl(apolloClientWithFullResponseNoCurrentAddon, featureManager) + val result1 = sut1.invoke(testId) + assertThat(result1) + .isEqualTo(either { mockWithoutUpgrade }) + val sut2 = GetTravelAddonOfferUseCaseImpl(apolloClientWithFullResponseWithCurrentAddon, featureManager) + val result2 = sut2.invoke(testId) + assertThat(result2) + .isEqualTo(either { mockWithUpgrade }) + } +} + +private val mockWithoutUpgrade = TravelAddonOffer( + addonOptions = nonEmptyListOf( + TravelAddonQuote( + quoteId = "id", + addonId = "addonId1", + displayName = "45 days", + addonVariant = AddonVariant( + termsVersion = "", + documents = listOf(), + displayDetails = listOf("Coverage" to "45 days"), + ), + price = UiMoney( + 49.0, + UiCurrencyCode.SEK, + ), + ), + TravelAddonQuote( + displayName = "60 days", + addonId = "addonId1", + quoteId = "id", + addonVariant = AddonVariant( + termsVersion = "", + documents = listOf(), + displayDetails = listOf("Coverage" to "60 days"), + ), + price = UiMoney( + 60.0, + UiCurrencyCode.SEK, + ), + ), + ), + title = "Travel plus", + description = "For those who travel often: luggage protection and 24/7 assistance worldwide", + activationDate = LocalDate(2025, 1, 1), + currentTravelAddon = null, +) + +private val mockWithUpgrade = TravelAddonOffer( + addonOptions = nonEmptyListOf( + TravelAddonQuote( + displayName = "60 days", + addonId = "addonId1", + quoteId = "id", + addonVariant = AddonVariant( + termsVersion = "", + documents = listOf(), + displayDetails = listOf("Coverage" to "60 days"), + ), + price = UiMoney( + 60.0, + UiCurrencyCode.SEK, + ), + ), + ), + title = "Travel plus", + description = "For those who travel often: luggage protection and 24/7 assistance worldwide", + activationDate = LocalDate(2025, 1, 1), + currentTravelAddon = CurrentTravelAddon( + UiMoney(49.0, UiCurrencyCode.SEK), + listOf("Coverage" to "45 days"), + ), +)