Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
746 changes: 746 additions & 0 deletions app/schemas/com.duckduckgo.app.global.db.AppDatabase/23.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2175,6 +2175,15 @@ class BrowserTabViewModelTest {
verify(mockPixel).fire(Pixel.PixelName.UOA_VISITED_AFTER_DELETE_CTA)
}

@Test
fun whenViewReadyIfDomainSameAsUseOurAppThenPixelSent() = coroutineRule.runBlocking {
givenUseOurAppSiteSelected()

testee.onViewReady()

verify(mockPixel).fire(Pixel.PixelName.UOA_VISITED)
}

@Test
fun whenViewReadyIfDomainIsNotTheSameAsUseOurAppAfterNotificationSeenThenPixelNotSent() = coroutineRule.runBlocking {
givenUseOurAppSiteIsNotSelected()
Expand Down Expand Up @@ -2205,6 +2214,15 @@ class BrowserTabViewModelTest {
verify(mockPixel, never()).fire(Pixel.PixelName.UOA_VISITED_AFTER_DELETE_CTA)
}

@Test
fun whenViewReadyIfDomainIsNotTheSameAsUseOurAppAThenPixelNotSent() = coroutineRule.runBlocking {
givenUseOurAppSiteIsNotSelected()

testee.onViewReady()

verify(mockPixel, never()).fire(Pixel.PixelName.UOA_VISITED)
}

@Test
fun whenPageChangedIfPreviousOneWasNotUseOurAppSiteAfterNotificationSeenThenPixelSent() = coroutineRule.runBlocking {
givenUseOurAppSiteIsNotSelected()
Expand Down Expand Up @@ -2235,6 +2253,15 @@ class BrowserTabViewModelTest {
verify(mockPixel).fire(Pixel.PixelName.UOA_VISITED_AFTER_DELETE_CTA)
}

@Test
fun whenPageChangedIfPreviousOneWasNotUseOurAppSiteThenPixelSent() = coroutineRule.runBlocking {
givenUseOurAppSiteIsNotSelected()

loadUrl(USE_OUR_APP_DOMAIN, isBrowserShowing = true)

verify(mockPixel).fire(Pixel.PixelName.UOA_VISITED)
}

@Test
fun whenPageChangedIfPreviousOneWasUseOurAppSiteAfterNotificationSeenThenPixelNotSent() = coroutineRule.runBlocking {
givenUseOurAppSiteSelected()
Expand Down Expand Up @@ -2266,6 +2293,15 @@ class BrowserTabViewModelTest {
verify(mockPixel, never()).fire(Pixel.PixelName.UOA_VISITED_AFTER_DELETE_CTA)
}

@Test
fun whenPageChangedIfPreviousOneWasUseOurAppSiteThenNotSent() = coroutineRule.runBlocking {
givenUseOurAppSiteSelected()

loadUrl(USE_OUR_APP_DOMAIN, isBrowserShowing = true)

verify(mockPixel, never()).fire(Pixel.PixelName.UOA_VISITED)
}

private inline fun <reified T : Command> assertCommandIssued(instanceAssertions: T.() -> Unit = {}) {
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
val issuedCommand = commandCaptor.allValues.find { it is T }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ import com.duckduckgo.app.CoroutineTestRule
import com.duckduckgo.app.browser.BrowserViewModel.Command
import com.duckduckgo.app.browser.BrowserViewModel.Command.DisplayMessage
import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter
import com.duckduckgo.app.cta.db.DismissedCtaDao
import com.duckduckgo.app.cta.model.CtaId
import com.duckduckgo.app.fire.DataClearer
import com.duckduckgo.app.global.events.db.UserEventsStore
import com.duckduckgo.app.global.rating.AppEnjoymentPromptEmitter
import com.duckduckgo.app.global.rating.AppEnjoymentPromptOptions
import com.duckduckgo.app.global.rating.AppEnjoymentUserEventRecorder
import com.duckduckgo.app.global.rating.PromptCount
import com.duckduckgo.app.global.useourapp.UseOurAppDetector.Companion.USE_OUR_APP_SHORTCUT_URL
import com.duckduckgo.app.global.useourapp.UseOurAppDetector
import com.duckduckgo.app.global.useourapp.UseOurAppDetector.Companion.USE_OUR_APP_DOMAIN
import com.duckduckgo.app.privacy.ui.PrivacyDashboardActivity
import com.duckduckgo.app.runBlocking
import com.duckduckgo.app.statistics.pixels.Pixel
Expand Down Expand Up @@ -85,7 +85,7 @@ class BrowserViewModelTest {
private lateinit var mockPixel: Pixel

@Mock
private lateinit var mockDismissedCtaDao: DismissedCtaDao
private lateinit var mockUserEventsStore: UserEventsStore

private lateinit var testee: BrowserViewModel

Expand All @@ -101,7 +101,7 @@ class BrowserViewModelTest {
dataClearer = mockAutomaticDataClearer,
appEnjoymentPromptEmitter = mockAppEnjoymentPromptEmitter,
appEnjoymentUserEventRecorder = mockAppEnjoymentUserEventRecorder,
ctaDao = mockDismissedCtaDao,
useOurAppDetector = UseOurAppDetector(mockUserEventsStore),
dispatchers = coroutinesTestRule.testDispatcherProvider,
pixel = mockPixel
)
Expand Down Expand Up @@ -193,23 +193,13 @@ class BrowserViewModelTest {
}

@Test
fun whenOpenShortcutIfUrlIsUseOurAppUrlAndCtaHasBeenSeenThenFirePixel() {
givenUseOurAppCtaHasBeenSeen()
val url = USE_OUR_APP_SHORTCUT_URL
fun whenOpenShortcutIfUrlIsUseOurAppDomainThenFirePixel() {
val url = "http://m.$USE_OUR_APP_DOMAIN"
whenever(mockOmnibarEntryConverter.convertQueryToUrl(url)).thenReturn(url)
testee.onOpenShortcut(url)
verify(mockPixel).fire(Pixel.PixelName.USE_OUR_APP_SHORTCUT_OPENED)
}

@Test
fun whenOpenShortcutIfUrlIsUseOurAppUrlAndCtaHasNotBeenSeenThenDoNotFireUseOurAppPixel() {
val url = USE_OUR_APP_SHORTCUT_URL
whenever(mockOmnibarEntryConverter.convertQueryToUrl(url)).thenReturn(url)
testee.onOpenShortcut(url)
verify(mockPixel, never()).fire(Pixel.PixelName.USE_OUR_APP_SHORTCUT_OPENED)
verify(mockPixel).fire(Pixel.PixelName.SHORTCUT_OPENED)
}

@Test
fun whenOpenShortcutIfUrlIsNotUSeOurAppUrlThenFirePixel() {
val url = "example.com"
Expand All @@ -218,10 +208,6 @@ class BrowserViewModelTest {
verify(mockPixel).fire(Pixel.PixelName.SHORTCUT_OPENED)
}

private fun givenUseOurAppCtaHasBeenSeen() {
whenever(mockDismissedCtaDao.exists(CtaId.USE_OUR_APP)).thenReturn(true)
}

companion object {
const val TAB_ID = "TAB_ID"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ package com.duckduckgo.app.browser.shortcut

import android.content.Intent
import com.duckduckgo.app.CoroutineTestRule
import com.duckduckgo.app.cta.db.DismissedCtaDao
import com.duckduckgo.app.cta.model.CtaId
import com.duckduckgo.app.global.events.db.UserEventKey
import com.duckduckgo.app.global.events.db.UserEventsStore
import com.duckduckgo.app.global.useourapp.UseOurAppDetector.Companion.USE_OUR_APP_SHORTCUT_URL
import com.duckduckgo.app.global.useourapp.UseOurAppDetector
import com.duckduckgo.app.runBlocking
import com.duckduckgo.app.statistics.Variant
import com.duckduckgo.app.statistics.VariantManager
import com.duckduckgo.app.statistics.pixels.Pixel
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.never
Expand All @@ -42,70 +42,89 @@ class ShortcutReceiverTest {

private val mockUserEventsStore: UserEventsStore = mock()
private val mockPixel: Pixel = mock()
private val mockDismissedCtaDao: DismissedCtaDao = mock()
private val mockVariantManager: VariantManager = mock()
private lateinit var testee: ShortcutReceiver

@Before
fun before() {
testee = ShortcutReceiver(mockUserEventsStore, mockDismissedCtaDao, coroutinesTestRule.testDispatcherProvider, mockPixel)
testee = ShortcutReceiver(
mockUserEventsStore,
coroutinesTestRule.testDispatcherProvider,
UseOurAppDetector(mockUserEventsStore),
mockVariantManager,
mockPixel
)
}

@Test
fun whenIntentReceivedIfUrlIsFromUseOurAppUrlThenRegisterTimestamp() = coroutinesTestRule.runBlocking {
givenUseOurAppCtaHasBeenSeen()
fun whenIntentReceivedIfUrlIsFromUseOurAppDomainAndVariantIsInAppUsageThenRegisterTimestamp() = coroutinesTestRule.runBlocking {
setInAppUsageVariant()
val intent = Intent()
intent.putExtra(ShortcutBuilder.SHORTCUT_URL_ARG, USE_OUR_APP_SHORTCUT_URL)
intent.putExtra(ShortcutBuilder.SHORTCUT_URL_ARG, "https://facebook.com")
intent.putExtra(ShortcutBuilder.SHORTCUT_TITLE_ARG, "Title")
testee.onReceive(null, intent)

verify(mockUserEventsStore).registerUserEvent(UserEventKey.USE_OUR_APP_SHORTCUT_ADDED)
}

@Test
fun whenIntentReceivedIfUrlIsFromUseOurAppUrlThenFirePixel() {
givenUseOurAppCtaHasBeenSeen()
fun whenIntentReceivedIfUrlIsFromUseOurAppDomainAndVariantIsNotInAppUsageThenDoNotRegisterTimestamp() = coroutinesTestRule.runBlocking {
setDefaultVariant()
val intent = Intent()
intent.putExtra(ShortcutBuilder.SHORTCUT_URL_ARG, USE_OUR_APP_SHORTCUT_URL)
intent.putExtra(ShortcutBuilder.SHORTCUT_URL_ARG, "https://facebook.com")
intent.putExtra(ShortcutBuilder.SHORTCUT_TITLE_ARG, "Title")
testee.onReceive(null, intent)

verify(mockPixel).fire(Pixel.PixelName.USE_OUR_APP_SHORTCUT_ADDED)
verify(mockUserEventsStore, never()).registerUserEvent(UserEventKey.USE_OUR_APP_SHORTCUT_ADDED)
}

@Test
fun whenIntentReceivedIfUrlIsNotFromUseOurAppUrlThenDoNotRegisterEvent() = coroutinesTestRule.runBlocking {
givenUseOurAppCtaHasBeenSeen()
fun whenIntentReceivedIfUrlContainsUseOurAppDomainThenFirePixel() {
setDefaultVariant()
val intent = Intent()
intent.putExtra(ShortcutBuilder.SHORTCUT_URL_ARG, "www.example.com")
intent.putExtra(ShortcutBuilder.SHORTCUT_URL_ARG, "https://facebook.com")
intent.putExtra(ShortcutBuilder.SHORTCUT_TITLE_ARG, "Title")
testee.onReceive(null, intent)

verify(mockUserEventsStore, never()).registerUserEvent(UserEventKey.USE_OUR_APP_SHORTCUT_ADDED)
verify(mockPixel).fire(Pixel.PixelName.USE_OUR_APP_SHORTCUT_ADDED)
}

@Test
fun whenIntentReceivedIfUrlIsNotFromUseOurAppUrlThenFireShortcutAddedPixel() {
fun whenIntentReceivedIfUrlIsNotFromUseOurAppDomainThenDoNotRegisterEvent() = coroutinesTestRule.runBlocking {
setDefaultVariant()
val intent = Intent()
intent.putExtra(ShortcutBuilder.SHORTCUT_URL_ARG, "www.example.com")
intent.putExtra(ShortcutBuilder.SHORTCUT_TITLE_ARG, "Title")
testee.onReceive(null, intent)

verify(mockPixel).fire(Pixel.PixelName.SHORTCUT_ADDED)
verify(mockUserEventsStore, never()).registerUserEvent(UserEventKey.USE_OUR_APP_SHORTCUT_ADDED)
}

@Test
fun whenIntentReceivedAndCtaNotSeenIfUrlIsFromUseOurAppUrlThenDoNotFireUseOurAppPixelAndFireShortcutPixel() = coroutinesTestRule.runBlocking {
fun whenIntentReceivedIfUrlIsNotFromUseOurAppDomainThenFireShortcutAddedPixel() {
setDefaultVariant()
val intent = Intent()
intent.putExtra(ShortcutBuilder.SHORTCUT_URL_ARG, USE_OUR_APP_SHORTCUT_URL)

intent.putExtra(ShortcutBuilder.SHORTCUT_URL_ARG, "www.example.com")
intent.putExtra(ShortcutBuilder.SHORTCUT_TITLE_ARG, "Title")
testee.onReceive(null, intent)

verify(mockPixel, never()).fire(Pixel.PixelName.USE_OUR_APP_SHORTCUT_ADDED)
verify(mockPixel).fire(Pixel.PixelName.SHORTCUT_ADDED)
}

private fun givenUseOurAppCtaHasBeenSeen() {
whenever(mockDismissedCtaDao.exists(CtaId.USE_OUR_APP)).thenReturn(true)
private fun setDefaultVariant() {
whenever(mockVariantManager.getVariant()).thenReturn(VariantManager.DEFAULT_VARIANT)
}

private fun setInAppUsageVariant() {
whenever(mockVariantManager.getVariant()).thenReturn(
Variant(
"test",
features = listOf(
VariantManager.VariantFeature.InAppUsage,
VariantManager.VariantFeature.RemoveDay1AndDay3Notifications,
VariantManager.VariantFeature.KillOnboarding
),
filterBy = { true })
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import com.duckduckgo.app.blockingObserve
import com.duckduckgo.app.browser.addtohome.AddToHomeCapabilityDetector
import com.duckduckgo.app.global.exception.UncaughtExceptionEntity
import com.duckduckgo.app.global.exception.UncaughtExceptionSource
import com.duckduckgo.app.global.useourapp.MigrationManager
import com.duckduckgo.app.onboarding.store.AppStage
import com.duckduckgo.app.runBlocking
import com.duckduckgo.app.settings.db.SettingsDataStore
Expand Down Expand Up @@ -63,10 +62,9 @@ class AppDatabaseTest {
private val context = mock<Context>()
private val mockSettingsDataStore = mock<SettingsDataStore>()
private val mockAddToHomeCapabilityDetector = mock<AddToHomeCapabilityDetector>()
private val mockUseOurAppMigrationManager = mock<MigrationManager>()

private val migrationsProvider: MigrationsProvider =
MigrationsProvider(context, mockSettingsDataStore, mockAddToHomeCapabilityDetector, mockUseOurAppMigrationManager)
MigrationsProvider(context, mockSettingsDataStore, mockAddToHomeCapabilityDetector)

@Before
fun setup() {
Expand Down Expand Up @@ -234,76 +232,34 @@ class AppDatabaseTest {
}

@Test
fun whenMigratingFromVersion21To22IfUserIsEstablishedAndConditionsAreMetThenMigrateToNotification() {
testHelper.createDatabase(TEST_DB_NAME, 21).use {
givenUseOurAppStateIs(canMigrate = true, hideTips = false, canAddToHome = true)
givenUserStageIs(it, AppStage.ESTABLISHED)

testHelper.runMigrationsAndValidate(TEST_DB_NAME, 22, true, migrationsProvider.MIGRATION_21_TO_22)
val stage = getUserStage(it)

assertEquals(AppStage.USE_OUR_APP_NOTIFICATION.name, stage)
}
}

@Test
fun whenMigratingFromVersion21To22IfUserIsEstablishedAndHideTipsIsTrueThenDoNotMigrateToNotification() {
testHelper.createDatabase(TEST_DB_NAME, 21).use {
givenUseOurAppStateIs(canMigrate = true, hideTips = true, canAddToHome = true)
givenUserStageIs(it, AppStage.ESTABLISHED)

testHelper.runMigrationsAndValidate(TEST_DB_NAME, 22, true, migrationsProvider.MIGRATION_21_TO_22)
val stage = getUserStage(it)

assertEquals(AppStage.ESTABLISHED.name, stage)
}
fun whenMigratingFromVersion22To23ThenValidationSucceeds() {
createDatabaseAndMigrate(22, 23, migrationsProvider.MIGRATION_22_TO_23)
}

@Test
fun whenMigratingFromVersion21To22IfUserIsEstablishedAndHomeShortcutNotSupportedThenDoNotMigrateToNotification() {
testHelper.createDatabase(TEST_DB_NAME, 21).use {
givenUseOurAppStateIs(canMigrate = true, hideTips = false, canAddToHome = false)
givenUserStageIs(it, AppStage.ESTABLISHED)
fun whenMigratingFromVersion22To23IfUserStageIsUseOurAppNotificationThenMigrateToEstablished() {
testHelper.createDatabase(TEST_DB_NAME, 22).use {
givenUserStageIs(it, AppStage.USE_OUR_APP_NOTIFICATION)

testHelper.runMigrationsAndValidate(TEST_DB_NAME, 22, true, migrationsProvider.MIGRATION_21_TO_22)
testHelper.runMigrationsAndValidate(TEST_DB_NAME, 23, true, migrationsProvider.MIGRATION_22_TO_23)
val stage = getUserStage(it)

assertEquals(AppStage.ESTABLISHED.name, stage)
}
}

@Test
fun whenMigratingFromVersion21To22IfUserIsNotEstablishedThenDoNotMigrateToNotification() {
testHelper.createDatabase(TEST_DB_NAME, 21).use {
givenUseOurAppStateIs(canMigrate = true, hideTips = false, canAddToHome = false)
fun whenMigratingFromVersion22To23IfUserStageIsNotUseOurAppNotificationThenDoNotMigrateToEstablished() {
testHelper.createDatabase(TEST_DB_NAME, 22).use {
givenUserStageIs(it, AppStage.ESTABLISHED)

testHelper.runMigrationsAndValidate(TEST_DB_NAME, 22, true, migrationsProvider.MIGRATION_21_TO_22)
testHelper.runMigrationsAndValidate(TEST_DB_NAME, 23, true, migrationsProvider.MIGRATION_22_TO_23)
val stage = getUserStage(it)

assertEquals(AppStage.ESTABLISHED.name, stage)
}
}

@Test
fun whenMigratingFromVersion21To22IfShouldNotRunMigrationThenDoNotMigrateToNotification2() {
testHelper.createDatabase(TEST_DB_NAME, 21).use {
givenUseOurAppStateIs(canMigrate = false)
givenUserStageIs(it, AppStage.ESTABLISHED)

testHelper.runMigrationsAndValidate(TEST_DB_NAME, 22, true, migrationsProvider.MIGRATION_21_TO_22)
val stage = getUserStage(it)

assertEquals(AppStage.ESTABLISHED.name, stage)
}
}

private fun givenUseOurAppStateIs(canMigrate: Boolean = true, hideTips: Boolean = false, canAddToHome: Boolean = true) {
whenever(mockUseOurAppMigrationManager.shouldRunMigration()).thenReturn(canMigrate)
whenever(mockSettingsDataStore.hideTips).thenReturn(hideTips)
whenever(mockAddToHomeCapabilityDetector.isAddToHomeSupported()).thenReturn(canAddToHome)
}

private fun givenUserStageIs(database: SupportSQLiteDatabase, appStage: AppStage) {
val values: ContentValues = ContentValues().apply {
put("key", 1)
Expand All @@ -316,7 +272,7 @@ class AppDatabaseTest {
}

private fun getUserStage(database: SupportSQLiteDatabase): String {
var stage = ""
var stage: String

database.query("SELECT appStage from userStage limit 1").apply {
moveToFirst()
Expand Down
Loading