Skip to content

Commit 321eb8d

Browse files
committed
Merge branch 'release/5.57.0' into main
2 parents b1c863a + d00cd59 commit 321eb8d

32 files changed

+635
-95
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve
4+
title: ''
5+
labels: bug, needs triage
6+
assignees: ''
7+
8+
---
9+
10+
**Describe the bug**
11+
A clear and concise description of what the bug is.
12+
13+
**How to Reproduce**
14+
Steps to reproduce the behavior:
15+
1. Go to '...'
16+
2. Click on '....'
17+
3. Scroll down to '....'
18+
4. See error
19+
20+
If applicable, please include information about any settings that may be relevant to this issue (e.g. selected theme, auto clear option, etc).
21+
22+
**Expected behavior**
23+
A clear and concise description of what you expected to happen.
24+
25+
**Smartphone (please complete the following information):**
26+
- DDG App Version: (e.g. 5.25.0) Version can be found:
27+
- DDG App settings: Settings -> Version
28+
- System settings: Settings -> Apps & notifications -> App Info
29+
- Device: [e.g. Pixel 2, Samsung s10]
30+
- OS: [e.g. Android 10]
31+
- If applicable, add screenshots to help explain your problem.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea for this project
4+
title: ''
5+
labels: feature request, needs triage
6+
assignees: ''
7+
8+
---
9+
10+
**Is your feature request related to a problem? Please describe.**
11+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12+
13+
**Describe the solution or the user experience you'd like**
14+
A clear and concise description of what you want to happen.
15+
16+
**Additional context**
17+
Add any other context or screenshots about the feature request here.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Welcome to our android application. We are excited to engage the community in development, see [CONTRIBUTING.md](CONTRIBUTING.md).
44

