1616
1717package com.duckduckgo.app.browser
1818
19+ import android.content.Intent
1920import android.graphics.Bitmap
2021import android.net.Uri
2122import android.view.MenuItem
@@ -47,6 +48,7 @@ import com.duckduckgo.app.browser.BrowserTabViewModel.FireButton
4748import com.duckduckgo.app.browser.LongPressHandler.RequiredAction.DownloadFile
4849import com.duckduckgo.app.browser.LongPressHandler.RequiredAction.OpenInNewTab
4950import com.duckduckgo.app.browser.addtohome.AddToHomeCapabilityDetector
51+ import com.duckduckgo.app.browser.applinks.AppLinksHandler
5052import com.duckduckgo.app.browser.downloader.FileDownloader
5153import com.duckduckgo.app.browser.favicon.FaviconManager
5254import com.duckduckgo.app.browser.favicon.FaviconSource
@@ -112,15 +114,11 @@ import com.duckduckgo.app.trackerdetection.EntityLookup
112114import com.duckduckgo.app.trackerdetection.model.TrackingEvent
113115import com.duckduckgo.app.usage.search.SearchCountDao
114116import com.duckduckgo.app.widget.ui.WidgetCapabilities
117+ import com.nhaarman.mockitokotlin2.*
115118import com.nhaarman.mockitokotlin2.any
116- import com.nhaarman.mockitokotlin2.anyOrNull
117119import com.nhaarman.mockitokotlin2.atLeastOnce
118- import com.nhaarman.mockitokotlin2.doAnswer
119120import com.nhaarman.mockitokotlin2.doReturn
120121import com.nhaarman.mockitokotlin2.eq
121- import com.nhaarman.mockitokotlin2.firstValue
122- import com.nhaarman.mockitokotlin2.lastValue
123- import com.nhaarman.mockitokotlin2.mock
124122import com.nhaarman.mockitokotlin2.whenever
125123import dagger.Lazy
126124import io.reactivex.Observable
@@ -143,11 +141,13 @@ import org.junit.Before
143141import org.junit.Rule
144142import org.junit.Test
145143import org.mockito.ArgumentCaptor
146- import org.mockito.ArgumentMatchers.anyString
147144import org.mockito.Captor
148145import org.mockito.Mock
149146import org.mockito.Mockito
150147import org.mockito.Mockito.*
148+ import org.mockito.Mockito.never
149+ import org.mockito.Mockito.times
150+ import org.mockito.Mockito.verify
151151import org.mockito.MockitoAnnotations
152152import org.mockito.internal.util.DefaultMockingDetails
153153import java.io.File
@@ -264,6 +264,12 @@ class BrowserTabViewModelTest {
264264 @Mock
265265 private lateinit var mockFavoritesRepository: FavoritesRepository
266266
267+ @Mock
268+ private lateinit var mockSpecialUrlDetector: SpecialUrlDetector
269+
270+ @Mock
271+ private lateinit var mockAppLinksHandler: AppLinksHandler
272+
267273 private val lazyFaviconManager = Lazy { mockFaviconManager }
268274
269275 private lateinit var mockAutoCompleteApi: AutoCompleteApi
@@ -273,6 +279,9 @@ class BrowserTabViewModelTest {
273279 @Captor
274280 private lateinit var commandCaptor: ArgumentCaptor <Command >
275281
282+ @Captor
283+ private lateinit var appLinkCaptor: ArgumentCaptor < () -> Unit >
284+
276285 private lateinit var db: AppDatabase
277286
278287 private lateinit var testee: BrowserTabViewModel
@@ -352,7 +361,7 @@ class BrowserTabViewModelTest {
352361 bookmarksDao = mockBookmarksDao,
353362 longPressHandler = mockLongPressHandler,
354363 webViewSessionStorage = webViewSessionStorage,
355- specialUrlDetector = SpecialUrlDetectorImpl () ,
364+ specialUrlDetector = mockSpecialUrlDetector ,
356365 faviconManager = mockFaviconManager,
357366 addToHomeCapabilityDetector = mockAddToHomeCapabilityDetector,
358367 ctaViewModel = ctaViewModel,
@@ -375,7 +384,8 @@ class BrowserTabViewModelTest {
375384 fireproofDialogsEventHandler = fireproofDialogsEventHandler,
376385 emailManager = mockEmailManager,
377386 favoritesRepository = mockFavoritesRepository,
378- appCoroutineScope = TestCoroutineScope ()
387+ appCoroutineScope = TestCoroutineScope (),
388+ appLinksHandler = mockAppLinksHandler
379389 )
380390
381391 testee.loadData(" abc" , null , false )
@@ -1125,6 +1135,14 @@ class BrowserTabViewModelTest {
11251135 assertTrue(commandCaptor.allValues.any { it == Command .HideKeyboard })
11261136 }
11271137
1138+ @Test
1139+ fun whenEnteringAppLinkQueryThenNavigateInBrowser () {
1140+ whenever(mockOmnibarConverter.convertQueryToUrl(" foo" , null )).thenReturn(" foo.com" )
1141+ testee.onUserSubmittedQuery(" foo" )
1142+ verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
1143+ assertTrue(commandCaptor.allValues.any { it == Command .HideKeyboard })
1144+ }
1145+
11281146 @Test
11291147 fun whenNotifiedEnteringFullScreenThenViewStateUpdatedWithFullScreenFlag () {
11301148 val stubView = View (getInstrumentation().targetContext)
@@ -3011,24 +3029,24 @@ class BrowserTabViewModelTest {
30113029 @Test
30123030 fun whenExternalAppLinkClickedIfGpcIsEnabledThenAddHeaderToUrl () {
30133031 whenever(mockSettingsStore.globalPrivacyControlEnabled).thenReturn(true )
3014- val intentType = SpecialUrlDetector .UrlType .IntentType (" query" , mock(), null )
3032+ val intentType = SpecialUrlDetector .UrlType .NonHttpAppLink (" query" , mock(), null )
30153033
3016- testee.externalAppLinkClicked (intentType)
3034+ testee.nonHttpAppLinkClicked (intentType)
30173035 verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
30183036
3019- val command = commandCaptor.lastValue as Command .HandleExternalAppLink
3037+ val command = commandCaptor.lastValue as Command .HandleNonHttpAppLink
30203038 assertEquals(GPC_HEADER_VALUE , command.headers[GPC_HEADER ])
30213039 }
30223040
30233041 @Test
30243042 fun whenExternalAppLinkClickedIfGpcIsDisabledThenDoNotAddHeaderToUrl () {
30253043 whenever(mockSettingsStore.globalPrivacyControlEnabled).thenReturn(false )
3026- val intentType = SpecialUrlDetector .UrlType .IntentType (" query" , mock(), null )
3044+ val intentType = SpecialUrlDetector .UrlType .NonHttpAppLink (" query" , mock(), null )
30273045
3028- testee.externalAppLinkClicked (intentType)
3046+ testee.nonHttpAppLinkClicked (intentType)
30293047 verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
30303048
3031- val command = commandCaptor.lastValue as Command .HandleExternalAppLink
3049+ val command = commandCaptor.lastValue as Command .HandleNonHttpAppLink
30323050 assertTrue(command.headers.isEmpty())
30333051 }
30343052
@@ -3197,6 +3215,39 @@ class BrowserTabViewModelTest {
31973215 assertCommandNotIssued<Command .ShowEmailTooltip >()
31983216 }
31993217
3218+ @Test
3219+ fun whenHandleAppLinkCalledThenHandleAppLink () {
3220+ val urlType = SpecialUrlDetector .UrlType .AppLink (uriString = " http://example.com" )
3221+ testee.handleAppLink(urlType, isRedirect = false , isForMainFrame = true )
3222+ verify(mockAppLinksHandler).handleAppLink(isRedirect = eq(false ), isForMainFrame = eq(true ), capture(appLinkCaptor))
3223+ appLinkCaptor.value.invoke()
3224+ assertCommandIssued<Command .HandleAppLink >()
3225+ }
3226+
3227+ @Test
3228+ fun whenHandleNonHttpAppLinkCalledThenHandleNonHttpAppLink () {
3229+ val urlType = SpecialUrlDetector .UrlType .NonHttpAppLink (" market://details?id=com.example" , Intent (), " http://example.com" )
3230+ testee.handleNonHttpAppLink(urlType, false )
3231+ verify(mockAppLinksHandler).handleNonHttpAppLink(isRedirect = eq(false ), capture(appLinkCaptor))
3232+ appLinkCaptor.value.invoke()
3233+ assertCommandIssued<Command .HandleNonHttpAppLink >()
3234+ }
3235+
3236+ @Test
3237+ fun whenResetAppLinkStateCalledThenResetAppLinkState () {
3238+ testee.resetAppLinkState()
3239+ verify(mockAppLinksHandler).reset()
3240+ }
3241+
3242+ @Test
3243+ fun whenUserSubmittedQueryIsAppLinkThenOpenAppLinkInBrowser () {
3244+ whenever(mockOmnibarConverter.convertQueryToUrl(" foo" , null )).thenReturn(" foo.com" )
3245+ whenever(mockSpecialUrlDetector.determineType(anyString())).thenReturn(SpecialUrlDetector .UrlType .AppLink (uriString = " http://foo.com" ))
3246+ testee.onUserSubmittedQuery(" foo" )
3247+ verify(mockAppLinksHandler).enterBrowserState()
3248+ assertCommandIssued<Navigate >()
3249+ }
3250+
32003251 private suspend fun givenFireButtonPulsing () {
32013252 whenever(mockUserStageStore.getUserAppStage()).thenReturn(AppStage .DAX_ONBOARDING )
32023253 dismissedCtaDaoChannel.send(listOf (DismissedCta (CtaId .DAX_DIALOG_TRACKERS_FOUND )))
0 commit comments