@@ -105,8 +105,11 @@ import com.duckduckgo.app.browser.duckplayer.DuckPlayerJSHelper
105105import com.duckduckgo.app.browser.favicon.FaviconManager
106106import com.duckduckgo.app.browser.favicon.FaviconSource
107107import com.duckduckgo.app.browser.history.NavigationHistoryEntry
108+ import com.duckduckgo.app.browser.httperrors.HttpCodeSiteErrorHandler
108109import com.duckduckgo.app.browser.httperrors.HttpErrorPixelName
109110import com.duckduckgo.app.browser.httperrors.HttpErrorPixels
111+ import com.duckduckgo.app.browser.httperrors.SiteErrorHandlerKillSwitch
112+ import com.duckduckgo.app.browser.httperrors.StringSiteErrorHandler
110113import com.duckduckgo.app.browser.logindetection.FireproofDialogsEventHandler
111114import com.duckduckgo.app.browser.logindetection.LoginDetected
112115import com.duckduckgo.app.browser.logindetection.NavigationAwareLoginDetector
@@ -540,6 +543,11 @@ class BrowserTabViewModelTest {
540543 private val defaultVisualExperimentStateFlow = MutableStateFlow (FeatureState (isAvailable = true , isEnabled = false ))
541544 private val defaultVisualExperimentNavBarStateFlow = MutableStateFlow (FeatureState (isAvailable = true , isEnabled = false ))
542545
546+ private val mockSiteErrorHandlerKillSwitch: SiteErrorHandlerKillSwitch = mock()
547+ private val mockSiteErrorHandlerKillSwitchToggle: Toggle = mock { on { it.isEnabled() } doReturn true }
548+ private val mockSiteErrorHandler: StringSiteErrorHandler = mock()
549+ private val mockSiteHttpErrorHandler: HttpCodeSiteErrorHandler = mock()
550+
543551 @Before
544552 fun before () = runTest {
545553 MockitoAnnotations .openMocks(this )
@@ -655,6 +663,8 @@ class BrowserTabViewModelTest {
655663 defaultVisualExperimentNavBarStateFlow,
656664 )
657665
666+ whenever(mockSiteErrorHandlerKillSwitch.self()).thenReturn(mockSiteErrorHandlerKillSwitchToggle)
667+
658668 testee = BrowserTabViewModel (
659669 statisticsUpdater = mockStatisticsUpdater,
660670 queryUrlConverter = mockOmnibarConverter,
@@ -723,6 +733,9 @@ class BrowserTabViewModelTest {
723733 defaultBrowserPromptsExperiment = mockDefaultBrowserPromptsExperiment,
724734 swipingTabsFeature = swipingTabsFeatureProvider,
725735 visualDesignExperimentDataStore = mockVisualDesignExperimentDataStore,
736+ siteErrorHandlerKillSwitch = mockSiteErrorHandlerKillSwitch,
737+ siteErrorHandler = mockSiteErrorHandler,
738+ siteHttpErrorHandler = mockSiteHttpErrorHandler,
726739 )
727740
728741 testee.loadData(" abc" , null , false , false )
@@ -4917,7 +4930,8 @@ class BrowserTabViewModelTest {
49174930 }
49184931
49194932 @Test
4920- fun whenPageIsChangedWithHttpErrorThenPrivacyProtectionsPopupManagerIsNotified () = runTest {
4933+ fun whenErrorHandlerKilledAndPageIsChangedWithHttpErrorThenPrivacyProtectionsPopupManagerIsNotified () = runTest {
4934+ whenever(mockSiteErrorHandlerKillSwitchToggle.isEnabled()).thenReturn(false )
49214935 testee.recordHttpErrorCode(statusCode = 404 , url = " example2.com" )
49224936
49234937 updateUrl(
@@ -4933,6 +4947,26 @@ class BrowserTabViewModelTest {
49334947 )
49344948 }
49354949
4950+ @Test
4951+ fun whenPageIsChangedWithHttpErrorThenPrivacyProtectionsPopupManagerIsNotified () = runTest {
4952+ val siteCaptor = argumentCaptor<Site >()
4953+ whenever(mockSiteHttpErrorHandler.assignErrorsAndClearCache(siteCaptor.capture())).then {
4954+ siteCaptor.lastValue.onHttpErrorDetected(404 )
4955+ }
4956+
4957+ updateUrl(
4958+ originalUrl = " example.com" ,
4959+ currentUrl = " example2.com" ,
4960+ isBrowserShowing = true ,
4961+ )
4962+
4963+ verify(mockPrivacyProtectionsPopupManager).onPageLoaded(
4964+ url = " example2.com" ,
4965+ httpErrorCodes = listOf (404 ),
4966+ hasBrowserError = false ,
4967+ )
4968+ }
4969+
49364970 @Test
49374971 fun whenPageIsChangedWithHttpError400ThenUpdateCountPixelCalledForWebViewReceivedHttpError400Daily () = runTest {
49384972 testee.recordHttpErrorCode(statusCode = 400 , url = " example2.com" )
@@ -6085,6 +6119,66 @@ class BrowserTabViewModelTest {
60856119 verify(mockPixel).fire(ONBOARDING_DAX_CTA_DISMISS_BUTTON , mapOf (PixelParameter .CTA_SHOWN to DAX_SERP_CTA ))
60866120 }
60876121
6122+ @Test
6123+ fun whenRecordErrorCodeThenProvideValueToErrorHandler () {
6124+ val site = givenCurrentSite(" some.domain" )
6125+ val siteCaptor = argumentCaptor<Site >()
6126+ val errorUrl = " some.domain"
6127+ val errorValue = " error value"
6128+
6129+ testee.recordErrorCode(url = errorUrl, error = errorValue)
6130+
6131+ verify(mockSiteErrorHandler).handleError(currentSite = siteCaptor.capture(), urlWithError = eq(errorUrl), error = eq(errorValue))
6132+ assertEquals(site.url, siteCaptor.lastValue.url)
6133+ }
6134+
6135+ @Test
6136+ fun whenRecordHttpErrorCodeThenProvideValueToErrorHandler () {
6137+ val site = givenCurrentSite(" some.domain" )
6138+ val siteCaptor = argumentCaptor<Site >()
6139+ val errorUrl = " some.domain"
6140+ val errorValue = - 1
6141+
6142+ testee.recordHttpErrorCode(url = errorUrl, statusCode = errorValue)
6143+
6144+ verify(mockSiteHttpErrorHandler).handleError(currentSite = siteCaptor.capture(), urlWithError = eq(errorUrl), error = eq(errorValue))
6145+ assertEquals(site.url, siteCaptor.lastValue.url)
6146+ }
6147+
6148+ @Test
6149+ fun whenRecordErrorCodeNotMatchingCurrentSiteThenProvideValueToErrorHandler () {
6150+ val site = givenCurrentSite(" some.domain" )
6151+ val siteCaptor = argumentCaptor<Site >()
6152+ val errorUrl = " error.com"
6153+ val errorValue = " error value"
6154+
6155+ testee.recordErrorCode(url = errorUrl, error = errorValue)
6156+
6157+ verify(mockSiteErrorHandler).handleError(currentSite = siteCaptor.capture(), urlWithError = eq(errorUrl), error = eq(errorValue))
6158+ assertEquals(site.url, siteCaptor.lastValue.url)
6159+ }
6160+
6161+ @Test
6162+ fun whenRecordHttpErrorCodeNotMatchingCurrentSiteThenProvideValueToErrorHandler () {
6163+ val site = givenCurrentSite(" some.domain" )
6164+ val siteCaptor = argumentCaptor<Site >()
6165+ val errorUrl = " error.com"
6166+ val errorValue = - 1
6167+
6168+ testee.recordHttpErrorCode(url = errorUrl, statusCode = errorValue)
6169+
6170+ verify(mockSiteHttpErrorHandler).handleError(currentSite = siteCaptor.capture(), urlWithError = eq(errorUrl), error = eq(errorValue))
6171+ assertEquals(site.url, siteCaptor.lastValue.url)
6172+ }
6173+
6174+ @Test
6175+ fun whenSiteLoadedThenAssignCachedErrors () {
6176+ val site = givenCurrentSite(" some.domain" )
6177+
6178+ verify(mockSiteErrorHandler).assignErrorsAndClearCache(site)
6179+ verify(mockSiteHttpErrorHandler).assignErrorsAndClearCache(site)
6180+ }
6181+
60886182 private fun aCredential (): LoginCredentials {
60896183 return LoginCredentials (domain = null , username = null , password = null )
60906184 }
0 commit comments