Skip to content

Commit a2c2ffb

Browse files
committed
Merge branch 'release/5.58.0' into main
2 parents 3bf56e4 + 32e3a98 commit a2c2ffb

File tree

73 files changed

+1712
-244
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+1712
-244
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ We use git submodules and so when you are checking out the app, you'll need to e
1313
Alternatively, if you already have the project checked out, you can initialize the submodules manually.
1414

1515
git submodule update --init
16+
17+
## Terminology
18+
19+
We have taken steps to update our terminology and remove words with problematic racial connotations, most notably the change to `main` branches, `allow lists`, and `blocklists`. Closed issues or PRs may contain deprecated terminology that should not be used going forward.
1620

1721
## Contribute
1822

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt

Lines changed: 96 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ import com.duckduckgo.app.browser.LongPressHandler.RequiredAction.DownloadFile
4141
import com.duckduckgo.app.browser.LongPressHandler.RequiredAction.OpenInNewTab
4242
import com.duckduckgo.app.browser.addtohome.AddToHomeCapabilityDetector
4343
import com.duckduckgo.app.browser.favicon.FaviconDownloader
44+
import com.duckduckgo.app.browser.logindetection.LoginDetected
45+
import com.duckduckgo.app.browser.logindetection.NavigationAwareLoginDetector
46+
import com.duckduckgo.app.browser.logindetection.NavigationEvent.LoginAttempt
4447
import com.duckduckgo.app.browser.model.BasicAuthenticationCredentials
4548
import com.duckduckgo.app.browser.model.BasicAuthenticationRequest
4649
import com.duckduckgo.app.browser.model.LongPressTarget
@@ -49,13 +52,10 @@ import com.duckduckgo.app.browser.session.WebViewSessionStorage
4952
import com.duckduckgo.app.cta.db.DismissedCtaDao
5053
import com.duckduckgo.app.cta.model.CtaId
5154
import com.duckduckgo.app.cta.model.DismissedCta
55+
import com.duckduckgo.app.cta.ui.*
5256
import com.duckduckgo.app.fire.fireproofwebsite.data.FireproofWebsiteDao
5357
import com.duckduckgo.app.fire.fireproofwebsite.data.FireproofWebsiteEntity
54-
import com.duckduckgo.app.cta.ui.Cta
55-
import com.duckduckgo.app.cta.ui.CtaViewModel
56-
import com.duckduckgo.app.cta.ui.DaxBubbleCta
57-
import com.duckduckgo.app.cta.ui.DaxDialogCta
58-
import com.duckduckgo.app.cta.ui.HomePanelCta
58+
import com.duckduckgo.app.fire.fireproofwebsite.data.FireproofWebsiteRepository
5959
import com.duckduckgo.app.global.db.AppDatabase
6060
import com.duckduckgo.app.global.install.AppInstallStore
6161
import com.duckduckgo.app.global.model.SiteFactory
@@ -83,14 +83,7 @@ import com.duckduckgo.app.trackerdetection.EntityLookup
8383
import com.duckduckgo.app.trackerdetection.model.TrackingEvent
8484
import com.duckduckgo.app.usage.search.SearchCountDao
8585
import com.duckduckgo.app.widget.ui.WidgetCapabilities
86-
import com.nhaarman.mockitokotlin2.any
87-
import com.nhaarman.mockitokotlin2.anyOrNull
88-
import com.nhaarman.mockitokotlin2.atLeastOnce
89-
import com.nhaarman.mockitokotlin2.doReturn
90-
import com.nhaarman.mockitokotlin2.firstValue
91-
import com.nhaarman.mockitokotlin2.lastValue
92-
import com.nhaarman.mockitokotlin2.mock
93-
import com.nhaarman.mockitokotlin2.whenever
86+
import com.nhaarman.mockitokotlin2.*
9487
import io.reactivex.Observable
9588
import io.reactivex.Single
9689
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -101,14 +94,10 @@ import org.junit.Assert.*
10194
import org.junit.Before
10295
import org.junit.Rule
10396
import org.junit.Test
104-
import org.mockito.ArgumentCaptor
97+
import org.mockito.*
10598
import org.mockito.ArgumentMatchers.anyString
106-
import org.mockito.Captor
107-
import org.mockito.Mock
108-
import org.mockito.Mockito
10999
import org.mockito.Mockito.never
110100
import org.mockito.Mockito.verify
111-
import org.mockito.MockitoAnnotations
112101
import java.util.concurrent.TimeUnit
113102

