Skip to content

Commit 275358a

Browse files
Merge branch 'release/5.241.0'
2 parents 8b37705 + 738cd98 commit 275358a

File tree

187 files changed

+5281
-1171
lines changed

Some content is hidden

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

187 files changed

+5281
-1171
lines changed

.github/workflows/end-to-end-robintest.yml

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,14 @@ jobs:
5252

5353
- name: Move APK to new folder
5454
if: always()
55-
run: find . -name "*.apk" -exec mv '{}' apk/release.apk \;
55+
run: find . -name "*play-release*.apk" -exec mv '{}' apk/release.apk \;
56+
57+
- name: Assemble internal release APK
58+
run: ./gradlew assembleInternalRelease -Pforce-default-variant -Pskip-onboarding
59+
60+
- name: Move APK to new folder
61+
if: always()
62+
run: find . -name "*internal-release*.apk" -exec mv '{}' apk/internal.apk \;
5663

5764
- name: Onboarding flows
5865
uses: mobile-dev-inc/[email protected]
@@ -94,6 +101,20 @@ jobs:
94101
workspace: .maestro
95102
include-tags: privacyTest
96103

104+
- name: Internal Privacy Tests
105+
if: always()
106+
uses: mobile-dev-inc/[email protected]
107+
timeout-minutes: 120
108+
with:
109+
api-key: ${{ secrets.ROBIN_API_KEY }}
110+
project-id: ${{ vars.ROBIN_ANDROID_PROJECT_ID }}
111+
name: internalPrivacyTest_${{ github.sha }}
112+
timeout: ${{ vars.ROBIN_TIMEOUT_MINUTES }}
113+
app-file: apk/internal.apk
114+
android-api-level: 34
115+
workspace: .maestro
116+
include-tags: privacyTestInternal
117+
97118
- name: Security Tests
98119
if: always()
99120
uses: mobile-dev-inc/[email protected]

.maestro/browsing/visit_site.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ tags:
2424
id: "omnibarTextInput"
2525
- eraseText
2626
- assertVisible:
27-
text: "Search or type URL"
27+
text: "Search"
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
appId: com.duckduckgo.mobile.android
2+
tags:
3+
- privacyTestInternal
4+
---
5+
- retry:
6+
maxRetries: 3
7+
commands:
8+
- launchApp:
9+
clearState: true
10+
- runFlow: ../shared/skip_all_onboarding.yaml
11+
- tapOn:
12+
id: "com.duckduckgo.mobile.android:id/browserMenu"
13+
- tapOn:
14+
id: "com.duckduckgo.mobile.android:id/settingsMenuItem"
15+
- scrollUntilVisible:
16+
element:
17+
text: "Developer Settings"
18+
direction: DOWN
19+
timeout: 50000
20+
speed: 40
21+
visibilityPercentage: 100
22+
centerElement: false
23+
- tapOn: "Developer Settings"
24+
- scrollUntilVisible:
25+
element:
26+
id: "com.duckduckgo.mobile.android:id/overridePrivacyRemoteConfigUrl"
27+
direction: DOWN
28+
timeout: 50000
29+
speed: 40
30+
visibilityPercentage: 100
31+
centerElement: true
32+
- tapOn:
33+
id: "com.duckduckgo.mobile.android:id/overridePrivacyRemoteConfigUrl"
34+
- tapOn:
35+
id: "com.duckduckgo.mobile.android:id/trailingSwitch"
36+
- tapOn:
37+
id: "com.duckduckgo.mobile.android:id/internal_edit_text"
38+
- inputText: "https://privacy-test-pages.site/content-scope-scripts/infra/config/conditional-matching-experiments.json"
39+
- hideKeyboard
40+
- tapOn:
41+
id: "com.duckduckgo.mobile.android:id/load"
42+
- tapOn: "OK"
43+
- pressKey: Back
44+
- pressKey: Back
45+
- pressKey: Back
46+
- assertVisible:
47+
id: "com.duckduckgo.mobile.android:id/omnibarTextInput"
48+
- inputText: "https://privacy-test-pages.site/content-scope-scripts/infra/pages/conditional-matching-experiments.html?automation=1"
49+
- pressKey: Enter
50+
- tapOn:
51+
id: "run-tests"
52+
- assertVisible:
53+
id: "test-status"
54+
text: "pass"

