Skip to content

Commit

Permalink
Remove Privacy Pro CTA test (#5509)
Browse files Browse the repository at this point in the history
Task/Issue URL: https://app.asana.com/0/0/1209206973663840/f

### Description
Remove logic added for Privacy Pro CTA copy test

### Steps to test this PR

_Privacy Pro eligible user, device locale set to `en-US`_
- [x] Fresh install
- [x] Tap on a site suggestion
- [x] Dismiss SERP onboarding dialog
- [x] Tap on a site suggestion
- [x] Dismiss Trackers dialog
- [x] Tap fire button and Clear Data
- [x] End dialog appears -> Tap on 'High Five!' button
- [x] Check privacy pro onboarding is shown

_Privacy Pro eligible user, device locale set to something other than
`en-US`_
- [x] Fresh install
- [x] Tap on a site suggestion
- [x] Dismiss SERP onboarding dialog
- [x] Tap on a site suggestion
- [x] Dismiss Trackers dialog
- [x] Tap fire button and Clear Data
- [x] End dialog appears -> Tap on 'High Five!' button
- [x] Check privacy pro onboarding is **not** shown

_Privacy Pro NOT eligible user_
- [x] Fresh install
- [x] Tap on a site suggestion
- [x] Dismiss SERP onboarding dialog
- [x] Tap on a site suggestion
- [x] Dismiss Trackers dialog
- [x] Tap fire button and Clear Data
- [x] End dialog appears -> Tap on 'High Five!' button
- [x] Check privacy pro onboarding is **not** shown

### No UI changes
  • Loading branch information
nalcalag authored Jan 23, 2025
1 parent 92df16a commit f42ccaf
Show file tree
Hide file tree
Showing 7 changed files with 3 additions and 164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ import com.duckduckgo.app.onboarding.store.AppStage.ESTABLISHED
import com.duckduckgo.app.onboarding.store.OnboardingStore
import com.duckduckgo.app.onboarding.store.UserStageStore
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.ExtendedOnboardingFeatureToggles
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.ExtendedOnboardingPixelsPlugin
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.HighlightsOnboardingExperimentManager
import com.duckduckgo.app.pixels.AppPixelName
import com.duckduckgo.app.pixels.AppPixelName.AUTOCOMPLETE_BANNER_SHOWN
Expand Down Expand Up @@ -212,8 +211,6 @@ import com.duckduckgo.duckplayer.api.PrivatePlayerMode.AlwaysAsk
import com.duckduckgo.duckplayer.api.PrivatePlayerMode.Disabled
import com.duckduckgo.duckplayer.api.PrivatePlayerMode.Enabled
import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory
import com.duckduckgo.feature.toggles.api.FakeToggleStore
import com.duckduckgo.feature.toggles.api.FeatureToggles
import com.duckduckgo.feature.toggles.api.Toggle
import com.duckduckgo.feature.toggles.api.Toggle.State
import com.duckduckgo.history.api.HistoryEntry.VisitedPage
Expand Down Expand Up @@ -501,9 +498,6 @@ class BrowserTabViewModelTest {
private val mockToggleReports: ToggleReports = mock()
private val mockBrokenSitePrompt: BrokenSitePrompt = mock()
private val mockTabStatsBucketing: TabStatsBucketing = mock()
private val extendedOnboardingFeatureToggles = FeatureToggles.Builder(FakeToggleStore(), featureName = "extendedOnboarding").build()
.create(ExtendedOnboardingFeatureToggles::class.java)
private val extendedOnboardingPixelsPlugin = ExtendedOnboardingPixelsPlugin(extendedOnboardingFeatureToggles)

@Before
fun before() = runTest {
Expand All @@ -530,7 +524,6 @@ class BrowserTabViewModelTest {
lazyFaviconManager,
)

whenever(mockExtendedOnboardingFeatureToggles.testPrivacyProOnboardingCopyNov24()).thenReturn(mockDisabledToggle)
whenever(mockHighlightsOnboardingExperimentManager.isHighlightsEnabled()).thenReturn(false)
whenever(mockDuckPlayer.observeUserPreferences()).thenReturn(flowOf(UserPreferences(false, Disabled)))
whenever(mockDismissedCtaDao.dismissedCtas()).thenReturn(dismissedCtaDaoChannel.consumeAsFlow())
Expand Down Expand Up @@ -573,7 +566,6 @@ class BrowserTabViewModelTest {
duckPlayer = mockDuckPlayer,
highlightsOnboardingExperimentManager = mockHighlightsOnboardingExperimentManager,
brokenSitePrompt = mockBrokenSitePrompt,
extendedOnboardingPixelsPlugin = extendedOnboardingPixelsPlugin,
)

val siteFactory = SiteFactoryImpl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ import com.duckduckgo.app.onboarding.store.AppStage
import com.duckduckgo.app.onboarding.store.OnboardingStore
import com.duckduckgo.app.onboarding.store.UserStageStore
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.ExtendedOnboardingFeatureToggles
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.ExtendedOnboardingFeatureToggles.Cohorts
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.ExtendedOnboardingPixelsPlugin
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.HighlightsOnboardingExperimentManager
import com.duckduckgo.app.pixels.AppPixelName.*
import com.duckduckgo.app.privacy.db.UserAllowListRepository
Expand All @@ -59,10 +57,7 @@ import com.duckduckgo.duckplayer.api.DuckPlayer.DuckPlayerState.DISABLED
import com.duckduckgo.duckplayer.api.DuckPlayer.DuckPlayerState.ENABLED
import com.duckduckgo.duckplayer.api.DuckPlayer.UserPreferences
import com.duckduckgo.duckplayer.api.PrivatePlayerMode.AlwaysAsk
import com.duckduckgo.feature.toggles.api.FakeToggleStore
import com.duckduckgo.feature.toggles.api.FeatureToggles
import com.duckduckgo.feature.toggles.api.Toggle
import com.duckduckgo.feature.toggles.api.Toggle.State.Cohort
import com.duckduckgo.subscriptions.api.Subscriptions
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.FlowPreview
Expand Down Expand Up @@ -131,10 +126,6 @@ class CtaViewModelTest {
CtaId.DAX_END,
)

private val extendedOnboardingFeatureToggles = FeatureToggles.Builder(FakeToggleStore(), featureName = "extendedOnboarding").build()
.create(ExtendedOnboardingFeatureToggles::class.java)
private val extendedOnboardingPixelsPlugin = ExtendedOnboardingPixelsPlugin(extendedOnboardingFeatureToggles)

private lateinit var testee: CtaViewModel

val context: Context = InstrumentationRegistry.getInstrumentation().targetContext
Expand All @@ -149,7 +140,6 @@ class CtaViewModelTest {

val mockDisabledToggle: Toggle = mock { on { it.isEnabled() } doReturn false }
whenever(mockExtendedOnboardingFeatureToggles.noBrowserCtas()).thenReturn(mockDisabledToggle)
whenever(mockExtendedOnboardingFeatureToggles.testPrivacyProOnboardingCopyNov24()).thenReturn(mockDisabledToggle)
whenever(mockAppInstallStore.installTimestamp).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1))
whenever(mockUserAllowListRepository.isDomainInUserAllowList(any())).thenReturn(false)
whenever(mockDismissedCtaDao.dismissedCtas()).thenReturn(db.dismissedCtaDao().dismissedCtas())
Expand Down Expand Up @@ -180,7 +170,6 @@ class CtaViewModelTest {
duckPlayer = mockDuckPlayer,
highlightsOnboardingExperimentManager = mockHighlightsOnboardingExperimentManager,
brokenSitePrompt = mockBrokenSitePrompt,
extendedOnboardingPixelsPlugin = extendedOnboardingPixelsPlugin,
)
}

Expand Down Expand Up @@ -757,7 +746,6 @@ class CtaViewModelTest {
whenever(mockSubscriptions.isEligible()).thenReturn(true)
whenever(mockExtendedOnboardingFeatureToggles.noBrowserCtas()).thenReturn(mockEnabledToggle)
whenever(mockExtendedOnboardingFeatureToggles.privacyProCta()).thenReturn(mockEnabledToggle)
whenever(mockExtendedOnboardingFeatureToggles.testPrivacyProOnboardingCopyNov24()).thenReturn(mockEnabledToggle)
whenever(mockDismissedCtaDao.exists(CtaId.DAX_INTRO)).thenReturn(true)
whenever(mockDismissedCtaDao.exists(CtaId.DAX_INTRO_VISIT_SITE)).thenReturn(true)
whenever(mockDismissedCtaDao.exists(CtaId.DAX_END)).thenReturn(true)
Expand Down Expand Up @@ -828,19 +816,6 @@ class CtaViewModelTest {
assertTrue(value is OnboardingDaxDialogCta.DaxExperimentFireButtonCta)
}

@Test
fun givenPrivacyProExperimentWhenControlCohortThenAppendItToOriginForPrivacyProSubscriptionURL() = runTest {
val controlCohort = Cohort(Cohorts.CONTROL.cohortName, 1)
whenever(mockExtendedOnboardingFeatureToggles.testPrivacyProOnboardingCopyNov24().getCohort()).thenReturn(controlCohort)

assertEquals(testee.getCohortOrigin(), "_control")
}

@Test
fun whenPrivacyProExperimentIsDisabledThenCohortIsNotAppendToPrivacyProSubscriptionURL() = runTest {
assertEquals(testee.getCohortOrigin(), "")
}

private suspend fun givenDaxOnboardingActive() {
whenever(mockUserStageStore.getUserAppStage()).thenReturn(AppStage.DAX_ONBOARDING)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2634,7 +2634,6 @@ class BrowserTabViewModel @Inject constructor(
fun onUserClickCtaSecondaryButton(cta: Cta) {
viewModelScope.launch {
ctaViewModel.onUserDismissedCta(cta)
ctaViewModel.onUserClickCtaSkipButton(cta)
if (cta is DaxBubbleCta.DaxPrivacyProCta || cta is DaxBubbleCta.DaxExperimentPrivacyProCta) {
val updatedCta = refreshCta()
ctaViewState.value = currentCtaViewState().copy(cta = updatedCta)
Expand Down Expand Up @@ -3464,10 +3463,7 @@ class BrowserTabViewModel @Inject constructor(
onUserDismissedCta(cta)
return when (cta) {
is DaxBubbleCta.DaxPrivacyProCta, is DaxBubbleCta.DaxExperimentPrivacyProCta -> {
val cohortOrigin = ctaViewModel.getCohortOrigin()
LaunchPrivacyPro(
"https://duckduckgo.com/pro?origin=funnel_pro_android_onboarding$cohortOrigin".toUri(),
)
LaunchPrivacyPro("https://duckduckgo.com/pro?origin=funnel_pro_android_onboarding".toUri())
}

is DaxBubbleCta.DaxEndCta, is DaxBubbleCta.DaxExperimentEndCta -> {
Expand Down
62 changes: 2 additions & 60 deletions app/src/main/java/com/duckduckgo/app/cta/ui/CtaViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,7 @@ import com.duckduckgo.app.onboarding.store.OnboardingStore
import com.duckduckgo.app.onboarding.store.UserStageStore
import com.duckduckgo.app.onboarding.store.daxOnboardingActive
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.ExtendedOnboardingFeatureToggles
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.ExtendedOnboardingFeatureToggles.Cohorts
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.ExtendedOnboardingPixelsPlugin
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.HighlightsOnboardingExperimentManager
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.testPrivacyProOnboardingPrimaryButtonMetricPixel
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.testPrivacyProOnboardingSecondaryButtonMetricPixel
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.testPrivacyProOnboardingShownMetricPixel
import com.duckduckgo.app.privacy.db.UserAllowListRepository
import com.duckduckgo.app.settings.db.SettingsDataStore
import com.duckduckgo.app.statistics.pixels.Pixel
Expand Down Expand Up @@ -87,7 +82,6 @@ class CtaViewModel @Inject constructor(
private val duckPlayer: DuckPlayer,
private val highlightsOnboardingExperimentManager: HighlightsOnboardingExperimentManager,
private val brokenSitePrompt: BrokenSitePrompt,
private val extendedOnboardingPixelsPlugin: ExtendedOnboardingPixelsPlugin,
) {
@ExperimentalCoroutinesApi
@VisibleForTesting
Expand Down Expand Up @@ -150,12 +144,6 @@ class CtaViewModel @Inject constructor(
if (cta is BrokenSitePromptDialogCta) {
brokenSitePrompt.ctaShown()
}

if (cta is DaxBubbleCta.DaxPrivacyProCta || cta is DaxBubbleCta.DaxExperimentPrivacyProCta) {
extendedOnboardingPixelsPlugin.testPrivacyProOnboardingShownMetricPixel()?.getPixelDefinitions()?.forEach {
pixel.fire(it.pixelName, it.params)
}
}
}
}

Expand Down Expand Up @@ -198,23 +186,6 @@ class CtaViewModel @Inject constructor(
if (cta is BrokenSitePromptDialogCta) {
brokenSitePrompt.userAcceptedPrompt()
}
withContext(dispatchers.io()) {
if (cta is DaxBubbleCta.DaxPrivacyProCta || cta is DaxBubbleCta.DaxExperimentPrivacyProCta) {
extendedOnboardingPixelsPlugin.testPrivacyProOnboardingPrimaryButtonMetricPixel()?.getPixelDefinitions()?.forEach {
pixel.fire(it.pixelName, it.params)
}
}
}
}

suspend fun onUserClickCtaSkipButton(cta: Cta) {
withContext(dispatchers.io()) {
if (cta is DaxBubbleCta.DaxPrivacyProCta || cta is DaxBubbleCta.DaxExperimentPrivacyProCta) {
extendedOnboardingPixelsPlugin.testPrivacyProOnboardingSecondaryButtonMetricPixel()?.getPixelDefinitions()?.forEach {
pixel.fire(it.pixelName, it.params)
}
}
}
}

suspend fun refreshCta(
Expand Down Expand Up @@ -293,26 +264,8 @@ class CtaViewModel @Inject constructor(
}

canShowPrivacyProCta() -> {
val titleRes: Int
val descriptionRes: Int
when {
extendedOnboardingFeatureToggles.testPrivacyProOnboardingCopyNov24().isEnabled(Cohorts.STEP) -> {
titleRes = R.string.onboardingPrivacyProStepDaxDialogTitle
descriptionRes = R.string.onboardingPrivacyProStepDaxDialogDescription
}
extendedOnboardingFeatureToggles.testPrivacyProOnboardingCopyNov24().isEnabled(Cohorts.PROTECTION) -> {
titleRes = R.string.onboardingPrivacyProProtectionDaxDialogTitle
descriptionRes = R.string.onboardingPrivacyProProtectionDaxDialogDescription
}
extendedOnboardingFeatureToggles.testPrivacyProOnboardingCopyNov24().isEnabled(Cohorts.DEAL) -> {
titleRes = R.string.onboardingPrivacyProDealDaxDialogTitle
descriptionRes = R.string.onboardingPrivacyProDealDaxDialogDescription
}
else -> {
titleRes = R.string.onboardingPrivacyProDaxDialogTitle
descriptionRes = R.string.onboardingPrivacyProDaxDialogDescription
}
}
val titleRes: Int = R.string.onboardingPrivacyProDaxDialogTitle
val descriptionRes: Int = R.string.onboardingPrivacyProDaxDialogDescription

if (highlightsOnboardingExperimentManager.isHighlightsEnabled()) {
DaxBubbleCta.DaxExperimentPrivacyProCta(onboardingStore, appInstallStore, titleRes, descriptionRes)
Expand Down Expand Up @@ -551,17 +504,6 @@ class CtaViewModel @Inject constructor(

fun isSuggestedSiteOption(query: String): Boolean = onboardingStore.getSitesOptions().map { it.link }.contains(query)

fun getCohortOrigin(): String {
val cohort = extendedOnboardingFeatureToggles.testPrivacyProOnboardingCopyNov24().getCohort()
return when (cohort?.name) {
Cohorts.STEP.cohortName -> "_${Cohorts.STEP.cohortName}"
Cohorts.PROTECTION.cohortName -> "_${Cohorts.PROTECTION.cohortName}"
Cohorts.DEAL.cohortName -> "_${Cohorts.DEAL.cohortName}"
Cohorts.CONTROL.cohortName -> "_${Cohorts.CONTROL.cohortName}"
else -> ""
}
}

companion object {
private const val MAX_TABS_OPEN_FIRE_EDUCATION = 2
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,8 @@ package com.duckduckgo.app.onboarding.ui.page.extendedonboarding

import com.duckduckgo.anvil.annotations.ContributesRemoteFeature
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.feature.toggles.api.ConversionWindow
import com.duckduckgo.feature.toggles.api.MetricsPixel
import com.duckduckgo.feature.toggles.api.MetricsPixelPlugin
import com.duckduckgo.feature.toggles.api.Toggle
import com.duckduckgo.feature.toggles.api.Toggle.Experiment
import com.duckduckgo.feature.toggles.api.Toggle.State.CohortName
import com.squareup.anvil.annotations.ContributesMultibinding
import javax.inject.Inject

@ContributesRemoteFeature(
scope = AppScope::class,
Expand All @@ -45,53 +39,4 @@ interface ExtendedOnboardingFeatureToggles {
@Toggle.DefaultValue(false)
@Experiment
fun highlights(): Toggle

@Toggle.DefaultValue(false)
fun testPrivacyProOnboardingCopyNov24(): Toggle

enum class Cohorts(override val cohortName: String) : CohortName {
CONTROL("control"),
PROTECTION("protection"),
DEAL("deal"),
STEP("step"),
}
}

internal suspend fun ExtendedOnboardingPixelsPlugin.testPrivacyProOnboardingShownMetricPixel(): MetricsPixel? {
return this.getMetrics().firstOrNull { it.metric == "dialogShown" }
}

internal suspend fun ExtendedOnboardingPixelsPlugin.testPrivacyProOnboardingPrimaryButtonMetricPixel(): MetricsPixel? {
return this.getMetrics().firstOrNull { it.metric == "primaryButtonSelected" }
}

internal suspend fun ExtendedOnboardingPixelsPlugin.testPrivacyProOnboardingSecondaryButtonMetricPixel(): MetricsPixel? {
return this.getMetrics().firstOrNull { it.metric == "secondaryButtonSelected" }
}

@ContributesMultibinding(AppScope::class)
class ExtendedOnboardingPixelsPlugin @Inject constructor(private val toggle: ExtendedOnboardingFeatureToggles) : MetricsPixelPlugin {

override suspend fun getMetrics(): List<MetricsPixel> {
return listOf(
MetricsPixel(
metric = "dialogShown",
value = "1",
toggle = toggle.testPrivacyProOnboardingCopyNov24(),
conversionWindow = listOf(ConversionWindow(lowerWindow = 0, upperWindow = 1)),
),
MetricsPixel(
metric = "primaryButtonSelected",
value = "1",
toggle = toggle.testPrivacyProOnboardingCopyNov24(),
conversionWindow = listOf(ConversionWindow(lowerWindow = 0, upperWindow = 1)),
),
MetricsPixel(
metric = "secondaryButtonSelected",
value = "1",
toggle = toggle.testPrivacyProOnboardingCopyNov24(),
conversionWindow = listOf(ConversionWindow(lowerWindow = 0, upperWindow = 1)),
),
)
}
}
8 changes: 0 additions & 8 deletions app/src/main/res/values/donottranslate.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,6 @@
<string name="newTabPageIndonesiaMessageBody">The government may be blocking access to duckduckgo.com on this network provider, which could affect this app\'s functionality. Other providers may not be affected.</string>
<string name="newTabPageIndonesiaMessageCta">Okay</string>

<!-- Privacy Pro onboarding copy test -->
<string name="onboardingPrivacyProStepDaxDialogTitle">Oh, just one more step…</string>
<string name="onboardingPrivacyProStepDaxDialogDescription"><![CDATA[DuckDuckGo also has a built-in <b>VPN</b>!<br/><br/>Activate it with a <b>paid Privacy Pro subscription</b>.]]></string>
<string name="onboardingPrivacyProProtectionDaxDialogTitle">Get even more protection…</string>
<string name="onboardingPrivacyProProtectionDaxDialogDescription"><![CDATA[You can mask your device\'s IP address from sites with our built-in <b>VPN</b>!<br/><br/>Activate it with a <b>paid Privacy Pro subscription</b>.]]></string>
<string name="onboardingPrivacyProDealDaxDialogTitle">Ready for a deal…?</string>
<string name="onboardingPrivacyProDealDaxDialogDescription"><![CDATA[Get 3 premium protections for the price of 1, including our <b>VPN</b>.<br/><br/>Activate it with a <b>paid Privacy Pro subscription.</b>]]></string>

<!-- Default Browser Bottom Sheet Dialog -->
<string name="defaultBrowserBottomSheetDialogTitle">Protect your personal data every time with DuckDuckGo</string>
<string name="defaultBrowserBottomSheetDialogSubTitle">If you love protecting your data, make us your default browser. All site links will open in DuckDuckGo.</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import com.duckduckgo.app.onboarding.store.AppStage.DAX_ONBOARDING
import com.duckduckgo.app.onboarding.store.OnboardingStore
import com.duckduckgo.app.onboarding.store.UserStageStore
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.ExtendedOnboardingFeatureToggles
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.ExtendedOnboardingPixelsPlugin
import com.duckduckgo.app.onboarding.ui.page.extendedonboarding.HighlightsOnboardingExperimentManager
import com.duckduckgo.app.privacy.db.UserAllowListRepository
import com.duckduckgo.app.settings.db.SettingsDataStore
Expand Down Expand Up @@ -75,7 +74,6 @@ class OnboardingDaxDialogTests {
private val mockDuckPlayer: DuckPlayer = mock()
private val mockHighlightsOnboardingExperimentManager: HighlightsOnboardingExperimentManager = mock()
private val mockBrokenSitePrompt: BrokenSitePrompt = mock()
private val mockExtendedOnboardingPixelsPlugin: ExtendedOnboardingPixelsPlugin = mock()

val mockEnabledToggle: Toggle = org.mockito.kotlin.mock { on { it.isEnabled() } doReturn true }
val mockDisabledToggle: Toggle = org.mockito.kotlin.mock { on { it.isEnabled() } doReturn false }
Expand All @@ -102,7 +100,6 @@ class OnboardingDaxDialogTests {
mockDuckPlayer,
mockHighlightsOnboardingExperimentManager,
mockBrokenSitePrompt,
mockExtendedOnboardingPixelsPlugin,
)
}

Expand Down

0 comments on commit f42ccaf

Please sign in to comment.