114103
@ExperimentalCoroutinesApi
@@ -196,6 +185,9 @@ class BrowserTabViewModelTest {
196185
@Mock
197186
private lateinit var mockUserWhitelistDao: UserWhitelistDao
198187

188+
@Mock
189+
private lateinit var mockNavigationAwareLoginDetector: NavigationAwareLoginDetector
190+
199191
private lateinit var mockAutoCompleteApi: AutoCompleteApi
200192

201193
private lateinit var ctaViewModel: CtaViewModel
@@ -211,6 +203,8 @@ class BrowserTabViewModelTest {
211203

212204
private val selectedTabLiveData = MutableLiveData<TabEntity>()
213205

206+
private val loginEventLiveData = MutableLiveData<LoginDetected>()
207+
214208
@Before
215209
fun before() {
216210
MockitoAnnotations.initMocks(this)
@@ -241,6 +235,7 @@ class BrowserTabViewModelTest {
241235
whenever(mockOmnibarConverter.convertQueryToUrl(any(), any())).thenReturn("duckduckgo.com")
242236
whenever(mockVariantManager.getVariant()).thenReturn(DEFAULT_VARIANT)
243237
whenever(mockTabsRepository.liveSelectedTab).thenReturn(selectedTabLiveData)
238+
whenever(mockNavigationAwareLoginDetector.loginEventLiveData).thenReturn(loginEventLiveData)
244239
whenever(mockTabsRepository.retrieveSiteData(any())).thenReturn(MutableLiveData())
245240
whenever(mockPrivacyPractices.privacyPracticesFor(any())).thenReturn(PrivacyPractices.UNKNOWN)
246241
whenever(mockAppInstallStore.installTimestamp).thenReturn(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1))
@@ -266,7 +261,8 @@ class BrowserTabViewModelTest {
266261
searchCountDao = mockSearchCountDao,
267262
pixel = mockPixel,
268263
dispatchers = coroutineRule.testDispatcherProvider,
269-
fireproofWebsiteDao = fireproofWebsiteDao,
264+
fireproofWebsiteRepository = FireproofWebsiteRepository(fireproofWebsiteDao, coroutineRule.testDispatcherProvider),
265+
navigationAwareLoginDetector = mockNavigationAwareLoginDetector,
270266
variantManager = mockVariantManager
271267
)
272268

@@ -1768,23 +1764,25 @@ class BrowserTabViewModelTest {
17681764
}
17691765

17701766
@Test
1771-
fun whenUserLoadsNotFireproofWebsiteThenFireproofWebsiteOptionMenuEnabled() {
1767+
fun whenUserLoadsNotFireproofWebsiteThenFireproofWebsiteBrowserStateUpdated() {
17721768
loadUrl("http://www.example.com/path", isBrowserShowing = true)
17731769
assertTrue(browserViewState().canFireproofSite)
1770+
assertFalse(browserViewState().isFireproofWebsite)
17741771
}
17751772

17761773
@Test
1777-
fun whenUserLoadsFireproofWebsiteThenFireproofWebsiteOptionMenuDisabled() {
1774+
fun whenUserLoadsFireproofWebsiteThenFireproofWebsiteBrowserStateUpdated() {
17781775
givenFireproofWebsiteDomain("www.example.com")
17791776
loadUrl("http://www.example.com/path", isBrowserShowing = true)
1780-
assertFalse(browserViewState().canFireproofSite)
1777+
assertTrue(browserViewState().isFireproofWebsite)
17811778
}
17821779

17831780
@Test
1784-
fun whenUserLoadsFireproofWebsiteSubDomainThenFireproofWebsiteOptionMenuEnabled() {
1781+
fun whenUserLoadsFireproofWebsiteSubDomainThenFireproofWebsiteBrowserStateUpdated() {
17851782
givenFireproofWebsiteDomain("example.com")
17861783
loadUrl("http://mobile.example.com/path", isBrowserShowing = true)
17871784
assertTrue(browserViewState().canFireproofSite)
1785+
assertFalse(browserViewState().isFireproofWebsite)
17881786
}
17891787

17901788
@Test
@@ -1796,64 +1794,127 @@ class BrowserTabViewModelTest {
17961794
}
17971795

17981796
@Test
1799-
fun whenUrlIsUpdatedWithNonFireproofWebsiteThenFireproofWebsiteOptionMenuEnabled() {
1797+
fun whenUrlIsUpdatedWithNonFireproofWebsiteThenFireproofWebsiteBrowserStateUpdated() {
18001798
givenFireproofWebsiteDomain("www.example.com")
18011799
loadUrl("http://www.example.com/", isBrowserShowing = true)
18021800
updateUrl("http://www.example.com/", "http://twitter.com/explore", true)
18031801
assertTrue(browserViewState().canFireproofSite)
1802+
assertFalse(browserViewState().isFireproofWebsite)
18041803
}
18051804

18061805
@Test
1807-
fun whenUrlIsUpdatedWithFireproofWebsiteThenFireproofWebsiteOptionMenuDisabled() {
1806+
fun whenUrlIsUpdatedWithFireproofWebsiteThenFireproofWebsiteBrowserStateUpdated() {
18081807
givenFireproofWebsiteDomain("twitter.com")
18091808
loadUrl("http://example.com/", isBrowserShowing = true)
18101809
updateUrl("http://example.com/", "http://twitter.com/explore", true)
1811-
assertFalse(browserViewState().canFireproofSite)
1810+
assertTrue(browserViewState().isFireproofWebsite)
18121811
}
18131812

18141813
@Test
18151814
fun whenUserClicksFireproofWebsiteOptionMenuThenShowConfirmationIsIssued() {
18161815
loadUrl("http://mobile.example.com/", isBrowserShowing = true)
1817-
testee.onFireproofWebsiteClicked()
1816+
testee.onFireproofWebsiteMenuClicked()
18181817
assertCommandIssued<Command.ShowFireproofWebSiteConfirmation> {
18191818
assertEquals("mobile.example.com", this.fireproofWebsiteEntity.domain)
18201819
}
18211820
}
18221821

18231822
@Test
1824-
fun whenUserClicksFireproofWebsiteOptionMenuThenFireproofWebsiteOptionMenuDisabled() {
1823+
fun whenUserClicksFireproofWebsiteOptionMenuThenFireproofWebsiteBrowserStateUpdated() {
18251824
loadUrl("http://example.com/", isBrowserShowing = true)
1826-
testee.onFireproofWebsiteClicked()
1827-
assertFalse(browserViewState().canFireproofSite)
1825+
testee.onFireproofWebsiteMenuClicked()
1826+
assertTrue(browserViewState().isFireproofWebsite)
18281827
}
18291828

18301829
@Test
18311830
fun whenFireproofWebsiteAddedThenPixelSent() {
18321831
loadUrl("http://example.com/", isBrowserShowing = true)
1833-
testee.onFireproofWebsiteClicked()
1832+
testee.onFireproofWebsiteMenuClicked()
18341833
verify(mockPixel).fire(Pixel.PixelName.FIREPROOF_WEBSITE_ADDED)
18351834
}
18361835

1836+
@Test
1837+
fun whenUserRemovesFireproofWebsiteFromOptionMenuThenFireproofWebsiteBrowserStateUpdated() {
1838+
givenFireproofWebsiteDomain("mobile.example.com")
1839+
loadUrl("http://mobile.example.com/", isBrowserShowing = true)
1840+
testee.onFireproofWebsiteMenuClicked()
1841+
assertFalse(browserViewState().isFireproofWebsite)
1842+
}
1843+
1844+
@Test
1845+
fun whenUserRemovesFireproofWebsiteFromOptionMenuThenPixelSent() {
1846+
givenFireproofWebsiteDomain("mobile.example.com")
1847+
loadUrl("http://mobile.example.com/", isBrowserShowing = true)
1848+
testee.onFireproofWebsiteMenuClicked()
1849+
verify(mockPixel).fire(Pixel.PixelName.FIREPROOF_WEBSITE_REMOVE)
1850+
}
1851+
18371852
@Test
18381853
fun whenUserClicksOnFireproofWebsiteSnackbarUndoActionThenFireproofWebsiteIsRemoved() {
18391854
loadUrl("http://example.com/", isBrowserShowing = true)
1840-
testee.onFireproofWebsiteClicked()
1855+
testee.onFireproofWebsiteMenuClicked()
18411856
assertCommandIssued<Command.ShowFireproofWebSiteConfirmation> {
18421857
testee.onFireproofWebsiteSnackbarUndoClicked(this.fireproofWebsiteEntity)
18431858
}
18441859
assertTrue(browserViewState().canFireproofSite)
1860+
assertFalse(browserViewState().isFireproofWebsite)
18451861
}
18461862

18471863
@Test
18481864
fun whenUserClicksOnFireproofWebsiteSnackbarUndoActionThenPixelSent() {
18491865
loadUrl("http://example.com/", isBrowserShowing = true)
1850-
testee.onFireproofWebsiteClicked()
1866+
testee.onFireproofWebsiteMenuClicked()
18511867
assertCommandIssued<Command.ShowFireproofWebSiteConfirmation> {
18521868
testee.onFireproofWebsiteSnackbarUndoClicked(this.fireproofWebsiteEntity)
18531869
}
18541870
verify(mockPixel).fire(Pixel.PixelName.FIREPROOF_WEBSITE_UNDO)
18551871
}
18561872

1873+
@Test
1874+
fun whenUserFireproofsWebsiteFromLoginDialogThenShowConfirmationIsIssuedWithExpectedDomain() {
1875+
loadUrl("http://mobile.example.com/", isBrowserShowing = true)
1876+
testee.onUserConfirmedFireproofDialog("login.example.com")
1877+
assertCommandIssued<Command.ShowFireproofWebSiteConfirmation> {
1878+
assertEquals("login.example.com", this.fireproofWebsiteEntity.domain)
1879+
}
1880+
}
1881+
1882+
@Test
1883+
fun whenUserFireproofsWebsiteFromLoginDialogThenPixelSent() {
1884+
testee.onUserConfirmedFireproofDialog("login.example.com")
1885+
verify(mockPixel).fire(Pixel.PixelName.FIREPROOF_WEBSITE_LOGIN_ADDED)
1886+
}
1887+
1888+
@Test
1889+
fun whenUserDismissesFireproofWebsiteLoginDialogThenPixelSent() {
1890+
testee.onUserDismissedFireproofLoginDialog()
1891+
verify(mockPixel).fire(Pixel.PixelName.FIREPROOF_WEBSITE_LOGIN_DISMISS)
1892+
}
1893+
1894+
@Test
1895+
fun whenLoginAttempDetectedThenNotifyNavigationAwareLoginDetector() {
1896+
loadUrl("http://example.com/", isBrowserShowing = true)
1897+
1898+
testee.loginDetected()
1899+
1900+
verify(mockNavigationAwareLoginDetector).onEvent(LoginAttempt("http://example.com/"))
1901+
}
1902+
1903+
@Test
1904+
fun whenLoginDetectedOnAFireproofedWebsiteThenDoNotAskToFireproofWebsite() {
1905+
givenFireproofWebsiteDomain("example.com")
1906+
loginEventLiveData.value = givenLoginDetected("example.com")
1907+
assertCommandNotIssued<Command.AskToFireproofWebsite>()
1908+
}
1909+
1910+
@Test
1911+
fun whenLoginDetectedThenAskToFireproofWebsite() {
1912+
loginEventLiveData.value = givenLoginDetected("example.com")
1913+
assertCommandIssued<Command.AskToFireproofWebsite> {
1914+
assertEquals(FireproofWebsiteEntity("example.com"), this.fireproofWebsite)
1915+
}
1916+
}
1917+
18571918
@Test
18581919
fun whenUserBrowsingPressesBackThenCannotAddBookmark() {
18591920
setupNavigation(skipHome = false, isBrowsing = true, canGoBack = false)
@@ -2041,6 +2102,8 @@ class BrowserTabViewModelTest {
20412102
}
20422103
}
20432104

2105+
private fun givenLoginDetected(domain: String) = LoginDetected(authLoginDomain = "", forwardedToDomain = domain)
2106+
20442107
private fun setBrowserShowing(isBrowsing: Boolean) {
20452108
testee.browserViewState.value = browserViewState().copy(browserShowing = isBrowsing)
20462109
}

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserWebViewClientTest.kt

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,29 @@ package com.duckduckgo.app.browser
1818

1919
import android.content.Context
2020
import android.os.Build
21-
import android.webkit.CookieManager
22-
import android.webkit.HttpAuthHandler
23-
import android.webkit.RenderProcessGoneDetail
24-
import android.webkit.WebView
21+
import android.webkit.*
2522
import androidx.test.annotation.UiThreadTest
2623
import androidx.test.filters.SdkSuppress
2724
import androidx.test.platform.app.InstrumentationRegistry
25+
import com.duckduckgo.app.CoroutineTestRule
26+
import com.duckduckgo.app.browser.logindetection.DOMLoginDetector
27+
import com.duckduckgo.app.browser.logindetection.WebNavigationEvent
2828
import com.duckduckgo.app.browser.model.BasicAuthenticationRequest
2929
import com.duckduckgo.app.global.exception.UncaughtExceptionRepository
30+
import com.duckduckgo.app.runBlocking
3031
import com.duckduckgo.app.statistics.store.OfflinePixelCountDataStore
3132
import com.nhaarman.mockitokotlin2.*
33+
import kotlinx.coroutines.ExperimentalCoroutinesApi
3234
import org.junit.Before
35+
import org.junit.Rule
3336
import org.junit.Test
3437

38+
@ExperimentalCoroutinesApi
3539
class BrowserWebViewClientTest {
3640

41+
@get:Rule
42+
var coroutinesTestRule = CoroutineTestRule()
43+
3744
private lateinit var testee: BrowserWebViewClient
3845
private lateinit var webView: WebView
3946

@@ -42,6 +49,7 @@ class BrowserWebViewClientTest {
4249
private val requestInterceptor: RequestInterceptor = mock()
4350
private val listener: WebViewClientListener = mock()
4451
private val cookieManager: CookieManager = mock()
52+
private val loginDetector: DOMLoginDetector = mock()
4553
private val offlinePixelCountDataStore: OfflinePixelCountDataStore = mock()
4654
private val uncaughtExceptionRepository: UncaughtExceptionRepository = mock()
4755

@@ -55,7 +63,8 @@ class BrowserWebViewClientTest {
5563
requestInterceptor,
5664
offlinePixelCountDataStore,
5765
uncaughtExceptionRepository,
58-
cookieManager
66+
cookieManager,
67+
loginDetector
5968
)
6069
testee.webViewClientListener = listener
6170
}
@@ -83,6 +92,13 @@ class BrowserWebViewClientTest {
8392
verify(listener, never()).pageRefreshed(any())
8493
}
8594

95+
@UiThreadTest
96+
@Test
97+
fun whenOnPageStartedCalledThenEventSentToLoginDetector() = coroutinesTestRule.runBlocking {
98+
testee.onPageStarted(webView, EXAMPLE_URL, null)
99+
verify(loginDetector).onEvent(WebNavigationEvent.OnPageStarted(webView))
100+
}
101+
86102
@UiThreadTest
87103
@Test
88104
fun whenOnPageFinishedCalledThenListenerInstructedToUpdateNavigationState() {
@@ -99,6 +115,14 @@ class BrowserWebViewClientTest {
99115
verify(listener).requiresAuthentication(authenticationRequest)
100116
}
101117

118+
@UiThreadTest
119+
@Test
120+
fun whenShouldInterceptRequestThenEventSentToLoginDetector() = coroutinesTestRule.runBlocking {
121+
val webResourceRequest = mock<WebResourceRequest>()
122+
testee.shouldInterceptRequest(webView, webResourceRequest)
123+
verify(loginDetector).onEvent(WebNavigationEvent.ShouldInterceptRequest(webView, webResourceRequest))
124+
}
125+
102126
@Test
103127
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
104128
fun whenRenderProcessGoneDueToCrashThenCrashDataStoreEntryIsIncremented() {

0 commit comments

Comments
 (0)