.maestro/security_tests/5_-_AddressBarSpoof,_downloadpath.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ tags:
2222
- tapOn: "Save to Downloads"
2323
- copyTextFrom:
2424
id: "omnibarTextInput"
25-
- assertTrue: ${maestro.copiedText == "Search or type URL"} # Downloads should occur in empty origin.
25+
- assertTrue: ${maestro.copiedText == "Search"} # Downloads should occur in empty origin.
2626
- pressKey: Back
2727
# Download Cancel Flow:
2828
- tapOn: "Start"

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

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,11 @@ import com.duckduckgo.browser.api.autocomplete.AutoComplete.AutoCompleteSuggesti
216216
import com.duckduckgo.browser.api.autocomplete.AutoComplete.AutoCompleteSuggestion.AutoCompleteSearchSuggestion
217217
import com.duckduckgo.browser.api.autocomplete.AutoComplete.AutoCompleteSuggestion.AutoCompleteUrlSuggestion.AutoCompleteBookmarkSuggestion
218218
import com.duckduckgo.browser.api.autocomplete.AutoComplete.AutoCompleteSuggestion.AutoCompleteUrlSuggestion.AutoCompleteSwitchToTabSuggestion
219+
import com.duckduckgo.browser.api.autocomplete.AutoCompleteSettings
219220
import com.duckduckgo.browser.api.brokensite.BrokenSiteContext
220221
import com.duckduckgo.common.test.CoroutineTestRule
221222
import com.duckduckgo.common.test.InstantSchedulersRule
222-
import com.duckduckgo.common.ui.experiments.visual.store.VisualDesignExperimentDataStore
223+
import com.duckduckgo.common.ui.experiments.visual.store.ExperimentalThemingDataStore
223224
import com.duckduckgo.common.ui.tabs.SwipingTabsFeature
224225
import com.duckduckgo.common.ui.tabs.SwipingTabsFeatureProvider
225226
import com.duckduckgo.common.utils.DispatcherProvider
@@ -231,6 +232,7 @@ import com.duckduckgo.daxprompts.impl.ReactivateUsersExperiment
231232
import com.duckduckgo.downloads.api.DownloadStateListener
232233
import com.duckduckgo.downloads.api.FileDownloader
233234
import com.duckduckgo.downloads.api.FileDownloader.PendingFileDownload
235+
import com.duckduckgo.duckchat.api.DuckAiFeatureState
234236
import com.duckduckgo.duckchat.api.DuckChat
235237
import com.duckduckgo.duckchat.impl.helper.DuckChatJSHelper
236238
import com.duckduckgo.duckchat.impl.helper.RealDuckChatJSHelper.Companion.DUCK_CHAT_FEATURE_NAME
@@ -431,6 +433,8 @@ class BrowserTabViewModelTest {
431433

432434
private val mockSettingsDataStore: SettingsDataStore = mock()
433435

436+
private val mockAutoCompleteSettings: AutoCompleteSettings = mock()
437+
434438
private val mockAdClickManager: AdClickManager = mock()
435439

436440
private val mockUserAllowListRepository: UserAllowListRepository = mock()
@@ -443,6 +447,8 @@ class BrowserTabViewModelTest {
443447

444448
private val mockDuckChat: DuckChat = mock()
445449

450+
private val mockDuckAiFeatureState: DuckAiFeatureState = mock()
451+
446452
private val mockAppBuildConfig: AppBuildConfig = mock()
447453

448454
private val mockDuckDuckGoUrlDetector: DuckDuckGoUrlDetector = mock()
@@ -551,7 +557,7 @@ class BrowserTabViewModelTest {
551557
private val mockDefaultBrowserPromptsExperiment: DefaultBrowserPromptsExperiment = mock()
552558
val mockStack: WebBackForwardList = mock()
553559

554-
private val mockVisualDesignExperimentDataStore: VisualDesignExperimentDataStore = mock()
560+
private val mockExperimentalThemingDataStore: ExperimentalThemingDataStore = mock()
555561
private val defaultVisualExperimentStateFlow = MutableStateFlow(false)
556562

557563
private val mockSiteErrorHandlerKillSwitch: SiteErrorHandlerKillSwitch = mock()
@@ -643,8 +649,8 @@ class BrowserTabViewModelTest {
643649
whenever(mockSitePermissionsManager.hasSitePermanentPermission(any(), any())).thenReturn(false)
644650
whenever(mockToggleReports.shouldPrompt()).thenReturn(false)
645651
whenever(subscriptions.isEligible()).thenReturn(false)
646-
whenever(mockDuckChat.showInBrowserMenu).thenReturn(MutableStateFlow(false))
647-
whenever(mockDuckChat.showInputScreen).thenReturn(MutableStateFlow(false))
652+
whenever(mockDuckAiFeatureState.showPopupMenuShortcut).thenReturn(MutableStateFlow(false))
653+
whenever(mockDuckAiFeatureState.showInputScreen).thenReturn(MutableStateFlow(false))
648654

649655
remoteMessagingModel = givenRemoteMessagingModel(mockRemoteMessagingRepository, mockPixel, coroutineRule.testDispatcherProvider)
650656

@@ -703,9 +709,6 @@ class BrowserTabViewModelTest {
703709
whenever(mockDefaultBrowserPromptsExperiment.showSetAsDefaultPopupMenuItem).thenReturn(
704710
defaultBrowserPromptsExperimentShowPopupMenuItemFlow,
705711
)
706-
whenever(mockVisualDesignExperimentDataStore.isExperimentEnabled).thenReturn(
707-
defaultVisualExperimentStateFlow,
708-
)
709712

710713
whenever(mockSiteErrorHandlerKillSwitch.self()).thenReturn(mockSiteErrorHandlerKillSwitchToggle)
711714

@@ -764,6 +767,7 @@ class BrowserTabViewModelTest {
764767
httpErrorPixels = { mockHttpErrorPixels },
765768
duckPlayer = mockDuckPlayer,
766769
duckChat = mockDuckChat,
770+
duckAiFeatureState = mockDuckAiFeatureState,
767771
duckPlayerJSHelper = DuckPlayerJSHelper(
768772
mockDuckPlayer,
769773
mockAppBuildConfig,
@@ -783,7 +787,7 @@ class BrowserTabViewModelTest {
783787
tabStatsBucketing = mockTabStatsBucketing,
784788
defaultBrowserPromptsExperiment = mockDefaultBrowserPromptsExperiment,
785789
swipingTabsFeature = swipingTabsFeatureProvider,
786-
visualDesignExperimentDataStore = mockVisualDesignExperimentDataStore,
790+
experimentalThemingDataStore = mockExperimentalThemingDataStore,
787791
siteErrorHandlerKillSwitch = mockSiteErrorHandlerKillSwitch,
788792
siteErrorHandler = mockSiteErrorHandler,
789793
siteHttpErrorHandler = mockSiteHttpErrorHandler,
@@ -792,6 +796,7 @@ class BrowserTabViewModelTest {
792796
onboardingDesignExperimentToggles = fakeOnboardingDesignExperimentToggles,
793797
tabManager = tabManager,
794798
addressDisplayFormatter = mockAddressDisplayFormatter,
799+
autoCompleteSettings = mockAutoCompleteSettings,
795800
)
796801

797802
testee.loadData("abc", null, false, false)
@@ -875,7 +880,7 @@ class BrowserTabViewModelTest {
875880
fun whenViewBecomesVisibleAndDuckAIPoCIsEnabledThenKeyboardNotShown() = runTest {
876881
whenever(mockExtendedOnboardingFeatureToggles.noBrowserCtas()).thenReturn(mockDisabledToggle)
877882
whenever(mockWidgetCapabilities.hasInstalledWidgets).thenReturn(true)
878-
whenever(mockDuckChat.showInputScreen).thenReturn(MutableStateFlow(true))
883+
whenever(mockDuckAiFeatureState.showInputScreen).thenReturn(MutableStateFlow(true))
879884

880885
testee.onViewVisible()
881886

@@ -921,15 +926,15 @@ class BrowserTabViewModelTest {
921926

922927
@Test
923928
fun whenViewBecomesVisibleAndDuckChatDisabledThenDuckChatNotVisible() {
924-
whenever(mockDuckChat.showInBrowserMenu).thenReturn(MutableStateFlow(false))
929+
whenever(mockDuckAiFeatureState.showPopupMenuShortcut).thenReturn(MutableStateFlow(false))
925930
setBrowserShowing(true)
926931
testee.onViewVisible()
927932
assertFalse(browserViewState().showDuckChatOption)
928933
}
929934

930935
@Test
931936
fun whenViewBecomesVisibleAndDuckChatEnabledThenDuckChatIsVisible() {
932-
whenever(mockDuckChat.showInBrowserMenu).thenReturn(MutableStateFlow(true))
937+
whenever(mockDuckAiFeatureState.showPopupMenuShortcut).thenReturn(MutableStateFlow(true))
933938
setBrowserShowing(true)
934939
testee.onViewVisible()
935940
assertTrue(browserViewState().showDuckChatOption)
@@ -1528,14 +1533,14 @@ class BrowserTabViewModelTest {
15281533
@Test
15291534
fun whenTriggeringAutocompleteThenAutoCompleteSuggestionsShown() = runTest {
15301535
whenever(mockAutoCompleteService.autoComplete("foo")).thenReturn(emptyList())
1531-
doReturn(true).whenever(ctaViewModelMockSettingsStore).autoCompleteSuggestionsEnabled
1536+
doReturn(true).whenever(mockAutoCompleteSettings).autoCompleteSuggestionsEnabled
15321537
testee.triggerAutocomplete("foo", true, hasQueryChanged = true)
15331538
assertTrue(autoCompleteViewState().showSuggestions)
15341539
}
15351540

15361541
@Test
15371542
fun whenTriggeringAutoCompleteButNoQueryChangeThenAutoCompleteSuggestionsNotShown() {
1538-
doReturn(true).whenever(ctaViewModelMockSettingsStore).autoCompleteSuggestionsEnabled
1543+
doReturn(true).whenever(mockAutoCompleteSettings).autoCompleteSuggestionsEnabled
15391544
testee.triggerAutocomplete("foo", true, hasQueryChanged = false)
15401545
assertFalse(autoCompleteViewState().showSuggestions)
15411546
}
@@ -1556,7 +1561,7 @@ class BrowserTabViewModelTest {
15561561
),
15571562
),
15581563
)
1559-
doReturn(true).whenever(ctaViewModelMockSettingsStore).autoCompleteSuggestionsEnabled
1564+
doReturn(true).whenever(mockAutoCompleteSettings).autoCompleteSuggestionsEnabled
15601565
testee.triggerAutocomplete("https://example.com", true, hasQueryChanged = false)
15611566
assertFalse(autoCompleteViewState().showSuggestions)
15621567
assertTrue(autoCompleteViewState().showFavorites)
@@ -1578,7 +1583,7 @@ class BrowserTabViewModelTest {
15781583
whenever(mockTabRepository.flowTabs).thenReturn(
15791584
flowOf(listOf(TabEntity(tabId = "1", position = 1, url = "https://example.com", title = "title"))),
15801585
)
1581-
doReturn(true).whenever(ctaViewModelMockSettingsStore).autoCompleteSuggestionsEnabled
1586+
doReturn(true).whenever(mockAutoCompleteSettings).autoCompleteSuggestionsEnabled
15821587

15831588
whenever(mockAutoCompleteRepository.wasHistoryInAutoCompleteIAMDismissed()).thenReturn(false)
15841589
whenever(mockAutoCompleteRepository.countHistoryInAutoCompleteIAMShown()).thenReturn(0)
@@ -1604,7 +1609,7 @@ class BrowserTabViewModelTest {
16041609
flowOf(listOf(Favorite("abc", "title", "https://example.com", position = 1, lastModified = null))),
16051610
)
16061611
whenever(mockNavigationHistory.getHistory()).thenReturn(flowOf(emptyList()))
1607-
doReturn(true).whenever(ctaViewModelMockSettingsStore).autoCompleteSuggestionsEnabled
1612+
doReturn(true).whenever(mockAutoCompleteSettings).autoCompleteSuggestionsEnabled
16081613
testee.autoCompleteStateFlow.value = "query"
16091614
testee.autoCompleteSuggestionsGone()
16101615
verify(mockAutoCompleteRepository, never()).submitUserSeenHistoryIAM()

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ import com.duckduckgo.common.test.CoroutineTestRule
7373
import com.duckduckgo.common.utils.CurrentTimeProvider
7474
import com.duckduckgo.common.utils.device.DeviceInfo
7575
import com.duckduckgo.common.utils.plugins.PluginPoint
76+
import com.duckduckgo.contentscopescripts.api.contentscopeExperiments.ContentScopeExperiments
7677
import com.duckduckgo.cookies.api.CookieManagerProvider
7778
import com.duckduckgo.duckchat.api.DuckChat
7879
import com.duckduckgo.duckplayer.api.DuckPlayer
@@ -81,6 +82,7 @@ import com.duckduckgo.duckplayer.api.DuckPlayer.OpenDuckPlayerInNewTab
8182
import com.duckduckgo.duckplayer.api.DuckPlayer.OpenDuckPlayerInNewTab.Off
8283
import com.duckduckgo.duckplayer.api.DuckPlayer.OpenDuckPlayerInNewTab.On
8384
import com.duckduckgo.duckplayer.api.DuckPlayer.OpenDuckPlayerInNewTab.Unavailable
85+
import com.duckduckgo.feature.toggles.api.Toggle
8486
import com.duckduckgo.history.api.NavigationHistory
8587
import com.duckduckgo.privacy.config.api.AmpLinks
8688
import com.duckduckgo.subscriptions.api.Subscriptions
@@ -164,6 +166,7 @@ class BrowserWebViewClientTest {
164166
mock(),
165167
)
166168
private val mockDuckChat: DuckChat = mock()
169+
private val mockContentScopeExperiments: ContentScopeExperiments = mock()
167170

168171
@UiThreadTest
169172
@Before
@@ -202,6 +205,7 @@ class BrowserWebViewClientTest {
202205
mockUriLoadedManager,
203206
mockAndroidFeaturesHeaderPlugin,
204207
mockDuckChat,
208+
mockContentScopeExperiments,
205209
)
206210
testee.webViewClientListener = listener
207211
whenever(webResourceRequest.url).thenReturn(Uri.EMPTY)
@@ -221,8 +225,11 @@ class BrowserWebViewClientTest {
221225
@UiThreadTest
222226
@Test
223227
fun whenOnPageStartedCalledThenListenerNotified() {
228+
val toggle: Toggle = mock()
229+
whenever(mockContentScopeExperiments.getActiveExperiments()).thenReturn(listOf(toggle))
230+
224231
testee.onPageStarted(webView, EXAMPLE_URL, null)
225-
verify(listener).pageStarted(any())
232+
verify(listener).pageStarted(any(), eq(listOf(toggle)))
226233
}
227234

228235
@UiThreadTest
@@ -1185,7 +1192,12 @@ class BrowserWebViewClientTest {
11851192
var countFinished = 0
11861193
var countStarted = 0
11871194

1188-
override fun onPageStarted(webView: WebView, url: String?, site: Site?) {
1195+
override fun onPageStarted(
1196+
webView: WebView,
1197+
url: String?,
1198+
isDesktopMode: Boolean?,
1199+
activeExperiments: List<Toggle>,
1200+
) {
11891201
countStarted++
11901202
}
11911203

0 commit comments

Comments
 (0)