55
## We are hiring!
6-
Are you a talented cross-platform mobile developer? We are looking for a Senior Cross-Platform Engineer to help shape our mobile apps. We embrace diverse perspectives, and seek out passionate, self-motivated people, committed to our shared vision of raising the standard of trust online. Visit our [careers](https://duckduckgo.com/hiring/#open) page to find out more!
6+
DuckDuckGo is growing fast and we continue to expand our fully distributed team. We embrace diverse perspectives, and seek out passionate, self-motivated people, committed to our shared vision of raising the standard of trust online. If you are a senior software engineer capable in either iOS or Android, visit our [careers](https://duckduckgo.com/hiring/#open) page to find out more about our openings!
77

88
## Building the Project
99
We use git submodules and so when you are checking out the app, you'll need to ensure the submodules are initialized properly. You can use the `--recursive` flag when cloning the project to do this.

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

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,13 @@ import com.duckduckgo.app.browser.session.WebViewSessionStorage
4949
import com.duckduckgo.app.cta.db.DismissedCtaDao
5050
import com.duckduckgo.app.cta.model.CtaId
5151
import com.duckduckgo.app.cta.model.DismissedCta
52-
import com.duckduckgo.app.cta.ui.*
5352
import com.duckduckgo.app.fire.fireproofwebsite.data.FireproofWebsiteDao
5453
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
5559
import com.duckduckgo.app.global.db.AppDatabase
5660
import com.duckduckgo.app.global.install.AppInstallStore
5761
import com.duckduckgo.app.global.model.SiteFactory
@@ -65,6 +69,7 @@ import com.duckduckgo.app.privacy.model.TestEntity
6569
import com.duckduckgo.app.privacy.model.UserWhitelistedDomain
6670
import com.duckduckgo.app.runBlocking
6771
import com.duckduckgo.app.settings.db.SettingsDataStore
72+
import com.duckduckgo.app.statistics.Variant
6873
import com.duckduckgo.app.statistics.VariantManager
6974
import com.duckduckgo.app.statistics.VariantManager.Companion.DEFAULT_VARIANT
7075
import com.duckduckgo.app.statistics.api.StatisticsUpdater
@@ -78,7 +83,14 @@ import com.duckduckgo.app.trackerdetection.EntityLookup
7883
import com.duckduckgo.app.trackerdetection.model.TrackingEvent
7984
import com.duckduckgo.app.usage.search.SearchCountDao
8085
import com.duckduckgo.app.widget.ui.WidgetCapabilities
81-
import com.nhaarman.mockitokotlin2.*
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
8294
import io.reactivex.Observable
8395
import io.reactivex.Single
8496
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -89,10 +101,14 @@ import org.junit.Assert.*
89101
import org.junit.Before
90102
import org.junit.Rule
91103
import org.junit.Test
92-
import org.mockito.*
104+
import org.mockito.ArgumentCaptor
93105
import org.mockito.ArgumentMatchers.anyString
106+
import org.mockito.Captor
107+
import org.mockito.Mock
108+
import org.mockito.Mockito
94109
import org.mockito.Mockito.never
95110
import org.mockito.Mockito.verify
111+
import org.mockito.MockitoAnnotations
96112
import java.util.concurrent.TimeUnit
97113

98114
@ExperimentalCoroutinesApi
@@ -222,7 +238,7 @@ class BrowserTabViewModelTest {
222238

223239
val siteFactory = SiteFactory(mockPrivacyPractices, mockEntityLookup)
224240

225-
whenever(mockOmnibarConverter.convertQueryToUrl(any())).thenReturn("duckduckgo.com")
241+
whenever(mockOmnibarConverter.convertQueryToUrl(any(), any())).thenReturn("duckduckgo.com")
226242
whenever(mockVariantManager.getVariant()).thenReturn(DEFAULT_VARIANT)
227243
whenever(mockTabsRepository.liveSelectedTab).thenReturn(selectedTabLiveData)
228244
whenever(mockTabsRepository.retrieveSiteData(any())).thenReturn(MutableLiveData())
@@ -250,7 +266,8 @@ class BrowserTabViewModelTest {
250266
searchCountDao = mockSearchCountDao,
251267
pixel = mockPixel,
252268
dispatchers = coroutineRule.testDispatcherProvider,
253-
fireproofWebsiteDao = fireproofWebsiteDao
269+
fireproofWebsiteDao = fireproofWebsiteDao,
270+
variantManager = mockVariantManager
254271
)
255272

256273
testee.loadData("abc", null, false)
@@ -353,6 +370,7 @@ class BrowserTabViewModelTest {
353370

354371
@Test
355372
fun whenSubmittedQueryHasWhitespaceItIsTrimmed() {
373+
whenever(mockOmnibarConverter.convertQueryToUrl("nytimes.com", null)).thenReturn("nytimes.com")
356374
testee.onUserSubmittedQuery(" nytimes.com ")
357375
assertEquals("nytimes.com", omnibarViewState().omnibarText)
358376
}
@@ -413,6 +431,7 @@ class BrowserTabViewModelTest {
413431

414432
@Test
415433
fun whenNonEmptyInputThenNavigateCommandSubmittedToActivity() {
434+
whenever(mockOmnibarConverter.convertQueryToUrl("foo", null)).thenReturn("foo.com")
416435
testee.onUserSubmittedQuery("foo")
417436
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
418437
assertTrue(commandCaptor.lastValue is Navigate)
@@ -701,6 +720,7 @@ class BrowserTabViewModelTest {
701720

702721
@Test
703722
fun whenBrowserShownAndOmnibarInputDoesNotHaveFocusThenPrivacyGradeIsShownAndSearchIconIsHidden() {
723+
whenever(mockOmnibarConverter.convertQueryToUrl("foo", null)).thenReturn("foo.com")
704724
testee.onUserSubmittedQuery("foo")
705725
testee.onOmnibarInputStateChanged(query = "", hasFocus = false, hasQueryChanged = false)
706726
assertTrue(browserViewState().showPrivacyGrade)
@@ -715,6 +735,7 @@ class BrowserTabViewModelTest {
715735

716736
@Test
717737
fun whenBrowserShownAndOmnibarInputHasFocusThenSearchIconIsShownAndPrivacyGradeIsHidden() {
738+
whenever(mockOmnibarConverter.convertQueryToUrl("foo", null)).thenReturn("foo.com")
718739
testee.onUserSubmittedQuery("foo")
719740
testee.onOmnibarInputStateChanged("", true, hasQueryChanged = false)
720741
assertFalse(browserViewState().showPrivacyGrade)
@@ -853,6 +874,7 @@ class BrowserTabViewModelTest {
853874

854875
@Test
855876
fun whenEnteringNonEmptyQueryThenHideKeyboardCommandIssued() {
877+
whenever(mockOmnibarConverter.convertQueryToUrl("foo", null)).thenReturn("foo.com")
856878
testee.onUserSubmittedQuery("foo")
857879
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
858880
assertTrue(commandCaptor.allValues.any { it == Command.HideKeyboard })
@@ -1452,6 +1474,7 @@ class BrowserTabViewModelTest {
14521474

14531475
@Test
14541476
fun whenUserSubmitsQueryThenCaretDoesNotMoveToTheEnd() {
1477+
whenever(mockOmnibarConverter.convertQueryToUrl("foo", null)).thenReturn("foo.com")
14551478
testee.onUserSubmittedQuery("foo")
14561479
assertFalse(omnibarViewState().shouldMoveCaretToEnd)
14571480
}
@@ -1935,6 +1958,38 @@ class BrowserTabViewModelTest {
19351958
assertTrue(findInPageViewState().canFindInPage)
19361959
}
19371960

1961+
@Test
1962+
fun whenSERPRemovalFeatureIsActiveAndBrowsingDDGSiteAndPrivacyGradeIsVisibleThenShowDaxIconIsTrue() {
1963+
val serpRemovalVariant = Variant("foo", 100.0, features = listOf(VariantManager.VariantFeature.SerpHeaderRemoval), filterBy = { true })
1964+
whenever(mockVariantManager.getVariant()).thenReturn(serpRemovalVariant)
1965+
val url = "https://duckduckgo.com?q=test%20search"
1966+
loadUrl(url, isBrowserShowing = true)
1967+
assertTrue(browserViewState().showDaxIcon)
1968+
}
1969+
1970+
@Test
1971+
fun whenSERPRemovalFeatureIsActiveAndBrowsingNonDDGSiteAndPrivacyGradeIsVisibleThenShowDaxIconIsFalse() {
1972+
val serpRemovalVariant = Variant("foo", 100.0, features = listOf(VariantManager.VariantFeature.SerpHeaderRemoval), filterBy = { true })
1973+
whenever(mockVariantManager.getVariant()).thenReturn(serpRemovalVariant)
1974+
val url = "https://example.com"
1975+
loadUrl(url, isBrowserShowing = true)
1976+
assertFalse(browserViewState().showDaxIcon)
1977+
}
1978+
1979+
@Test
1980+
fun whenSERPRemovalFeatureIsInactiveAndBrowsingDDGSiteAndPrivacyGradeIsVisibleThenShowDaxIconIsFalse() {
1981+
val url = "https://duckduckgo.com?q=test%20search"
1982+
loadUrl(url, isBrowserShowing = true)
1983+
assertFalse(browserViewState().showDaxIcon)
1984+
}
1985+
1986+
@Test
1987+
fun whenSERPRemovalFeatureIsInactiveAndBrowsingNonDDGSiteAndPrivacyGradeIsVisibleThenShowDaxIconIsFalse() {
1988+
val url = "https://example.com"
1989+
loadUrl(url, isBrowserShowing = true)
1990+
assertFalse(browserViewState().showDaxIcon)
1991+
}
1992+
19381993
private inline fun <reified T : Command> assertCommandIssued(instanceAssertions: T.() -> Unit = {}) {
19391994
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
19401995
val issuedCommand = commandCaptor.allValues.find { it is T }

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,12 @@ class BrowserViewModelTest {
8686
appEnjoymentPromptEmitter = mockAppEnjoymentPromptEmitter,
8787
appEnjoymentUserEventRecorder = mockAppEnjoymentUserEventRecorder
8888
)
89+
8990
testee.command.observeForever(mockCommandObserver)
9091

9192
runBlocking<Unit> {
9293
whenever(mockTabRepository.add()).thenReturn(TAB_ID)
93-
whenever(mockOmnibarEntryConverter.convertQueryToUrl(any())).then { it.arguments.first() }
94+
whenever(mockOmnibarEntryConverter.convertQueryToUrl(any(), any())).then { it.arguments.first() }
9495
}
9596
}
9697

@@ -108,6 +109,7 @@ class BrowserViewModelTest {
108109
@Test
109110
fun whenOpenInNewTabRequestedThenTabAddedToRepository() = runBlocking<Unit> {
110111
val url = "http://example.com"
112+
whenever(mockOmnibarEntryConverter.convertQueryToUrl(url)).thenReturn(url)
111113
testee.onOpenInNewTabRequested(url)
112114
verify(mockTabRepository).add(url)
113115
}

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.duckduckgo.app.browser
1919
import android.net.Uri
2020
import com.duckduckgo.app.global.AppUrl.ParamKey
2121
import com.duckduckgo.app.referral.AppReferrerDataStore
22+
import com.duckduckgo.app.statistics.Variant
2223
import com.duckduckgo.app.statistics.VariantManager
2324
import com.duckduckgo.app.statistics.model.Atb
2425
import com.duckduckgo.app.statistics.store.StatisticsDataStore
@@ -35,6 +36,7 @@ class DuckDuckGoRequestRewriterTest {
3536
private val mockVariantManager: VariantManager = mock()
3637
private val mockAppReferrerDataStore: AppReferrerDataStore = mock()
3738
private lateinit var builder: Uri.Builder
39+
private val currentUrl = "http://www.duckduckgo.com"
3840

3941
@Before
4042
fun before() {
@@ -79,4 +81,23 @@ class DuckDuckGoRequestRewriterTest {
7981
assertFalse(uri.queryParameterNames.contains(ParamKey.ATB))
8082
}
8183

84+
@Test
85+
fun whenSerpRemovalFeatureIsActiveThenHideParamIsAddedToSerpUrl() {
86+
val serpRemovalVariant = Variant("foo", 100.0, features = listOf(VariantManager.VariantFeature.SerpHeaderRemoval), filterBy = { true })
87+
whenever(mockVariantManager.getVariant()).thenReturn(serpRemovalVariant)
88+
89+
testee.addCustomQueryParams(builder)
90+
91+
val uri = builder.build()
92+
assertTrue(uri.queryParameterNames.contains(ParamKey.HIDE_SERP))
93+
}
94+
95+
@Test
96+
fun whenSerpRemovalFeatureIsInactiveThenHideParamIsNotAddedToSerpUrl() {
97+
testee.addCustomQueryParams(builder)
98+
99+
val uri = builder.build()
100+
assertFalse(uri.queryParameterNames.contains(ParamKey.HIDE_SERP))
101+
}
102+
82103
}

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,32 @@ class DuckDuckGoUrlDetectorTest {
7070
fun whenNonDDGUrlContainsQueryThenQueryIsNotDetected() {
7171
assertFalse(testee.isDuckDuckGoQueryUrl("https://example.com?q=test%20search"))
7272
}
73+
74+
@Test
75+
fun whenDDGUrlContainsVerticalThenVerticalCanBeExtracted() {
76+
val vertical = testee.extractVertical("https://duckduckgo.com/?q=new+zealand+images&t=ffab&atb=v218-6&iar=images&iax=images&ia=images")
77+
assertEquals("images", vertical)
78+
}
79+
80+
@Test
81+
fun whenDDGUrlDoesNotContainVerticalThenVerticalIsNull() {
82+
val vertical = testee.extractVertical("https://duckduckgo.com")
83+
assertNull(vertical)
84+
}
85+
86+
@Test
87+
fun whenDDGUrlContainsVerticalThenVerticalUrlDetected() {
88+
assertTrue(testee.isDuckDuckGoVerticalUrl("https://duckduckgo.com?ia=images"))
89+
}
90+
91+
@Test
92+
fun whenDDGUrlDoesNotContainsVerticalThenVerticalUrlIsNotDetected() {
93+
assertFalse(testee.isDuckDuckGoVerticalUrl("https://duckduckgo.com"))
94+
}
95+
96+
@Test
97+
fun whenCheckingNonDDGUrThenVerticalUrlIsNotDetected() {
98+
assertFalse(testee.isDuckDuckGoVerticalUrl("https://example.com?ia=images"))
99+
}
100+
73101
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ import com.duckduckgo.app.browser.omnibar.QueryUrlConverter
2121
import com.duckduckgo.app.referral.AppReferrerDataStore
2222
import com.duckduckgo.app.statistics.VariantManager
2323
import com.duckduckgo.app.statistics.store.StatisticsDataStore
24+
import com.nhaarman.mockitokotlin2.any
2425
import com.nhaarman.mockitokotlin2.mock
26+
import com.nhaarman.mockitokotlin2.whenever
2527
import org.junit.Assert.*
28+
import org.junit.Before
2629
import org.junit.Test
2730

2831
class QueryUrlConverterTest {
@@ -33,6 +36,11 @@ class QueryUrlConverterTest {
3336
private val requestRewriter = DuckDuckGoRequestRewriter(DuckDuckGoUrlDetector(), mockStatisticsStore, variantManager, mockAppReferrerDataStore)
3437
private val testee: QueryUrlConverter = QueryUrlConverter(requestRewriter)
3538

39+
@Before
40+
fun setup() {
41+
whenever(variantManager.getVariant(any())).thenReturn(VariantManager.DEFAULT_VARIANT)
42+
}
43+
3644
@Test
3745
fun whenSingleWordThenSearchQueryBuilt() {
3846
val input = "foo"

0 commit comments

Comments
 (0)