Skip to content

Commit 76c4059

Browse files
authored
Insert CTAs on concept test Experiment#2 (#724)
* Dax dialog with two buttons (#713) * New variant: Showing DefaultBrowserCta and SearchWidgetCta as Dax dialogs (#714) * Insert DefaultBrowser Cta and SearchWidget Cta as Dax dialog during Dax Journey (#716) * New control group and changes on when to show search widget cta (#723)
1 parent 412d70b commit 76c4059

30 files changed

+1225
-236
lines changed

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt

Lines changed: 140 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import com.duckduckgo.app.browser.BrowserTabViewModel.Command.Navigate
4242
import com.duckduckgo.app.browser.LongPressHandler.RequiredAction.DownloadFile
4343
import com.duckduckgo.app.browser.LongPressHandler.RequiredAction.OpenInNewTab
4444
import com.duckduckgo.app.browser.addtohome.AddToHomeCapabilityDetector
45+
import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserDetector
4546
import com.duckduckgo.app.browser.favicon.FaviconDownloader
4647
import com.duckduckgo.app.browser.model.BasicAuthenticationCredentials
4748
import com.duckduckgo.app.browser.model.BasicAuthenticationRequest
@@ -52,6 +53,7 @@ import com.duckduckgo.app.cta.db.DismissedCtaDao
5253
import com.duckduckgo.app.cta.model.DismissedCta
5354
import com.duckduckgo.app.cta.ui.CtaViewModel
5455
import com.duckduckgo.app.cta.ui.DaxBubbleCta
56+
import com.duckduckgo.app.cta.ui.DaxDialogCta
5557
import com.duckduckgo.app.cta.ui.HomePanelCta
5658
import com.duckduckgo.app.global.db.AppDatabase
5759
import com.duckduckgo.app.global.install.AppInstallStore
@@ -176,6 +178,9 @@ class BrowserTabViewModelTest {
176178
@Mock
177179
private lateinit var mockPrivacySettingsStore: PrivacySettingsStore
178180

181+
@Mock
182+
private lateinit var mockDefaultBrowserDetector: DefaultBrowserDetector
183+
179184
private lateinit var mockAutoCompleteApi: AutoCompleteApi
180185

181186
private lateinit var ctaViewModel: CtaViewModel
@@ -208,7 +213,8 @@ class BrowserTabViewModelTest {
208213
mockVariantManager,
209214
mockSettingsStore,
210215
mockOnboardingStore,
211-
mockPrivacySettingsStore
216+
mockPrivacySettingsStore,
217+
mockDefaultBrowserDetector
212218
)
213219

214220
val siteFactory = SiteFactory(mockPrivacyPractices, mockEntityLookup)
@@ -240,7 +246,9 @@ class BrowserTabViewModelTest {
240246
searchCountDao = mockSearchCountDao,
241247
pixel = mockPixel,
242248
variantManager = mockVariantManager,
243-
dispatchers = coroutineRule.testDispatcherProvider
249+
dispatchers = coroutineRule.testDispatcherProvider,
250+
defaultBrowserDetector = mockDefaultBrowserDetector,
251+
installStore = mockAppInstallStore
244252
)
245253

246254
testee.loadData("abc", null, false)
@@ -1361,7 +1369,7 @@ class BrowserTabViewModelTest {
13611369
@Test
13621370
fun whenSurveyCtaDismissedAndNoOtherCtaPossibleCtaIsNull() {
13631371
testee.onSurveyChanged(Survey("abc", "http://example.com", daysInstalled = 1, status = Survey.Status.SCHEDULED))
1364-
testee.onUserDismissedCta()
1372+
testee.onUserDismissedCta(testee.ctaViewState.value!!.cta!!)
13651373
assertNull(testee.ctaViewState.value!!.cta)
13661374
}
13671375

@@ -1372,7 +1380,7 @@ class BrowserTabViewModelTest {
13721380
whenever(mockWidgetCapabilities.hasInstalledWidgets).thenReturn(false)
13731381

13741382
testee.onSurveyChanged(Survey("abc", "http://example.com", daysInstalled = 1, status = Survey.Status.SCHEDULED))
1375-
testee.onUserDismissedCta()
1383+
testee.onUserDismissedCta(testee.ctaViewState.value!!.cta!!)
13761384
assertEquals(HomePanelCta.AddWidgetAuto, testee.ctaViewState.value!!.cta)
13771385
}
13781386

@@ -1467,75 +1475,171 @@ class BrowserTabViewModelTest {
14671475
@Test
14681476
fun whenUserClickedCtaButtonThenFirePixel() {
14691477
val cta = DaxBubbleCta.DaxIntroCta(mockOnboardingStore, mockAppInstallStore)
1470-
testee.ctaViewState.value = BrowserTabViewModel.CtaViewState(cta = cta)
1471-
1472-
testee.onUserClickCtaOkButton()
1478+
testee.onUserClickCtaOkButton(cta)
14731479
verify(mockPixel).fire(cta.okPixel!!, cta.pixelOkParameters())
14741480
}
14751481

14761482
@Test
1477-
fun whenUserClickedCtaButtonThenLaunchSurveyCommand() {
1483+
fun whenUserClickedSurveyCtaButtonThenLaunchSurveyCommand() {
14781484
val cta = HomePanelCta.Survey(Survey("abc", "http://example.com", daysInstalled = 1, status = Survey.Status.SCHEDULED))
1479-
testee.ctaViewState.value = BrowserTabViewModel.CtaViewState(cta = cta)
1480-
1481-
testee.onUserClickCtaOkButton()
1485+
testee.onUserClickCtaOkButton(cta)
14821486
assertCommandIssued<Command.LaunchSurvey>()
14831487
}
14841488

14851489
@Test
1486-
fun whenUserClickedCtaButtonThenLaunchAddWidgetCommand() {
1490+
fun whenUserClickedAddWidgetCtaButtonThenLaunchAddWidgetCommand() {
14871491
val cta = HomePanelCta.AddWidgetAuto
1488-
testee.ctaViewState.value = BrowserTabViewModel.CtaViewState(cta = cta)
1489-
1490-
testee.onUserClickCtaOkButton()
1492+
testee.onUserClickCtaOkButton(cta)
14911493
assertCommandIssued<Command.LaunchAddWidget>()
14921494
}
14931495

14941496
@Test
1495-
fun whenUserClickedCtaButtonThenLaunchLegacyAddWidgetCommand() {
1497+
fun whenUserClickedLegacyAddWidgetCtaButtonThenLaunchLegacyAddWidgetCommand() {
14961498
val cta = HomePanelCta.AddWidgetInstructions
1497-
testee.ctaViewState.value = BrowserTabViewModel.CtaViewState(cta = cta)
1499+
testee.onUserClickCtaOkButton(cta)
1500+
assertCommandIssued<Command.LaunchLegacyAddWidget>()
1501+
}
14981502

1499-
testee.onUserClickCtaOkButton()
1503+
@Test
1504+
fun whenUserClickedDefaultBrowserCtaButtonWithoutDefaultBrowserThenLaunchDialogCommand() {
1505+
whenever(mockDefaultBrowserDetector.hasDefaultBrowser()).thenReturn(false)
1506+
val cta = DaxDialogCta.DefaultBrowserCta(mockDefaultBrowserDetector, mock(), mock())
1507+
testee.onUserClickCtaOkButton(cta)
1508+
assertCommandIssued<Command.OpenDefaultBrowserDialog>()
1509+
}
1510+
1511+
@Test
1512+
fun whenUserClickedDefaultBrowserCtaButtonWithDefaultBrowserThenOpenDefaultBrowserSettings() {
1513+
whenever(mockDefaultBrowserDetector.hasDefaultBrowser()).thenReturn(true)
1514+
val cta = DaxDialogCta.DefaultBrowserCta(mockDefaultBrowserDetector, mock(), mock())
1515+
testee.onUserClickCtaOkButton(cta)
1516+
assertCommandIssued<Command.OpenDefaultBrowserSettings>()
1517+
}
1518+
1519+
@Test
1520+
fun whenUserClickedDaxSearchWidgetCtaButtonWithWidgetCapabilitiesThenLaunchAddWidget() {
1521+
whenever(mockWidgetCapabilities.supportsAutomaticWidgetAdd).thenReturn(true)
1522+
val cta = DaxDialogCta.SearchWidgetCta(mockWidgetCapabilities, mock(), mock())
1523+
testee.onUserClickCtaOkButton(cta)
1524+
assertCommandIssued<Command.LaunchAddWidget>()
1525+
}
1526+
1527+
@Test
1528+
fun whenUserClickedDaxSearchWidgetCtaButtonWithoutWidgetCapabilitiesThenLaunchLegacyAddWidget() {
1529+
whenever(mockWidgetCapabilities.supportsAutomaticWidgetAdd).thenReturn(false)
1530+
val cta = DaxDialogCta.SearchWidgetCta(mockWidgetCapabilities, mock(), mock())
1531+
testee.onUserClickCtaOkButton(cta)
15001532
assertCommandIssued<Command.LaunchLegacyAddWidget>()
15011533
}
15021534

15031535
@Test
15041536
fun whenUserDismissedCtaThenFirePixel() {
15051537
val cta = HomePanelCta.Survey(Survey("abc", "http://example.com", daysInstalled = 1, status = Survey.Status.SCHEDULED))
1506-
testee.ctaViewState.value = BrowserTabViewModel.CtaViewState(cta = cta)
1507-
1508-
testee.onUserDismissedCta()
1538+
testee.onUserDismissedCta(cta)
15091539
verify(mockPixel).fire(cta.cancelPixel!!, cta.pixelCancelParameters())
15101540
}
15111541

15121542
@Test
15131543
fun whenUserDismissedCtaThenRegisterInDatabase() {
15141544
val cta = HomePanelCta.AddWidgetAuto
1515-
testee.ctaViewState.value = BrowserTabViewModel.CtaViewState(cta = cta)
1516-
1517-
testee.onUserDismissedCta()
1545+
testee.onUserDismissedCta(cta)
15181546
verify(mockDismissedCtaDao).insert(DismissedCta(cta.ctaId))
15191547
}
15201548

15211549
@Test
15221550
fun whenUserDismissedSurveyCtaThenDoNotRegisterInDatabase() {
15231551
val cta = HomePanelCta.Survey(Survey("abc", "http://example.com", daysInstalled = 1, status = Survey.Status.SCHEDULED))
1524-
testee.ctaViewState.value = BrowserTabViewModel.CtaViewState(cta = cta)
1525-
1526-
testee.onUserDismissedCta()
1552+
testee.onUserDismissedCta(cta)
15271553
verify(mockDismissedCtaDao, never()).insert(DismissedCta(cta.ctaId))
15281554
}
15291555

15301556
@Test
15311557
fun whenUserDismissedSurveyCtaThenCancelScheduledSurveys() {
15321558
val cta = HomePanelCta.Survey(Survey("abc", "http://example.com", daysInstalled = 1, status = Survey.Status.SCHEDULED))
1533-
testee.ctaViewState.value = BrowserTabViewModel.CtaViewState(cta = cta)
1534-
1535-
testee.onUserDismissedCta()
1559+
testee.onUserDismissedCta(cta)
15361560
verify(mockSurveyDao).cancelScheduledSurveys()
15371561
}
15381562

1563+
@Test
1564+
fun whenUserFailedSettingDdgAsDefaultBrowserFromSettingsThenFirePixelAndUpdateInstallStore() {
1565+
whenever(mockDefaultBrowserDetector.isDefaultBrowser()).thenReturn(false)
1566+
1567+
testee.onUserTriedToSetAsDefaultBrowserFromSettings()
1568+
1569+
verify(mockAppInstallStore).defaultBrowser = false
1570+
verify(mockPixel).fire(Pixel.PixelName.DEFAULT_BROWSER_NOT_SET, defaultBrowserPixelParams(Pixel.PixelValues.DEFAULT_BROWSER_SETTINGS))
1571+
}
1572+
1573+
@Test
1574+
fun whenUserHasSetDdgAsDefaultBrowserFromSettingsThenFirePixelAndUpdateInstallStore() {
1575+
whenever(mockDefaultBrowserDetector.isDefaultBrowser()).thenReturn(true)
1576+
1577+
testee.onUserTriedToSetAsDefaultBrowserFromSettings()
1578+
1579+
verify(mockAppInstallStore).defaultBrowser = true
1580+
verify(mockPixel).fire(Pixel.PixelName.DEFAULT_BROWSER_SET, defaultBrowserPixelParams(Pixel.PixelValues.DEFAULT_BROWSER_SETTINGS))
1581+
}
1582+
1583+
@Test
1584+
fun whenUserFailedSettingDdgAsDefaultBrowserFromDialogOnceThenOpenDefaultBrowserDialogAgain() {
1585+
whenever(mockDefaultBrowserDetector.isDefaultBrowser()).thenReturn(false)
1586+
1587+
testee.onUserTriedToSetAsDefaultBrowserFromDialog()
1588+
1589+
assertCommandIssued<Command.OpenDefaultBrowserDialog>()
1590+
}
1591+
1592+
@Test
1593+
fun whenUserFailedSettingDdgAsDefaultBrowserFromDialogTwiceThenFirePixelAndUpdateInstallStore() {
1594+
whenever(mockDefaultBrowserDetector.isDefaultBrowser()).thenReturn(false)
1595+
1596+
testee.onUserTriedToSetAsDefaultBrowserFromDialog()
1597+
testee.onUserTriedToSetAsDefaultBrowserFromDialog()
1598+
1599+
verify(mockAppInstallStore, times(2)).defaultBrowser = false
1600+
verify(mockPixel).fire(
1601+
Pixel.PixelName.DEFAULT_BROWSER_NOT_SET,
1602+
defaultBrowserPixelParams(Pixel.PixelValues.DEFAULT_BROWSER_JUST_ONCE_MAX)
1603+
)
1604+
}
1605+
1606+
@Test
1607+
fun whenUserHasSetDdgAsDefaultBrowserFromDialogThenFirePixelAndUpdateInstallStore() {
1608+
whenever(mockDefaultBrowserDetector.isDefaultBrowser()).thenReturn(true)
1609+
1610+
testee.onUserTriedToSetAsDefaultBrowserFromDialog()
1611+
1612+
verify(mockAppInstallStore).defaultBrowser = true
1613+
verify(mockPixel).fire(Pixel.PixelName.DEFAULT_BROWSER_SET, defaultBrowserPixelParams(Pixel.PixelValues.DEFAULT_BROWSER_DIALOG))
1614+
}
1615+
1616+
@Test
1617+
fun whenUserDismissesDefaultBrowserDialogThenFirePixelAndUpdateInstallStore() {
1618+
whenever(mockDefaultBrowserDetector.isDefaultBrowser()).thenReturn(false)
1619+
1620+
testee.onUserDismissedDefaultBrowserDialog()
1621+
1622+
verify(mockAppInstallStore).defaultBrowser = false
1623+
verify(mockPixel).fire(
1624+
Pixel.PixelName.DEFAULT_BROWSER_NOT_SET,
1625+
defaultBrowserPixelParams(Pixel.PixelValues.DEFAULT_BROWSER_DIALOG_DISMISSED)
1626+
)
1627+
}
1628+
1629+
@Test
1630+
fun whenDefaultBrowserDialogDismissedAfterSelectingDefaultExternalBrowserAlwThenFirePixelAndUpdateInstallStore() {
1631+
whenever(mockDefaultBrowserDetector.isDefaultBrowser()).thenReturn(false)
1632+
whenever(mockDefaultBrowserDetector.hasDefaultBrowser()).thenReturn(true)
1633+
1634+
testee.onUserDismissedDefaultBrowserDialog()
1635+
1636+
verify(mockAppInstallStore).defaultBrowser = false
1637+
verify(mockPixel).fire(
1638+
Pixel.PixelName.DEFAULT_BROWSER_NOT_SET,
1639+
defaultBrowserPixelParams(Pixel.PixelValues.DEFAULT_BROWSER_EXTERNAL)
1640+
)
1641+
}
1642+
15391643
private inline fun <reified T : Command> assertCommandIssued(instanceAssertions: T.() -> Unit = {}) {
15401644
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
15411645
val issuedCommand = commandCaptor.allValues.find { it is T }
@@ -1548,6 +1652,12 @@ class BrowserTabViewModelTest {
15481652
Pixel.PixelParameter.BOOKMARK_CAPABLE to bookmarkCapable.toString()
15491653
)
15501654

1655+
private fun defaultBrowserPixelParams(origin: String) = mapOf(
1656+
Pixel.PixelParameter.DEFAULT_BROWSER_SET_FROM_ONBOARDING to false.toString(),
1657+
Pixel.PixelParameter.DEFAULT_BROWSER_SET_ORIGIN to origin
1658+
)
1659+
1660+
15511661
private fun givenExpectedCtaAddWidgetInstructions() {
15521662
setBrowserShowing(false)
15531663
whenever(mockWidgetCapabilities.supportsStandardWidgetAdd).thenReturn(true)

0 commit comments

Comments
 (0)