@@ -32,7 +32,7 @@ import com.duckduckgo.app.browser.BrowserTabViewModel.Command.DisplayMessage
3232import com.duckduckgo.app.browser.BrowserTabViewModel.Command.Navigate
3333import com.duckduckgo.app.browser.LongPressHandler.RequiredAction.DownloadFile
3434import com.duckduckgo.app.browser.LongPressHandler.RequiredAction.OpenInNewTab
35- import com.duckduckgo.app.browser.addToHome .AddToHomeCapabilityDetector
35+ import com.duckduckgo.app.browser.addtohome .AddToHomeCapabilityDetector
3636import com.duckduckgo.app.browser.favicon.FaviconDownloader
3737import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter
3838import com.duckduckgo.app.browser.session.WebViewSessionStorage
@@ -92,9 +92,6 @@ class BrowserTabViewModelTest {
9292 @Mock
9393 private lateinit var mockStatisticsUpdater: StatisticsUpdater
9494
95- @Mock
96- private lateinit var mockQueryObserver: Observer <String >
97-
9895 @Mock
9996 private lateinit var mockCommandObserver: Observer <Command >
10097
@@ -201,7 +198,6 @@ class BrowserTabViewModelTest {
201198 )
202199
203200 testee.loadData(" abc" , null )
204- testee.url.observeForever(mockQueryObserver)
205201 testee.command.observeForever(mockCommandObserver)
206202
207203 whenever(mockOmnibarConverter.convertQueryToUrl(any())).thenReturn(" duckduckgo.com" )
@@ -212,7 +208,6 @@ class BrowserTabViewModelTest {
212208 fun after () {
213209 testee.onCleared()
214210 db.close()
215- testee.url.removeObserver(mockQueryObserver)
216211 testee.command.removeObserver(mockCommandObserver)
217212 }
218213
@@ -250,15 +245,15 @@ class BrowserTabViewModelTest {
250245
251246 @Test
252247 fun whenViewBecomesVisibleWithActiveSiteThenKeyboardHidden () {
253- testee.url.value = " http://exmaple.com"
248+ changeUrl( " http://exmaple.com" )
254249 testee.onViewVisible()
255250 verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
256251 assertTrue(commandCaptor.allValues.contains(Command .HideKeyboard ))
257252 }
258253
259254 @Test
260255 fun whenViewBecomesVisibleWithoutActiveSiteThenKeyboardShown () {
261- testee.url.value = null
256+ changeUrl( null )
262257 testee.onViewVisible()
263258 verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
264259 assertTrue(commandCaptor.allValues.contains(Command .ShowKeyboard ))
@@ -272,13 +267,13 @@ class BrowserTabViewModelTest {
272267
273268 @Test
274269 fun whenUrlPresentThenAddBookmarkButtonEnabled () {
275- testee.urlChanged (" www.example.com" )
270+ changeUrl (" www.example.com" )
276271 assertTrue(browserViewState().canAddBookmarks)
277272 }
278273
279274 @Test
280275 fun whenNoUrlThenAddBookmarkButtonDisabled () {
281- testee.urlChanged (null )
276+ changeUrl (null )
282277 assertFalse(browserViewState().canAddBookmarks)
283278 }
284279
@@ -298,26 +293,27 @@ class BrowserTabViewModelTest {
298293 }
299294
300295 @Test
301- fun whenEmptyInputQueryThenNoQueryMadeAvailableToActivity () {
296+ fun whenEmptyInputQueryThenQueryNavigateCommandNotSubmittedToActivityActivity () {
302297 testee.onUserSubmittedQuery(" " )
303- verify(mockQueryObserver , never()).onChanged(ArgumentMatchers .anyString ())
298+ verify(mockCommandObserver , never()).onChanged(commandCaptor.capture ())
304299 }
305300
306301 @Test
307- fun whenBlankInputQueryThenNoQueryMadeAvailableToActivity () {
302+ fun whenBlankInputQueryThenQueryNavigateCommandNotSubmittedToActivity () {
308303 testee.onUserSubmittedQuery(" " )
309- verify(mockQueryObserver , never()).onChanged(ArgumentMatchers .anyString ())
304+ verify(mockCommandObserver , never()).onChanged(commandCaptor.capture ())
310305 }
311306
312307 @Test
313- fun whenNonEmptyInputThenQueryMadeAvailableToActivity () {
308+ fun whenNonEmptyInputThenNavigateCommandSubmittedToActivity () {
314309 testee.onUserSubmittedQuery(" foo" )
315- verify(mockQueryObserver).onChanged(ArgumentMatchers .anyString())
310+ verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
311+ assertTrue(commandCaptor.lastValue is Navigate )
316312 }
317313
318314 @Test
319315 fun whenViewModelNotifiedThatWebViewIsLoadingThenViewStateIsUpdated () {
320- testee.loadingStarted()
316+ testee.loadingStarted(" http://example.com " )
321317 assertTrue(loadingViewState().isLoading)
322318 }
323319
@@ -327,10 +323,29 @@ class BrowserTabViewModelTest {
327323 assertFalse(loadingViewState().isLoading)
328324 }
329325
326+ @Test
327+ fun whenLoadingFinishedAndInitialUrlNeverProgressedThenUrlUpdated () {
328+ val initialUrl = " http://foo.com/abc"
329+ val finalUrl = " http://bar.com/abc"
330+ testee.loadingStarted(initialUrl)
331+ testee.loadingFinished(finalUrl)
332+ assertEquals(finalUrl, testee.url)
333+ }
334+
335+ @Test
336+ fun whenLoadingFinishedAndInitialUrlProgressedThenUrlNotUpdated () {
337+ val initialUrl = " http://foo.com/abc"
338+ val finalUrl = " http://foo.com/xyz"
339+ testee.loadingStarted(initialUrl)
340+ testee.progressChanged(initialUrl, 10 )
341+ testee.loadingFinished(finalUrl)
342+ assertEquals(initialUrl, testee.url)
343+ }
344+
330345 @Test
331346 fun whenLoadingFinishedWithUrlThenSiteVisitedEntryAddedToLeaderboardDao () {
332- testee.url.value = " http://example.com/abc"
333- testee.loadingFinished(null )
347+ testee.loadingStarted( " http://example.com/abc" )
348+ testee.loadingFinished(" http://example.com/abc " )
334349 verify(mockNetworkLeaderboardDao).insert(SiteVisitedEntity (" example.com" ))
335350 }
336351
@@ -351,7 +366,7 @@ class BrowserTabViewModelTest {
351366 @Test
352367 fun whenLoadingFinishedWithNoUrlThenOmnibarTextUpdatedToMatch () {
353368 val exampleUrl = " http://example.com/abc"
354- testee.urlChanged (exampleUrl)
369+ changeUrl (exampleUrl)
355370 testee.loadingFinished(null )
356371 assertEquals(exampleUrl, omnibarViewState().omnibarText)
357372 }
@@ -385,65 +400,85 @@ class BrowserTabViewModelTest {
385400 assertEquals(" " , omnibarViewState().omnibarText)
386401 }
387402
403+ @Test
404+ fun whenUrlStartsLoadingWithProgressChangeThenUrlUpdated () {
405+ val url = " foo.com"
406+ testee.loadingStarted(url)
407+ testee.progressChanged(url, 10 )
408+ assertEquals(url, testee.url)
409+ }
410+
411+ @Test
412+ fun whenUrlStartsLoadingButProgressHasNotChangedThenUrlNotUpdated () {
413+ testee.loadingStarted(" foo.com" )
414+ assertNull(testee.url)
415+ }
416+
417+ @Test
418+ fun whenUrlHasNotStartedLoadingAndProgressChangeThenUrlNotUpdated () {
419+ testee.progressChanged(" foo.com" , 10 )
420+ assertNull(testee.url)
421+ }
422+
388423 @Test
389424 fun whenUrlChangedThenViewStateIsUpdated () {
390- testee.urlChanged (" duckduckgo.com" )
425+ changeUrl (" duckduckgo.com" )
391426 assertEquals(" duckduckgo.com" , omnibarViewState().omnibarText)
392427 }
393428
394429 @Test
395430 fun whenUrlChangedWithDuckDuckGoUrlContainingQueryThenUrlRewrittenToContainQuery () {
396- testee.urlChanged (" http://duckduckgo.com?q=test" )
431+ changeUrl (" http://duckduckgo.com?q=test" )
397432 assertEquals(" test" , omnibarViewState().omnibarText)
398433 }
399434
400435 @Test
401436 fun whenUrlChangedWithDuckDuckGoUrlContainingQueryThenAtbRefreshed () {
402- testee.urlChanged (" http://duckduckgo.com?q=test" )
437+ changeUrl (" http://duckduckgo.com?q=test" )
403438 verify(mockStatisticsUpdater).refreshRetentionAtb()
404439 }
405440
406441 @Test
407442 fun whenUrlChangedWithDuckDuckGoUrlNotContainingQueryThenFullUrlShown () {
408- testee.urlChanged (" http://duckduckgo.com" )
443+ changeUrl (" http://duckduckgo.com" )
409444 assertEquals(" http://duckduckgo.com" , omnibarViewState().omnibarText)
410445 }
411446
412447 @Test
413448 fun whenUrlChangedWithNonDuckDuckGoUrlThenFullUrlShown () {
414- testee.urlChanged (" http://example.com" )
449+ changeUrl (" http://example.com" )
415450 assertEquals(" http://example.com" , omnibarViewState().omnibarText)
416451 }
417452
418453 @Test
419454 fun whenViewModelGetsProgressUpdateThenViewStateIsUpdated () {
420- testee.progressChanged(0 )
455+ testee.progressChanged(" " , 0 )
421456 assertEquals(0 , loadingViewState().progress)
422457
423- testee.progressChanged(50 )
458+ testee.progressChanged(" " , 50 )
424459 assertEquals(50 , loadingViewState().progress)
425460
426- testee.progressChanged(100 )
461+ testee.progressChanged(" " , 100 )
427462 assertEquals(100 , loadingViewState().progress)
428463 }
429464
430465 @Test
431466 fun whenLoadingStartedThenPrivacyGradeIsCleared () {
432- testee.loadingStarted()
467+ testee.loadingStarted(" http://example.com " )
433468 assertNull(testee.privacyGrade.value)
434469 }
435470
436471 @Test
437472 fun whenUrlChangedThenPrivacyGradeIsReset () {
438473 val grade = testee.privacyGrade.value
439- testee.urlChanged (" https://example.com" )
474+ changeUrl (" https://example.com" )
440475 assertNotEquals(grade, testee.privacyGrade.value)
441476 }
442477
443478 @Test
444479 fun whenEnoughTrackersDetectedThenPrivacyGradeIsUpdated () {
445480 val grade = testee.privacyGrade.value
446- testee.urlChanged (" https://example.com" )
481+ changeUrl (" https://example.com" )
447482 for (i in 1 .. 10 ) {
448483 testee.trackerDetected(TrackingEvent (" https://example.com" , " " , null , false ))
449484 }
@@ -458,14 +493,14 @@ class BrowserTabViewModelTest {
458493 @Test
459494 fun whenUrlUpdatedAfterConfigDownloadThenPrivacyGradeIsShown () {
460495 testee.appConfigurationObserver.onChanged(AppConfigurationEntity (appConfigurationDownloaded = true ))
461- testee.urlChanged(( " " ) )
496+ changeUrl( " " )
462497 assertTrue(browserViewState().showPrivacyGrade)
463498 }
464499
465500 @Test
466501 fun whenUrlUpdatedBeforeConfigDownloadThenPrivacyGradeIsShown () {
467502 testee.appConfigurationObserver.onChanged(AppConfigurationEntity (appConfigurationDownloaded = false ))
468- testee.urlChanged(( " " ) )
503+ changeUrl( " " )
469504 assertFalse(browserViewState().showPrivacyGrade)
470505 }
471506
@@ -629,7 +664,7 @@ class BrowserTabViewModelTest {
629664 fun whenEnteringNonEmptyQueryThenHideKeyboardCommandIssued () {
630665 testee.onUserSubmittedQuery(" foo" )
631666 verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
632- assertTrue(commandCaptor.value == Command .HideKeyboard )
667+ assertTrue(commandCaptor.allValues.any { it == Command .HideKeyboard } )
633668 }
634669
635670 @Test
@@ -760,7 +795,7 @@ class BrowserTabViewModelTest {
760795
761796 @Test
762797 fun whenOnSiteAndBrokenSiteSelectedThenBrokenSiteFeedbackCommandSentWithUrl () {
763- testee.urlChanged (" foo.com" )
798+ changeUrl (" foo.com" )
764799 testee.onBrokenSiteSelected()
765800 val command = captureCommands().value as Command .BrokenSiteFeedback
766801 assertEquals(" foo.com" , command.url)
@@ -796,14 +831,17 @@ class BrowserTabViewModelTest {
796831 whenever(mockOmnibarConverter.convertQueryToUrl(" foo.com" )).thenReturn(" foo.com" )
797832 whenever(webViewSessionStorage.restoreSession(anyOrNull(), anyString())).thenReturn(false )
798833 testee.restoreWebViewState(null , " foo.com" )
799- assertEquals(" foo.com" , testee.url.value)
834+
835+ verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
836+ val command = commandCaptor.lastValue as Navigate
837+ assertEquals(" foo.com" , command.url)
800838 }
801839
802840 @Test
803841 fun whenRestoringWebViewSessionNotRestorableAndNoPreviousUrlThenNoUrlLoaded () {
804842 whenever(webViewSessionStorage.restoreSession(anyOrNull(), anyString())).thenReturn(false )
805843 testee.restoreWebViewState(null , " " )
806- assertNull(testee.url.value )
844+ assertFalse(commandCaptor.allValues.any { it is Navigate } )
807845 }
808846
809847 @Test
@@ -813,6 +851,11 @@ class BrowserTabViewModelTest {
813851 assertFalse(globalLayoutViewState().isNewTabState)
814852 }
815853
854+ private fun changeUrl (url : String? ) {
855+ testee.loadingStarted(url)
856+ testee.progressChanged(url, 100 )
857+ }
858+
816859 private fun captureCommands (): ArgumentCaptor <Command > {
817860 verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
818861 return commandCaptor
0 commit comments