16
16
17
17
package com.duckduckgo.app.browser
18
18
19
+ import android.content.Intent
19
20
import android.graphics.Bitmap
20
21
import android.net.Uri
21
22
import android.view.MenuItem
@@ -47,6 +48,7 @@ import com.duckduckgo.app.browser.BrowserTabViewModel.FireButton
47
48
import com.duckduckgo.app.browser.LongPressHandler.RequiredAction.DownloadFile
48
49
import com.duckduckgo.app.browser.LongPressHandler.RequiredAction.OpenInNewTab
49
50
import com.duckduckgo.app.browser.addtohome.AddToHomeCapabilityDetector
51
+ import com.duckduckgo.app.browser.applinks.AppLinksHandler
50
52
import com.duckduckgo.app.browser.downloader.FileDownloader
51
53
import com.duckduckgo.app.browser.favicon.FaviconManager
52
54
import com.duckduckgo.app.browser.favicon.FaviconSource
@@ -112,15 +114,11 @@ import com.duckduckgo.app.trackerdetection.EntityLookup
112
114
import com.duckduckgo.app.trackerdetection.model.TrackingEvent
113
115
import com.duckduckgo.app.usage.search.SearchCountDao
114
116
import com.duckduckgo.app.widget.ui.WidgetCapabilities
117
+ import com.nhaarman.mockitokotlin2.*
115
118
import com.nhaarman.mockitokotlin2.any
116
- import com.nhaarman.mockitokotlin2.anyOrNull
117
119
import com.nhaarman.mockitokotlin2.atLeastOnce
118
- import com.nhaarman.mockitokotlin2.doAnswer
119
120
import com.nhaarman.mockitokotlin2.doReturn
120
121
import com.nhaarman.mockitokotlin2.eq
121
- import com.nhaarman.mockitokotlin2.firstValue
122
- import com.nhaarman.mockitokotlin2.lastValue
123
- import com.nhaarman.mockitokotlin2.mock
124
122
import com.nhaarman.mockitokotlin2.whenever
125
123
import dagger.Lazy
126
124
import io.reactivex.Observable
@@ -135,18 +133,21 @@ import kotlinx.coroutines.flow.asStateFlow
135
133
import kotlinx.coroutines.flow.consumeAsFlow
136
134
import kotlinx.coroutines.flow.flowOf
137
135
import kotlinx.coroutines.runBlocking
136
+ import kotlinx.coroutines.test.TestCoroutineScope
138
137
import kotlinx.coroutines.test.runBlockingTest
139
138
import org.junit.After
140
139
import org.junit.Assert.*
141
140
import org.junit.Before
142
141
import org.junit.Rule
143
142
import org.junit.Test
144
143
import org.mockito.ArgumentCaptor
145
- import org.mockito.ArgumentMatchers.anyString
146
144
import org.mockito.Captor
147
145
import org.mockito.Mock
148
146
import org.mockito.Mockito
149
147
import org.mockito.Mockito.*
148
+ import org.mockito.Mockito.never
149
+ import org.mockito.Mockito.times
150
+ import org.mockito.Mockito.verify
150
151
import org.mockito.MockitoAnnotations
151
152
import org.mockito.internal.util.DefaultMockingDetails
152
153
import java.io.File
@@ -263,6 +264,12 @@ class BrowserTabViewModelTest {
263
264
@Mock
264
265
private lateinit var mockFavoritesRepository: FavoritesRepository
265
266
267
+ @Mock
268
+ private lateinit var mockSpecialUrlDetector: SpecialUrlDetector
269
+
270
+ @Mock
271
+ private lateinit var mockAppLinksHandler: AppLinksHandler
272
+
266
273
private val lazyFaviconManager = Lazy { mockFaviconManager }
267
274
268
275
private lateinit var mockAutoCompleteApi: AutoCompleteApi
@@ -272,6 +279,9 @@ class BrowserTabViewModelTest {
272
279
@Captor
273
280
private lateinit var commandCaptor: ArgumentCaptor <Command >
274
281
282
+ @Captor
283
+ private lateinit var appLinkCaptor: ArgumentCaptor < () -> Unit >
284
+
275
285
private lateinit var db: AppDatabase
276
286
277
287
private lateinit var testee: BrowserTabViewModel
@@ -351,7 +361,7 @@ class BrowserTabViewModelTest {
351
361
bookmarksDao = mockBookmarksDao,
352
362
longPressHandler = mockLongPressHandler,
353
363
webViewSessionStorage = webViewSessionStorage,
354
- specialUrlDetector = SpecialUrlDetectorImpl () ,
364
+ specialUrlDetector = mockSpecialUrlDetector ,
355
365
faviconManager = mockFaviconManager,
356
366
addToHomeCapabilityDetector = mockAddToHomeCapabilityDetector,
357
367
ctaViewModel = ctaViewModel,
@@ -373,7 +383,9 @@ class BrowserTabViewModelTest {
373
383
globalPrivacyControl = GlobalPrivacyControlManager (mockSettingsStore),
374
384
fireproofDialogsEventHandler = fireproofDialogsEventHandler,
375
385
emailManager = mockEmailManager,
376
- favoritesRepository = mockFavoritesRepository
386
+ favoritesRepository = mockFavoritesRepository,
387
+ appCoroutineScope = TestCoroutineScope (),
388
+ appLinksHandler = mockAppLinksHandler
377
389
)
378
390
379
391
testee.loadData(" abc" , null , false )
@@ -558,17 +570,6 @@ class BrowserTabViewModelTest {
558
570
verify(mockFavoritesRepository, times(0 )).insert(any(), any())
559
571
}
560
572
561
- @Test
562
- fun whenQuickAccessItemClickedThenSubmitNewQuery () {
563
- val savedSite = Favorite (1 , " title" , " http://example.com" , 0 )
564
-
565
- testee.onQuickAccesItemClicked(savedSite)
566
-
567
- assertCommandIssued<Command .SubmitQuery > {
568
- assertEquals(" http://example.com" , this .url)
569
- }
570
- }
571
-
572
573
@Test
573
574
fun whenQuickAccessDeletedThenRepositoryUpdated () = coroutineRule.runBlocking {
574
575
val savedSite = Favorite (1 , " title" , " http://example.com" , 0 )
@@ -1123,6 +1124,14 @@ class BrowserTabViewModelTest {
1123
1124
assertTrue(commandCaptor.allValues.any { it == Command .HideKeyboard })
1124
1125
}
1125
1126
1127
+ @Test
1128
+ fun whenEnteringAppLinkQueryThenNavigateInBrowser () {
1129
+ whenever(mockOmnibarConverter.convertQueryToUrl(" foo" , null )).thenReturn(" foo.com" )
1130
+ testee.onUserSubmittedQuery(" foo" )
1131
+ verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
1132
+ assertTrue(commandCaptor.allValues.any { it == Command .HideKeyboard })
1133
+ }
1134
+
1126
1135
@Test
1127
1136
fun whenNotifiedEnteringFullScreenThenViewStateUpdatedWithFullScreenFlag () {
1128
1137
val stubView = View (getInstrumentation().targetContext)
@@ -3009,24 +3018,24 @@ class BrowserTabViewModelTest {
3009
3018
@Test
3010
3019
fun whenExternalAppLinkClickedIfGpcIsEnabledThenAddHeaderToUrl () {
3011
3020
whenever(mockSettingsStore.globalPrivacyControlEnabled).thenReturn(true )
3012
- val intentType = SpecialUrlDetector .UrlType .IntentType (" query" , mock(), null )
3021
+ val intentType = SpecialUrlDetector .UrlType .NonHttpAppLink (" query" , mock(), null )
3013
3022
3014
- testee.externalAppLinkClicked (intentType)
3023
+ testee.nonHttpAppLinkClicked (intentType)
3015
3024
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
3016
3025
3017
- val command = commandCaptor.lastValue as Command .HandleExternalAppLink
3026
+ val command = commandCaptor.lastValue as Command .HandleNonHttpAppLink
3018
3027
assertEquals(GPC_HEADER_VALUE , command.headers[GPC_HEADER ])
3019
3028
}
3020
3029
3021
3030
@Test
3022
3031
fun whenExternalAppLinkClickedIfGpcIsDisabledThenDoNotAddHeaderToUrl () {
3023
3032
whenever(mockSettingsStore.globalPrivacyControlEnabled).thenReturn(false )
3024
- val intentType = SpecialUrlDetector .UrlType .IntentType (" query" , mock(), null )
3033
+ val intentType = SpecialUrlDetector .UrlType .NonHttpAppLink (" query" , mock(), null )
3025
3034
3026
- testee.externalAppLinkClicked (intentType)
3035
+ testee.nonHttpAppLinkClicked (intentType)
3027
3036
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
3028
3037
3029
- val command = commandCaptor.lastValue as Command .HandleExternalAppLink
3038
+ val command = commandCaptor.lastValue as Command .HandleNonHttpAppLink
3030
3039
assertTrue(command.headers.isEmpty())
3031
3040
}
3032
3041
@@ -3195,6 +3204,54 @@ class BrowserTabViewModelTest {
3195
3204
assertCommandNotIssued<Command .ShowEmailTooltip >()
3196
3205
}
3197
3206
3207
+ @Test
3208
+ fun whenHandleAppLinkCalledThenHandleAppLink () {
3209
+ val urlType = SpecialUrlDetector .UrlType .AppLink (uriString = " http://example.com" )
3210
+ testee.handleAppLink(urlType, isRedirect = false , isForMainFrame = true )
3211
+ verify(mockAppLinksHandler).handleAppLink(isRedirect = eq(false ), isForMainFrame = eq(true ), capture(appLinkCaptor))
3212
+ appLinkCaptor.value.invoke()
3213
+ assertCommandIssued<Command .HandleAppLink >()
3214
+ }
3215
+
3216
+ @Test
3217
+ fun whenHandleNonHttpAppLinkCalledThenHandleNonHttpAppLink () {
3218
+ val urlType = SpecialUrlDetector .UrlType .NonHttpAppLink (" market://details?id=com.example" , Intent (), " http://example.com" )
3219
+ testee.handleNonHttpAppLink(urlType, false )
3220
+ verify(mockAppLinksHandler).handleNonHttpAppLink(isRedirect = eq(false ), capture(appLinkCaptor))
3221
+ appLinkCaptor.value.invoke()
3222
+ assertCommandIssued<Command .HandleNonHttpAppLink >()
3223
+ }
3224
+
3225
+ @Test
3226
+ fun whenResetAppLinkStateCalledThenResetAppLinkState () {
3227
+ testee.resetAppLinkState()
3228
+ verify(mockAppLinksHandler).reset()
3229
+ }
3230
+
3231
+ @Test
3232
+ fun whenUserSubmittedQueryIsAppLinkThenOpenAppLinkInBrowser () {
3233
+ whenever(mockOmnibarConverter.convertQueryToUrl(" foo" , null )).thenReturn(" foo.com" )
3234
+ whenever(mockSpecialUrlDetector.determineType(anyString())).thenReturn(SpecialUrlDetector .UrlType .AppLink (uriString = " http://foo.com" ))
3235
+ testee.onUserSubmittedQuery(" foo" )
3236
+ verify(mockAppLinksHandler).enterBrowserState()
3237
+ assertCommandIssued<Navigate >()
3238
+ }
3239
+
3240
+ @Test
3241
+ fun whenSubmittedQueryAndNavigationStateIsNullThenResetHistoryCommandSent () {
3242
+ whenever(mockOmnibarConverter.convertQueryToUrl(" nytimes.com" , null )).thenReturn(" nytimes.com" )
3243
+ testee.onUserSubmittedQuery(" nytimes.com" )
3244
+ assertCommandIssued<Command .ResetHistory >()
3245
+ }
3246
+
3247
+ @Test
3248
+ fun whenSubmittedQueryAndNavigationStateIsNotNullThenResetHistoryCommandNotSent () {
3249
+ setupNavigation(isBrowsing = true )
3250
+ whenever(mockOmnibarConverter.convertQueryToUrl(" nytimes.com" , null )).thenReturn(" nytimes.com" )
3251
+ testee.onUserSubmittedQuery(" nytimes.com" )
3252
+ assertCommandNotIssued<Command .ResetHistory >()
3253
+ }
3254
+
3198
3255
private suspend fun givenFireButtonPulsing () {
3199
3256
whenever(mockUserStageStore.getUserAppStage()).thenReturn(AppStage .DAX_ONBOARDING )
3200
3257
dismissedCtaDaoChannel.send(listOf (DismissedCta (CtaId .DAX_DIALOG_TRACKERS_FOUND )))
0 commit comments