For #17771: three-dot menu reorder (#17838)

* Feature flag for toolbar menu redesign. Add new items to menu and reorder.

* Handle toolbar items in menu controller

* Menu controller tests

* Make icons invisible

* Lint

* UI tests reflect design change

* Refactor test names

* Lint fixes

* UI tests
upstream-sync
Elise Richards 3 years ago committed by GitHub
parent eabde04679
commit d0fd3e82c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,6 +12,8 @@ import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.ui.robots.navigationToolbar
import androidx.test.espresso.IdlingRegistry
import org.junit.Ignore
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
import org.mozilla.fenix.helpers.ViewVisibilityIdlingResource
@ -29,7 +31,7 @@ import org.mozilla.fenix.ui.robots.mDevice
*
*/
// @Ignore("Temp disable - reader view page detection issues: https://github.com/mozilla-mobile/fenix/issues/9688 ")
@Ignore("Temp disable - reader view page detection issues: https://github.com/mozilla-mobile/fenix/issues/9688 ")
class ReaderViewTest {
private lateinit var mockWebServer: MockWebServer
private var readerViewNotification: ViewVisibilityIdlingResource? = null
@ -103,39 +105,42 @@ class ReaderViewTest {
@Test
fun verifyReaderViewToggle() {
val readerViewPage =
TestAssetHelper.getLoremIpsumAsset(mockWebServer)
navigationToolbar {
}.enterURLAndEnterToBrowser(readerViewPage.url) {
mDevice.waitForIdle()
// New three-dot menu design does not have readerview
if (!FeatureFlags.toolbarMenuFeature) {
val readerViewPage =
TestAssetHelper.getLoremIpsumAsset(mockWebServer)
navigationToolbar {
}.enterURLAndEnterToBrowser(readerViewPage.url) {
mDevice.waitForIdle()
}
readerViewNotification = ViewVisibilityIdlingResource(
activityIntentTestRule.activity.findViewById(R.id.mozac_browser_toolbar_page_actions),
View.VISIBLE
)
IdlingRegistry.getInstance().register(readerViewNotification)
navigationToolbar {
verifyReaderViewDetected(true)
toggleReaderView()
mDevice.waitForIdle()
}
browserScreen {
verifyPageContent(estimatedReadingTime)
}.openThreeDotMenu {
verifyReaderViewAppearance(true)
}.closeBrowserMenuToBrowser { }
navigationToolbar {
toggleReaderView()
mDevice.waitForIdle()
}.openThreeDotMenu {
verifyReaderViewAppearance(false)
}.close { }
}
readerViewNotification = ViewVisibilityIdlingResource(
activityIntentTestRule.activity.findViewById(R.id.mozac_browser_toolbar_page_actions),
View.VISIBLE
)
IdlingRegistry.getInstance().register(readerViewNotification)
navigationToolbar {
verifyReaderViewDetected(true)
toggleReaderView()
mDevice.waitForIdle()
}
browserScreen {
verifyPageContent(estimatedReadingTime)
}.openThreeDotMenu {
verifyReaderViewAppearance(true)
}.closeBrowserMenuToBrowser { }
navigationToolbar {
toggleReaderView()
mDevice.waitForIdle()
}.openThreeDotMenu {
verifyReaderViewAppearance(false)
}.close { }
}
@Test

@ -79,19 +79,23 @@ class SettingsAddonsTest {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
val addonName = "uBlock Origin"
navigationToolbar {
}.openNewTabAndEnterToBrowser(defaultWebPage.url) {
}.openThreeDotMenu {
}.openAddonsManagerMenu {
addonsListIdlingResource =
RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.add_ons_list), 1)
IdlingRegistry.getInstance().register(addonsListIdlingResource!!)
clickInstallAddon(addonName)
verifyAddonPrompt(addonName)
cancelInstallAddon()
clickInstallAddon(addonName)
acceptInstallAddon()
verifyDownloadAddonPrompt(addonName, activityTestRule)
navigationToolbar {}
.openNewTabAndEnterToBrowser(defaultWebPage.url) {}
.openThreeDotMenu {}
.openAddonsManagerMenu {
addonsListIdlingResource =
RecyclerViewIdlingResource(
activityTestRule.activity.findViewById(R.id.add_ons_list),
1
)
IdlingRegistry.getInstance().register(addonsListIdlingResource!!)
clickInstallAddon(addonName)
verifyAddonPrompt(addonName)
cancelInstallAddon()
clickInstallAddon(addonName)
acceptInstallAddon()
verifyDownloadAddonPrompt(addonName, activityTestRule)
}
}

@ -14,6 +14,7 @@ import androidx.test.uiautomator.UiDevice
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Before
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.R
@ -198,6 +199,7 @@ class SmokeTest {
@Test
// Verifies the list of items in a tab's 3 dot menu
@Ignore("To be re-implemented with the three dot menu changes https://github.com/mozilla-mobile/fenix/issues/17870")
fun verifyPageMainMenuItemsTest() {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
@ -231,6 +233,7 @@ class SmokeTest {
}
@Test
@Ignore("To be re-implemented in https://github.com/mozilla-mobile/fenix/issues/17798")
// Verifies the Synced tabs menu opens from a tab's 3 dot menu
fun openMainMenuSyncedTabsItemTest() {
homeScreen {
@ -362,6 +365,7 @@ class SmokeTest {
@Test
// Turns ETP toggle off from Settings and verifies the ETP shield is not displayed in the nav bar
@Ignore("To be re-implemented with the three dot menu changes https://github.com/mozilla-mobile/fenix/issues/17870")
fun verifyETPShieldNotDisplayedIfOFFGlobally() {
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
@ -537,6 +541,7 @@ class SmokeTest {
@Test
// Saves a login, then changes it and verifies the update
@Ignore("To be re-implemented with the three dot menu changes https://github.com/mozilla-mobile/fenix/issues/17870")
fun updateSavedLoginTest() {
val saveLoginTest =
TestAssetHelper.getSaveLoginAsset(mockWebServer)
@ -600,6 +605,7 @@ class SmokeTest {
}
@Test
@Ignore("To be re-implemented in https://github.com/mozilla-mobile/fenix/issues/17799")
// Installs uBlock add-on and checks that the app doesn't crash while loading pages with trackers
fun noCrashWithAddonInstalledTest() {
// setting ETP to Strict mode to test it works with add-ons
@ -1107,6 +1113,7 @@ class SmokeTest {
}
@Test
@Ignore("To be re-implemented in https://github.com/mozilla-mobile/fenix/issues/17799")
fun mainMenuInstallPWATest() {
val pwaPage = "https://rpappalax.github.io/testapp/"
@ -1123,6 +1130,7 @@ class SmokeTest {
}
@Test
@Ignore("To be re-implemented in https://github.com/mozilla-mobile/fenix/issues/17971")
// Verifies that reader mode is detected and the custom appearance controls are displayed
fun verifyReaderViewAppearanceUI() {
val readerViewPage =

@ -8,6 +8,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Before
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.ext.settings
@ -126,6 +127,7 @@ class StrictEnhancedTrackingProtectionTest {
}
@Test
@Ignore("To be re-implemented with the three dot menu changes https://github.com/mozilla-mobile/fenix/issues/17870")
fun testStrictVisitDisable() {
val trackingProtectionTest =
TestAssetHelper.getEnhancedTrackingProtectionAsset(mockWebServer)

@ -12,6 +12,7 @@ import org.junit.Before
import org.junit.BeforeClass
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
import org.mozilla.fenix.helpers.HomeActivityTestRule
import org.mozilla.fenix.ui.robots.homeScreen
@ -54,42 +55,68 @@ class ThreeDotMenuMainTest {
@Test
fun threeDotMenuItemsTest() {
homeScreen {
}.openThreeDotMenu {
verifySettingsButton()
verifyBookmarksButton()
verifyHistoryButton()
verifyHelpButton()
verifyWhatsNewButton()
}.openSettings {
verifySettingsView()
}.goBack {
}.openThreeDotMenu {
}.openHelp {
verifyHelpUrl()
}.openTabDrawer {
closeTab()
}
if (FeatureFlags.toolbarMenuFeature) {
homeScreen {
}.openThreeDotMenu {
}.openHistory {
verifyHistoryMenuView()
}.goBackToBrowser {}
homeScreen {
}.openThreeDotMenu {
}.openWhatsNew {
verifyWhatsNewURL()
}.openTabDrawer {
closeTab()
}
homeScreen {
}.openThreeDotMenu {
}.openBookmarks {
verifyBookmarksMenuView()
}.closeMenu {}
homeScreen {
}.openThreeDotMenu {
}.openBookmarks {
verifyBookmarksMenuView()
}.closeMenu {
}
homeScreen {
}.openThreeDotMenu {
verifySettingsButton()
verifyBookmarksButton()
verifyHistoryButton()
}.openSettings {
verifySettingsView()
}.goBack {
}.openThreeDotMenu {
}.goBack {}
} else {
homeScreen {
}.openThreeDotMenu {
verifySettingsButton()
verifyBookmarksButton()
verifyHistoryButton()
verifyHelpButton()
verifyWhatsNewButton()
}.openSettings {
verifySettingsView()
}.goBack {
}.openThreeDotMenu {
}.openHelp {
verifyHelpUrl()
}.openTabDrawer {
closeTab()
}
homeScreen {
}.openThreeDotMenu {
}.openHistory {
verifyHistoryMenuView()
homeScreen {
}.openThreeDotMenu {
}.openWhatsNew {
verifyWhatsNewURL()
}.openTabDrawer {
closeTab()
}
homeScreen {
}.openThreeDotMenu {
}.openBookmarks {
verifyBookmarksMenuView()
}.closeMenu {
}
homeScreen {
}.openThreeDotMenu {
}.openHistory {
verifyHistoryMenuView()
}
}
}
}

@ -38,6 +38,7 @@ import androidx.test.uiautomator.Until
import org.hamcrest.Matcher
import org.hamcrest.Matchers.allOf
import org.junit.Assert.assertTrue
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.helpers.click
@ -124,21 +125,33 @@ class ThreeDotMenuMainRobot {
fun verifyShareTabsOverlay() = assertShareTabsOverlay()
fun verifyThreeDotMainMenuItems() {
verifyAddOnsButton()
verifyDownloadsButton()
verifyHistoryButton()
verifyBookmarksButton()
verifySyncedTabsButton()
verifySettingsButton()
verifyFindInPageButton()
verifyAddFirefoxHome()
verifyAddToMobileHome()
verifyDesktopSite()
verifySaveCollection()
verifyAddBookmarkButton()
verifyShareButton()
verifyForwardButton()
verifyRefreshButton()
if (FeatureFlags.toolbarMenuFeature) {
verifyDownloadsButton()
verifyHistoryButton()
verifyBookmarksButton()
verifySettingsButton()
verifyDesktopSite()
verifySaveCollection()
verifyShareButton()
verifyForwardButton()
verifyRefreshButton()
} else {
verifyAddOnsButton()
verifyDownloadsButton()
verifyHistoryButton()
verifyBookmarksButton()
verifySyncedTabsButton()
verifySettingsButton()
verifyFindInPageButton()
verifyAddFirefoxHome()
verifyAddToMobileHome()
verifyDesktopSite()
verifySaveCollection()
verifyAddBookmarkButton()
verifyShareButton()
verifyForwardButton()
verifyRefreshButton()
}
}
private fun assertShareTabsOverlay() {
@ -390,7 +403,8 @@ private fun assertSettingsButton() = settingsButton()
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
.check(matches(isCompletelyDisplayed()))
private fun addOnsButton() = onView(allOf(withText("Add-ons")))
private val addOnsText = if (FeatureFlags.toolbarMenuFeature) "Extensions" else "Add-ons"
private fun addOnsButton() = onView(allOf(withText(addOnsText)))
private fun assertAddOnsButton() {
onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeDown())
addOnsButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE)))

@ -30,4 +30,9 @@ object FeatureFlags {
* Enables WebAuthn support.
*/
val webAuthFeature = Config.channel.isNightlyOrDebug
/**
* Shows new three-dot toolbar menu design.
*/
val toolbarMenuFeature = Config.channel.isDebug
}

@ -51,7 +51,7 @@ interface BrowserToolbarMenuController {
fun handleToolbarItemInteraction(item: ToolbarMenu.Item)
}
@Suppress("LargeClass")
@Suppress("LargeClass", "ForbiddenComment")
class DefaultBrowserToolbarMenuController(
private val activity: HomeActivity,
private val navController: NavController,
@ -87,6 +87,76 @@ class DefaultBrowserToolbarMenuController(
trackToolbarItemInteraction(item)
Do exhaustive when (item) {
// TODO: These can be removed for https://github.com/mozilla-mobile/fenix/issues/17870
// todo === Start ===
is ToolbarMenu.Item.InstallToHomeScreen -> {
settings.installPwaOpened = true
MainScope().launch {
with(activity.components.useCases.webAppUseCases) {
if (isInstallable()) {
addToHomescreen()
} else {
val directions =
BrowserFragmentDirections.actionBrowserFragmentToCreateShortcutFragment()
navController.navigateSafe(R.id.browserFragment, directions)
}
}
}
}
is ToolbarMenu.Item.OpenInFenix -> {
// Stop the SessionFeature from updating the EngineView and let it release the session
// from the EngineView so that it can immediately be rendered by a different view once
// we switch to the actual browser.
sessionFeature.get()?.release()
// Strip the CustomTabConfig to turn this Session into a regular tab and then select it
customTabSession!!.customTabConfig = null
sessionManager.select(customTabSession)
// Switch to the actual browser which should now display our new selected session
activity.startActivity(openInFenixIntent.apply {
// We never want to launch the browser in the same task as the external app
// activity. So we force a new task here. IntentReceiverActivity will do the
// right thing and take care of routing to an already existing browser and avoid
// cloning a new one.
flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK
})
// Close this activity (and the task) since it is no longer displaying any session
activity.finishAndRemoveTask()
}
is ToolbarMenu.Item.Quit -> {
// We need to show the snackbar while the browsing data is deleting (if "Delete
// browsing data on quit" is activated). After the deletion is over, the snackbar
// is dismissed.
val snackbar: FenixSnackbar? = activity.getRootView()?.let { v ->
FenixSnackbar.make(
view = v,
duration = Snackbar.LENGTH_LONG,
isDisplayedWithBrowserToolbar = true
)
.setText(v.context.getString(R.string.deleting_browsing_data_in_progress))
}
deleteAndQuit(activity, scope, snackbar)
}
is ToolbarMenu.Item.ReaderModeAppearance -> {
readerModeController.showControls()
metrics.track(Event.ReaderModeAppearanceOpened)
}
is ToolbarMenu.Item.OpenInApp -> {
settings.openInAppOpened = true
val appLinksUseCases = activity.components.useCases.appLinksUseCases
val getRedirect = appLinksUseCases.appLinkRedirect
currentSession?.let {
val redirect = getRedirect.invoke(it.url)
redirect.appIntent?.flags = Intent.FLAG_ACTIVITY_NEW_TASK
appLinksUseCases.openAppLink.invoke(redirect.appIntent)
}
}
// todo === End ===
is ToolbarMenu.Item.Back -> {
if (item.viewHistory) {
navController.navigate(
@ -118,12 +188,24 @@ class DefaultBrowserToolbarMenuController(
sessionUseCases.reload.invoke(currentSession, flags = flags)
}
ToolbarMenu.Item.Stop -> sessionUseCases.stopLoading.invoke(currentSession)
ToolbarMenu.Item.Settings -> browserAnimator.captureEngineViewAndDrawStatically {
is ToolbarMenu.Item.Stop -> sessionUseCases.stopLoading.invoke(currentSession)
is ToolbarMenu.Item.Share -> {
val directions = NavGraphDirections.actionGlobalShareFragment(
data = arrayOf(
ShareData(
url = getProperUrl(currentSession),
title = currentSession?.title
)
),
showPage = true
)
navController.navigate(directions)
}
is ToolbarMenu.Item.Settings -> browserAnimator.captureEngineViewAndDrawStatically {
val directions = BrowserFragmentDirections.actionBrowserFragmentToSettingsFragment()
navController.nav(R.id.browserFragment, directions)
}
ToolbarMenu.Item.SyncedTabs -> browserAnimator.captureEngineViewAndDrawStatically {
is ToolbarMenu.Item.SyncedTabs -> browserAnimator.captureEngineViewAndDrawStatically {
navController.nav(
R.id.browserFragment,
BrowserFragmentDirections.actionBrowserFragmentToSyncedTabsFragment()
@ -133,7 +215,7 @@ class DefaultBrowserToolbarMenuController(
item.isChecked,
currentSession
)
ToolbarMenu.Item.AddToTopSites -> {
is ToolbarMenu.Item.AddToTopSites -> {
scope.launch {
val context = swipeRefresh.context
val numPinnedSites =
@ -169,7 +251,7 @@ class DefaultBrowserToolbarMenuController(
}
}
}
ToolbarMenu.Item.AddToHomeScreen, ToolbarMenu.Item.InstallToHomeScreen -> {
is ToolbarMenu.Item.AddToHomeScreen -> {
settings.installPwaOpened = true
MainScope().launch {
with(activity.components.useCases.webAppUseCases) {
@ -183,31 +265,17 @@ class DefaultBrowserToolbarMenuController(
}
}
}
ToolbarMenu.Item.Share -> {
val directions = NavGraphDirections.actionGlobalShareFragment(
data = arrayOf(
ShareData(
url = getProperUrl(currentSession),
title = currentSession?.title
)
),
showPage = true
)
navController.navigate(directions)
}
ToolbarMenu.Item.FindInPage -> {
is ToolbarMenu.Item.FindInPage -> {
findInPageLauncher()
metrics.track(Event.FindInPageOpened)
}
ToolbarMenu.Item.AddonsManager -> browserAnimator.captureEngineViewAndDrawStatically {
is ToolbarMenu.Item.AddonsManager -> browserAnimator.captureEngineViewAndDrawStatically {
navController.nav(
R.id.browserFragment,
BrowserFragmentDirections.actionGlobalAddonsManagementFragment()
)
}
ToolbarMenu.Item.SaveToCollection -> {
is ToolbarMenu.Item.SaveToCollection -> {
metrics
.track(Event.CollectionSaveButtonPressed(TELEMETRY_BROWSER_IDENTIFIER))
@ -225,82 +293,35 @@ class DefaultBrowserToolbarMenuController(
navController.nav(R.id.browserFragment, directions)
}
}
ToolbarMenu.Item.OpenInFenix -> {
// Stop the SessionFeature from updating the EngineView and let it release the session
// from the EngineView so that it can immediately be rendered by a different view once
// we switch to the actual browser.
sessionFeature.get()?.release()
// Strip the CustomTabConfig to turn this Session into a regular tab and then select it
customTabSession!!.customTabConfig = null
sessionManager.select(customTabSession)
// Switch to the actual browser which should now display our new selected session
activity.startActivity(openInFenixIntent.apply {
// We never want to launch the browser in the same task as the external app
// activity. So we force a new task here. IntentReceiverActivity will do the
// right thing and take care of routing to an already existing browser and avoid
// cloning a new one.
flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK
})
// Close this activity (and the task) since it is no longer displaying any session
activity.finishAndRemoveTask()
}
ToolbarMenu.Item.Quit -> {
// We need to show the snackbar while the browsing data is deleting (if "Delete
// browsing data on quit" is activated). After the deletion is over, the snackbar
// is dismissed.
val snackbar: FenixSnackbar? = activity.getRootView()?.let { v ->
FenixSnackbar.make(
view = v,
duration = Snackbar.LENGTH_LONG,
isDisplayedWithBrowserToolbar = true
)
.setText(v.context.getString(R.string.deleting_browsing_data_in_progress))
}
deleteAndQuit(activity, scope, snackbar)
}
ToolbarMenu.Item.ReaderModeAppearance -> {
readerModeController.showControls()
metrics.track(Event.ReaderModeAppearanceOpened)
}
ToolbarMenu.Item.OpenInApp -> {
settings.openInAppOpened = true
val appLinksUseCases = activity.components.useCases.appLinksUseCases
val getRedirect = appLinksUseCases.appLinkRedirect
currentSession?.let {
val redirect = getRedirect.invoke(it.url)
redirect.appIntent?.flags = Intent.FLAG_ACTIVITY_NEW_TASK
appLinksUseCases.openAppLink.invoke(redirect.appIntent)
}
}
ToolbarMenu.Item.Bookmark -> {
is ToolbarMenu.Item.Bookmark -> {
sessionManager.selectedSession?.let {
getProperUrl(it)?.let { url -> bookmarkTapped(url, it.title) }
}
}
ToolbarMenu.Item.Bookmarks -> browserAnimator.captureEngineViewAndDrawStatically {
is ToolbarMenu.Item.Bookmarks -> browserAnimator.captureEngineViewAndDrawStatically {
navController.nav(
R.id.browserFragment,
BrowserFragmentDirections.actionGlobalBookmarkFragment(BookmarkRoot.Mobile.id)
)
}
ToolbarMenu.Item.History -> browserAnimator.captureEngineViewAndDrawStatically {
is ToolbarMenu.Item.History -> browserAnimator.captureEngineViewAndDrawStatically {
navController.nav(
R.id.browserFragment,
BrowserFragmentDirections.actionGlobalHistoryFragment()
)
}
ToolbarMenu.Item.Downloads -> browserAnimator.captureEngineViewAndDrawStatically {
is ToolbarMenu.Item.Downloads -> browserAnimator.captureEngineViewAndDrawStatically {
navController.nav(
R.id.browserFragment,
BrowserFragmentDirections.actionGlobalDownloadsFragment()
)
}
is ToolbarMenu.Item.NewTab -> {
navController.navigate(
BrowserFragmentDirections.actionGlobalHome(focusOnAddressBar = true)
)
}
}
}
@ -318,35 +339,38 @@ class DefaultBrowserToolbarMenuController(
@Suppress("ComplexMethod")
private fun trackToolbarItemInteraction(item: ToolbarMenu.Item) {
val eventItem = when (item) {
// TODO: These can be removed for https://github.com/mozilla-mobile/fenix/issues/17870
// todo === Start ===
is ToolbarMenu.Item.OpenInFenix -> Event.BrowserMenuItemTapped.Item.OPEN_IN_FENIX
is ToolbarMenu.Item.InstallToHomeScreen -> Event.BrowserMenuItemTapped.Item.ADD_TO_HOMESCREEN
is ToolbarMenu.Item.Quit -> Event.BrowserMenuItemTapped.Item.QUIT
is ToolbarMenu.Item.ReaderModeAppearance ->
Event.BrowserMenuItemTapped.Item.READER_MODE_APPEARANCE
is ToolbarMenu.Item.OpenInApp -> Event.BrowserMenuItemTapped.Item.OPEN_IN_APP
// todo === End ===
is ToolbarMenu.Item.Back -> Event.BrowserMenuItemTapped.Item.BACK
is ToolbarMenu.Item.Forward -> Event.BrowserMenuItemTapped.Item.FORWARD
is ToolbarMenu.Item.Reload -> Event.BrowserMenuItemTapped.Item.RELOAD
ToolbarMenu.Item.Stop -> Event.BrowserMenuItemTapped.Item.STOP
ToolbarMenu.Item.Settings -> Event.BrowserMenuItemTapped.Item.SETTINGS
is ToolbarMenu.Item.Stop -> Event.BrowserMenuItemTapped.Item.STOP
is ToolbarMenu.Item.Share -> Event.BrowserMenuItemTapped.Item.SHARE
is ToolbarMenu.Item.Settings -> Event.BrowserMenuItemTapped.Item.SETTINGS
is ToolbarMenu.Item.RequestDesktop ->
if (item.isChecked) {
Event.BrowserMenuItemTapped.Item.DESKTOP_VIEW_ON
} else {
Event.BrowserMenuItemTapped.Item.DESKTOP_VIEW_OFF
}
ToolbarMenu.Item.FindInPage -> Event.BrowserMenuItemTapped.Item.FIND_IN_PAGE
ToolbarMenu.Item.OpenInFenix -> Event.BrowserMenuItemTapped.Item.OPEN_IN_FENIX
ToolbarMenu.Item.Share -> Event.BrowserMenuItemTapped.Item.SHARE
ToolbarMenu.Item.SaveToCollection -> Event.BrowserMenuItemTapped.Item.SAVE_TO_COLLECTION
ToolbarMenu.Item.AddToTopSites -> Event.BrowserMenuItemTapped.Item.ADD_TO_TOP_SITES
ToolbarMenu.Item.AddToHomeScreen -> Event.BrowserMenuItemTapped.Item.ADD_TO_HOMESCREEN
ToolbarMenu.Item.SyncedTabs -> Event.BrowserMenuItemTapped.Item.SYNC_TABS
ToolbarMenu.Item.InstallToHomeScreen -> Event.BrowserMenuItemTapped.Item.ADD_TO_HOMESCREEN
ToolbarMenu.Item.Quit -> Event.BrowserMenuItemTapped.Item.QUIT
ToolbarMenu.Item.ReaderModeAppearance ->
Event.BrowserMenuItemTapped.Item.READER_MODE_APPEARANCE
ToolbarMenu.Item.OpenInApp -> Event.BrowserMenuItemTapped.Item.OPEN_IN_APP
ToolbarMenu.Item.Bookmark -> Event.BrowserMenuItemTapped.Item.BOOKMARK
ToolbarMenu.Item.AddonsManager -> Event.BrowserMenuItemTapped.Item.ADDONS_MANAGER
ToolbarMenu.Item.Bookmarks -> Event.BrowserMenuItemTapped.Item.BOOKMARKS
ToolbarMenu.Item.History -> Event.BrowserMenuItemTapped.Item.HISTORY
ToolbarMenu.Item.Downloads -> Event.BrowserMenuItemTapped.Item.DOWNLOADS
is ToolbarMenu.Item.FindInPage -> Event.BrowserMenuItemTapped.Item.FIND_IN_PAGE
is ToolbarMenu.Item.SaveToCollection -> Event.BrowserMenuItemTapped.Item.SAVE_TO_COLLECTION
is ToolbarMenu.Item.AddToTopSites -> Event.BrowserMenuItemTapped.Item.ADD_TO_TOP_SITES
is ToolbarMenu.Item.AddToHomeScreen -> Event.BrowserMenuItemTapped.Item.ADD_TO_HOMESCREEN
is ToolbarMenu.Item.SyncedTabs -> Event.BrowserMenuItemTapped.Item.SYNC_TABS
is ToolbarMenu.Item.Bookmark -> Event.BrowserMenuItemTapped.Item.BOOKMARK
is ToolbarMenu.Item.AddonsManager -> Event.BrowserMenuItemTapped.Item.ADDONS_MANAGER
is ToolbarMenu.Item.Bookmarks -> Event.BrowserMenuItemTapped.Item.BOOKMARKS
is ToolbarMenu.Item.History -> Event.BrowserMenuItemTapped.Item.HISTORY
is ToolbarMenu.Item.Downloads -> Event.BrowserMenuItemTapped.Item.DOWNLOADS
is ToolbarMenu.Item.NewTab -> Event.BrowserMenuItemTapped.Item.NEW_TAB
}
metrics.track(Event.BrowserMenuItemTapped(eventItem))

@ -32,6 +32,7 @@ import mozilla.components.feature.webcompat.reporter.WebCompatReporterFeature
import mozilla.components.lib.state.ext.flowScoped
import mozilla.components.support.ktx.android.content.getColorFromAttr
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifAnyChanged
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
@ -69,7 +70,12 @@ class DefaultToolbarMenu(
override val menuBuilder by lazy {
WebExtensionBrowserMenuBuilder(
menuItems,
items =
if (FeatureFlags.toolbarMenuFeature) {
newCoreMenuItems
} else {
oldCoreMenuItems
},
endOfMenuAlwaysVisible = !shouldReverseItems,
store = store,
webExtIconTintColorResource = primaryTextColor(),
@ -179,7 +185,148 @@ class DefaultToolbarMenu(
} ?: false
// End of predicates //
private val menuItems by lazy {
private val oldCoreMenuItems by lazy {
val settings = BrowserMenuHighlightableItem(
label = context.getString(R.string.browser_menu_settings),
startImageResource = R.drawable.ic_settings,
iconTintColorResource = if (hasAccountProblem)
ThemeManager.resolveAttribute(R.attr.syncDisconnected, context) else
primaryTextColor(),
textColorResource = if (hasAccountProblem)
ThemeManager.resolveAttribute(R.attr.primaryText, context) else
primaryTextColor(),
highlight = BrowserMenuHighlight.HighPriority(
endImageResource = R.drawable.ic_sync_disconnected,
backgroundTint = context.getColorFromAttr(R.attr.syncDisconnectedBackground),
canPropagate = false
),
isHighlighted = { hasAccountProblem }
) {
onItemTapped.invoke(ToolbarMenu.Item.Settings)
}
val desktopMode = BrowserMenuImageSwitch(
imageResource = R.drawable.ic_desktop,
label = context.getString(R.string.browser_menu_desktop_site),
initialState = {
selectedSession?.content?.desktopMode ?: false
}
) { checked ->
onItemTapped.invoke(ToolbarMenu.Item.RequestDesktop(checked))
}
val addToTopSites = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_add_to_top_sites),
imageResource = R.drawable.ic_top_sites,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.AddToTopSites)
}
val addToHomescreen = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_add_to_homescreen),
imageResource = R.drawable.ic_add_to_homescreen,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.AddToHomeScreen)
}
val syncedTabs = BrowserMenuImageText(
label = context.getString(R.string.synced_tabs),
imageResource = R.drawable.ic_synced_tabs,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.SyncedTabs)
}
val installToHomescreen = BrowserMenuHighlightableItem(
label = context.getString(R.string.browser_menu_install_on_homescreen),
startImageResource = R.drawable.ic_add_to_homescreen,
iconTintColorResource = primaryTextColor(),
highlight = BrowserMenuHighlight.LowPriority(
label = context.getString(R.string.browser_menu_install_on_homescreen),
notificationTint = getColor(context, R.color.whats_new_notification_color)
),
isHighlighted = {
!context.settings().installPwaOpened
}
) {
onItemTapped.invoke(ToolbarMenu.Item.InstallToHomeScreen)
}
val findInPage = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_find_in_page),
imageResource = R.drawable.mozac_ic_search,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.FindInPage)
}
val reportSiteIssuePlaceholder = WebExtensionPlaceholderMenuItem(
id = WebCompatReporterFeature.WEBCOMPAT_REPORTER_EXTENSION_ID
)
val saveToCollection = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_save_to_collection_2),
imageResource = R.drawable.ic_tab_collection,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.SaveToCollection)
}
val deleteDataOnQuit = BrowserMenuImageText(
label = context.getString(R.string.delete_browsing_data_on_quit_action),
imageResource = R.drawable.ic_exit,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.Quit)
}
val readerAppearance = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_read_appearance),
imageResource = R.drawable.ic_readermode_appearance,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.ReaderModeAppearance)
}
val openInApp = BrowserMenuHighlightableItem(
label = context.getString(R.string.browser_menu_open_app_link),
startImageResource = R.drawable.ic_open_in_app,
iconTintColorResource = primaryTextColor(),
highlight = BrowserMenuHighlight.LowPriority(
label = context.getString(R.string.browser_menu_open_app_link),
notificationTint = getColor(context, R.color.whats_new_notification_color)
),
isHighlighted = { !context.settings().openInAppOpened }
) {
onItemTapped.invoke(ToolbarMenu.Item.OpenInApp)
}
val historyItem = BrowserMenuImageText(
context.getString(R.string.library_history),
R.drawable.ic_history,
primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.History)
}
val bookmarksItem = BrowserMenuImageText(
context.getString(R.string.library_bookmarks),
R.drawable.ic_bookmark_filled,
primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.Bookmarks)
}
val downloadsItem = BrowserMenuImageText(
context.getString(R.string.library_downloads),
R.drawable.ic_download,
primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.Downloads)
}
// Predicates that are called once, during screen init
val shouldShowSaveToCollection = (context.asActivity() as? HomeActivity)
?.browsingModeManager?.mode == BrowsingMode.Normal
@ -216,151 +363,149 @@ class DefaultToolbarMenu(
}
}
private val settings = BrowserMenuHighlightableItem(
label = context.getString(R.string.browser_menu_settings),
startImageResource = R.drawable.ic_settings,
iconTintColorResource = if (hasAccountProblem)
ThemeManager.resolveAttribute(R.attr.syncDisconnected, context) else
primaryTextColor(),
textColorResource = if (hasAccountProblem)
ThemeManager.resolveAttribute(R.attr.primaryText, context) else
primaryTextColor(),
highlight = BrowserMenuHighlight.HighPriority(
endImageResource = R.drawable.ic_sync_disconnected,
backgroundTint = context.getColorFromAttr(R.attr.syncDisconnectedBackground),
canPropagate = false
),
isHighlighted = { hasAccountProblem }
) {
onItemTapped.invoke(ToolbarMenu.Item.Settings)
}
private val newCoreMenuItems by lazy {
val newTabItem = BrowserMenuImageText(
context.getString(R.string.library_new_tab),
R.drawable.ic_bookmark_filled,
disabledTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.NewTab)
}
private val desktopMode = BrowserMenuImageSwitch(
imageResource = R.drawable.ic_desktop,
label = context.getString(R.string.browser_menu_desktop_site),
initialState = {
selectedSession?.content?.desktopMode ?: false
val bookmarksItem = BrowserMenuImageText(
context.getString(R.string.library_bookmarks),
R.drawable.ic_bookmark_filled,
disabledTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.Bookmarks)
}
) { checked ->
onItemTapped.invoke(ToolbarMenu.Item.RequestDesktop(checked))
}
private val addToTopSites = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_add_to_top_sites),
imageResource = R.drawable.ic_top_sites,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.AddToTopSites)
}
val historyItem = BrowserMenuImageText(
context.getString(R.string.library_history),
R.drawable.ic_history,
disabledTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.History)
}
private val addToHomescreen = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_add_to_homescreen),
imageResource = R.drawable.ic_add_to_homescreen,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.AddToHomeScreen)
}
val downloadsItem = BrowserMenuImageText(
context.getString(R.string.library_downloads),
R.drawable.ic_download,
disabledTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.Downloads)
}
private val syncedTabs = BrowserMenuImageText(
label = context.getString(R.string.synced_tabs),
imageResource = R.drawable.ic_synced_tabs,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.SyncedTabs)
}
val extensionsItem = BrowserMenuImageText(
context.getString(R.string.browser_menu_extensions),
R.drawable.ic_addons_extensions,
disabledTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.AddonsManager)
}
private val installToHomescreen = BrowserMenuHighlightableItem(
label = context.getString(R.string.browser_menu_install_on_homescreen),
startImageResource = R.drawable.ic_add_to_homescreen,
iconTintColorResource = primaryTextColor(),
highlight = BrowserMenuHighlight.LowPriority(
label = context.getString(R.string.browser_menu_install_on_homescreen),
notificationTint = getColor(context, R.color.whats_new_notification_color)
),
isHighlighted = {
!context.settings().installPwaOpened
val syncedTabsItem = BrowserMenuImageText(
context.getString(R.string.library_synced_tabs),
R.drawable.ic_synced_tabs,
disabledTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.SyncedTabs)
}
) {
onItemTapped.invoke(ToolbarMenu.Item.InstallToHomeScreen)
}
private val findInPage = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_find_in_page),
imageResource = R.drawable.mozac_ic_search,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.FindInPage)
}
val findInPageItem = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_find_in_page),
imageResource = R.drawable.mozac_ic_search,
iconTintColorResource = disabledTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.FindInPage)
}
private val reportSiteIssuePlaceholder = WebExtensionPlaceholderMenuItem(
id = WebCompatReporterFeature.WEBCOMPAT_REPORTER_EXTENSION_ID
)
val desktopSiteItem = BrowserMenuImageSwitch(
imageResource = R.drawable.ic_desktop,
label = context.getString(R.string.browser_menu_desktop_site),
initialState = {
selectedSession?.content?.desktopMode ?: false
}
) { checked ->
onItemTapped.invoke(ToolbarMenu.Item.RequestDesktop(checked))
}
private val saveToCollection = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_save_to_collection_2),
imageResource = R.drawable.ic_tab_collection,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.SaveToCollection)
}
val addToHomeScreenItem = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_add_to_homescreen),
imageResource = R.drawable.ic_add_to_homescreen,
iconTintColorResource = disabledTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.AddToHomeScreen)
}
private val deleteDataOnQuit = BrowserMenuImageText(
label = context.getString(R.string.delete_browsing_data_on_quit_action),
imageResource = R.drawable.ic_exit,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.Quit)
}
val addToTopSitesItem = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_add_to_top_sites),
imageResource = R.drawable.ic_top_sites,
iconTintColorResource = disabledTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.AddToTopSites)
}
private val readerAppearance = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_read_appearance),
imageResource = R.drawable.ic_readermode_appearance,
iconTintColorResource = primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.ReaderModeAppearance)
}
val saveToCollectionItem = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_save_to_collection_2),
imageResource = R.drawable.ic_tab_collection,
iconTintColorResource = disabledTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.SaveToCollection)
}
private val openInApp = BrowserMenuHighlightableItem(
label = context.getString(R.string.browser_menu_open_app_link),
startImageResource = R.drawable.ic_open_in_app,
iconTintColorResource = primaryTextColor(),
highlight = BrowserMenuHighlight.LowPriority(
label = context.getString(R.string.browser_menu_open_app_link),
notificationTint = getColor(context, R.color.whats_new_notification_color)
),
isHighlighted = { !context.settings().openInAppOpened }
) {
onItemTapped.invoke(ToolbarMenu.Item.OpenInApp)
}
val settingsItem = BrowserMenuHighlightableItem(
label = context.getString(R.string.browser_menu_settings),
startImageResource = R.drawable.ic_settings,
iconTintColorResource = disabledTextColor(),
textColorResource = if (hasAccountProblem)
ThemeManager.resolveAttribute(R.attr.primaryText, context) else
primaryTextColor(),
highlight = BrowserMenuHighlight.HighPriority(
endImageResource = R.drawable.ic_sync_disconnected,
backgroundTint = context.getColorFromAttr(R.attr.syncDisconnectedBackground),
canPropagate = false
),
isHighlighted = { hasAccountProblem }
) {
onItemTapped.invoke(ToolbarMenu.Item.Settings)
}
val historyItem = BrowserMenuImageText(
context.getString(R.string.library_history),
R.drawable.ic_history,
primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.History)
}
val syncedTabsInTabsTray = context.components.settings
.syncedTabsInTabsTray
val bookmarksItem = BrowserMenuImageText(
context.getString(R.string.library_bookmarks),
R.drawable.ic_bookmark_filled,
primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.Bookmarks)
}
val menuItems = listOfNotNull(
newTabItem,
BrowserMenuDivider(),
bookmarksItem,
historyItem,
downloadsItem,
extensionsItem,
if (syncedTabsInTabsTray) null else syncedTabsItem,
BrowserMenuDivider(),
findInPageItem,
desktopSiteItem,
BrowserMenuDivider(),
addToHomeScreenItem.apply { visible = ::canAddToHomescreen },
addToTopSitesItem,
saveToCollectionItem,
BrowserMenuDivider(),
settingsItem,
BrowserMenuDivider(),
menuToolbar
)
val downloadsItem = BrowserMenuImageText(
context.getString(R.string.library_downloads),
R.drawable.ic_download,
primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.Downloads)
menuItems
}
@ColorRes
@VisibleForTesting
internal fun primaryTextColor() = ThemeManager.resolveAttribute(R.attr.primaryText, context)
@ColorRes
@VisibleForTesting
internal fun disabledTextColor() = R.color.toolbar_menu_transparent
@VisibleForTesting
internal fun registerForIsBookmarkedUpdates() {
store.flowScoped(lifecycleOwner) { flow ->

@ -31,6 +31,7 @@ interface ToolbarMenu {
object Bookmarks : Item()
object History : Item()
object Downloads : Item()
object NewTab : Item()
}
val menuBuilder: BrowserMenuBuilder

@ -422,4 +422,7 @@
<!-- App Spinners colors -->
<color name="spinner_selected_item">#1415141A</color>
<!-- Toolbar menu icon colors -->
<color name="toolbar_menu_transparent">@android:color/transparent</color>
</resources>

@ -128,6 +128,8 @@
<string name="browser_menu_edit_bookmark">Edit bookmark</string>
<!-- Browser menu button that opens the addon manager -->
<string name="browser_menu_add_ons">Add-ons</string>
<!-- Browser menu button that opens the addon extensions manager -->
<string name="browser_menu_extensions">Extensions</string>
<!-- Text displayed when there are no add-ons to be shown -->
<string name="no_add_ons">No add-ons here</string>
<!-- Browser menu button that sends a user to help articles -->
@ -517,6 +519,10 @@
<string name="library_desktop_bookmarks_unfiled">Other Bookmarks</string>
<!-- Option in Library to open History page -->
<string name="library_history">History</string>
<!-- Option in Library to open a new tab -->
<string name="library_new_tab">New tab</string>
<!-- Option in Library to find text in page -->
<string name="library_find_in_page">Find in page</string>
<!-- Option in Library to open Synced Tabs page -->
<string name="library_synced_tabs">Synced tabs</string>
<!-- Option in Library to open Reading List -->

@ -45,6 +45,7 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R
@ -64,6 +65,7 @@ import org.mozilla.fenix.utils.Settings
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(FenixRobolectricTestRunner::class)
@Suppress("ForbiddenComment")
class DefaultBrowserToolbarMenuControllerTest {
@get:Rule
@ -124,8 +126,121 @@ class DefaultBrowserToolbarMenuControllerTest {
unmockkObject(FenixSnackbar.Companion)
}
// TODO: These can be removed for https://github.com/mozilla-mobile/fenix/issues/17870
// todo === Start ===
@Test
fun handleToolbarBackPress() = runBlockingTest {
fun handleToolbarBookmarkPressWithReaderModeInactive() = runBlockingTest {
if (!FeatureFlags.toolbarMenuFeature) {
val item = ToolbarMenu.Item.Bookmark
val title = "Mozilla"
val readerUrl = "moz-extension://1234"
val readerTab = createTab(
url = readerUrl,
readerState = ReaderState(active = false, activeUrl = "https://1234.org"),
title = title
)
browserStore =
BrowserStore(BrowserState(tabs = listOf(readerTab), selectedTabId = readerTab.id))
every { currentSession.id } returns readerTab.id
every { currentSession.title } returns title
every { currentSession.url } returns "https://mozilla.org"
val controller = createController(scope = this)
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.BOOKMARK)) }
verify { bookmarkTapped("https://mozilla.org", title) }
}
}
@Test
fun `IF reader mode is active WHEN bookmark menu item is pressed THEN menu item is handled`() = runBlockingTest {
if (!FeatureFlags.toolbarMenuFeature) {
val item = ToolbarMenu.Item.Bookmark
val title = "Mozilla"
val readerUrl = "moz-extension://1234"
val readerTab = createTab(
url = readerUrl,
readerState = ReaderState(active = true, activeUrl = "https://mozilla.org"),
title = title
)
browserStore =
BrowserStore(BrowserState(tabs = listOf(readerTab), selectedTabId = readerTab.id))
every { currentSession.id } returns readerTab.id
every { currentSession.title } returns title
every { currentSession.url } returns readerUrl
val controller = createController(scope = this)
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.BOOKMARK)) }
verify { bookmarkTapped("https://mozilla.org", title) }
}
}
@Test
fun `WHEN open in Fenix menu item is pressed THEN menu item is handled correctly`() = runBlockingTest {
if (!FeatureFlags.toolbarMenuFeature) {
val controller = createController(scope = this, customTabSession = currentSession)
val item = ToolbarMenu.Item.OpenInFenix
every { currentSession.customTabConfig } returns mockk()
every { activity.startActivity(any()) } just Runs
controller.handleToolbarItemInteraction(item)
verify { sessionFeature.release() }
verify { currentSession.customTabConfig = null }
verify { sessionManager.select(currentSession) }
verify { activity.startActivity(openInFenixIntent) }
verify { activity.finishAndRemoveTask() }
}
}
@Test
fun `WHEN quit menu item is pressed THEN menu item is handled correctly`() = runBlockingTest {
if (!FeatureFlags.toolbarMenuFeature) {
val item = ToolbarMenu.Item.Quit
val testScope = this
val controller = createController(scope = testScope)
controller.handleToolbarItemInteraction(item)
verify { deleteAndQuit(activity, testScope, null) }
}
}
@Test
fun handleToolbarOpenInAppPress() = runBlockingTest {
if (!FeatureFlags.toolbarMenuFeature) {
val item = ToolbarMenu.Item.OpenInApp
val controller = createController(scope = this)
controller.handleToolbarItemInteraction(item)
verify { settings.openInAppOpened = true }
}
}
@Test
fun `WHEN reader mode menu item is pressed THEN handle appearance change`() = runBlockingTest {
val item = ToolbarMenu.Item.ReaderModeAppearance
val controller = createController(scope = this)
controller.handleToolbarItemInteraction(item)
verify { readerModeController.showControls() }
verify { metrics.track(Event.ReaderModeAppearanceOpened) }
}
// todo === End ===
@Test
fun `WHEN backwards nav menu item is pressed THEN the session navigates back with active session`() = runBlockingTest {
val item = ToolbarMenu.Item.Back(false)
val controller = createController(scope = this)
@ -136,7 +251,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarBackLongPress() = runBlockingTest {
fun `WHEN backwards nav menu item is long pressed THEN the session navigates back with no active session`() = runBlockingTest {
val item = ToolbarMenu.Item.Back(true)
val controller = createController(scope = this)
@ -149,7 +264,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarForwardPress() = runBlockingTest {
fun `WHEN forward nav menu item is pressed THEN the session navigates forward to active session`() = runBlockingTest {
val item = ToolbarMenu.Item.Forward(false)
val controller = createController(scope = this)
@ -160,7 +275,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarForwardLongPress() = runBlockingTest {
fun `WHEN forward nav menu item is long pressed THEN the browser navigates forward with no active session`() = runBlockingTest {
val item = ToolbarMenu.Item.Forward(true)
val controller = createController(scope = this)
@ -173,7 +288,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarReloadPress() = runBlockingTest {
fun `WHEN reload nav menu item is pressed THEN the session reloads from cache`() = runBlockingTest {
val item = ToolbarMenu.Item.Reload(false)
val controller = createController(scope = this)
@ -184,7 +299,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarReloadLongPress() = runBlockingTest {
fun `WHEN reload nav menu item is long pressed THEN the session reloads with no cache`() = runBlockingTest {
val item = ToolbarMenu.Item.Reload(true)
val controller = createController(scope = this)
@ -200,7 +315,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarStopPress() = runBlockingTest {
fun `WHEN stop nav menu item is pressed THEN the session stops loading`() = runBlockingTest {
val item = ToolbarMenu.Item.Stop
val controller = createController(scope = this)
@ -211,7 +326,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarSettingsPress() = runBlockingTest {
fun `WHEN settings menu item is pressed THEN menu item is handled`() = runBlockingTest {
val item = ToolbarMenu.Item.Settings
val controller = createController(scope = this)
@ -224,52 +339,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarBookmarkPressWithReaderModeInactive() = runBlockingTest {
val item = ToolbarMenu.Item.Bookmark
val title = "Mozilla"
val readerUrl = "moz-extension://1234"
val readerTab = createTab(
url = readerUrl,
readerState = ReaderState(active = false, activeUrl = "https://1234.org"),
title = title
)
browserStore =
BrowserStore(BrowserState(tabs = listOf(readerTab), selectedTabId = readerTab.id))
every { currentSession.id } returns readerTab.id
every { currentSession.title } returns title
every { currentSession.url } returns "https://mozilla.org"
val controller = createController(scope = this)
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.BOOKMARK)) }
verify { bookmarkTapped("https://mozilla.org", title) }
}
@Test
fun handleToolbarBookmarkPressWithReaderModeActive() = runBlockingTest {
val item = ToolbarMenu.Item.Bookmark
val title = "Mozilla"
val readerUrl = "moz-extension://1234"
val readerTab = createTab(
url = readerUrl,
readerState = ReaderState(active = true, activeUrl = "https://mozilla.org"),
title = title
)
browserStore = BrowserStore(BrowserState(tabs = listOf(readerTab), selectedTabId = readerTab.id))
every { currentSession.id } returns readerTab.id
every { currentSession.title } returns title
every { currentSession.url } returns readerUrl
val controller = createController(scope = this)
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.BOOKMARK)) }
verify { bookmarkTapped("https://mozilla.org", title) }
}
@Test
fun handleToolbarBookmarksPress() = runBlockingTest {
fun `WHEN bookmark menu item is pressed THEN navigate to bookmarks page`() = runBlockingTest {
val item = ToolbarMenu.Item.Bookmarks
val controller = createController(scope = this)
@ -282,7 +352,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarHistoryPress() = runBlockingTest {
fun `WHEN history menu item is pressed THEN navigate to history page`() = runBlockingTest {
val item = ToolbarMenu.Item.History
val controller = createController(scope = this)
@ -295,7 +365,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarRequestDesktopOnPress() = runBlockingTest {
fun `WHEN request desktop menu item is toggled On THEN desktop site is requested for the session`() = runBlockingTest {
val requestDesktopSiteUseCase: SessionUseCases.RequestDesktopSiteUseCase =
mockk(relaxed = true)
val item = ToolbarMenu.Item.RequestDesktop(true)
@ -315,7 +385,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarRequestDesktopOffPress() = runBlockingTest {
fun `WHEN request desktop menu item is toggled Off THEN mobile site is requested for the session`() = runBlockingTest {
val requestDesktopSiteUseCase: SessionUseCases.RequestDesktopSiteUseCase =
mockk(relaxed = true)
val item = ToolbarMenu.Item.RequestDesktop(false)
@ -335,7 +405,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarAddToTopSitesPressed() = runBlockingTest {
fun `WHEN Add To Top Sites menu item is pressed THEN add site AND show snackbar`() = runBlockingTest {
val item = ToolbarMenu.Item.AddToTopSites
val addPinnedSiteUseCase: TopSitesUseCases.AddPinnedSiteUseCase = mockk(relaxed = true)
@ -353,7 +423,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarAddonsManagerPress() = runBlockingTest {
fun `WHEN addon extensions menu item is pressed THEN navigate to addons manager`() = runBlockingTest {
val item = ToolbarMenu.Item.AddonsManager
val controller = createController(scope = this)
@ -363,7 +433,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarAddToHomeScreenPress() = runBlockingTest {
fun `WHEN Add To Home Screen menu item is pressed THEN add site`() = runBlockingTest {
val item = ToolbarMenu.Item.AddToHomeScreen
val controller = createController(scope = this)
@ -373,7 +443,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarSharePressWithReaderModeInactive() = runBlockingTest {
fun `IF reader mode is inactive WHEN share menu item is pressed THEN navigate to share screen`() = runBlockingTest {
val item = ToolbarMenu.Item.Share
val title = "Mozilla"
val readerUrl = "moz-extension://1234"
@ -404,7 +474,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarSharePressWithReaderModeActive() = runBlockingTest {
fun `IF reader mode is active WHEN share menu item is pressed THEN navigate to share screen`() = runBlockingTest {
val item = ToolbarMenu.Item.Share
val title = "Mozilla"
val readerUrl = "moz-extension://1234"
@ -435,7 +505,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarFindInPagePress() = runBlockingTest {
fun `WHEN Find In Page menu item is pressed THEN launch finder`() = runBlockingTest {
val item = ToolbarMenu.Item.FindInPage
val controller = createController(scope = this)
@ -446,7 +516,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarSaveToCollectionPressWhenAtLeastOneCollectionExists() = runBlockingTest {
fun `IF one or more collection exists WHEN Save To Collection menu item is pressed THEN navigate to save collection page`() = runBlockingTest {
val item = ToolbarMenu.Item.SaveToCollection
val cachedTabCollections: List<TabCollection> = mockk(relaxed = true)
every { tabCollectionStorage.cachedTabCollections } returns cachedTabCollections
@ -474,7 +544,7 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarSaveToCollectionPressWhenNoCollectionsExists() = runBlockingTest {
fun `IF no collection exists WHEN Save To Collection menu item is pressed THEN navigate to create collection page`() = runBlockingTest {
val item = ToolbarMenu.Item.SaveToCollection
val cachedTabCollectionsEmpty: List<TabCollection> = emptyList()
every { tabCollectionStorage.cachedTabCollections } returns cachedTabCollectionsEmpty
@ -499,56 +569,22 @@ class DefaultBrowserToolbarMenuControllerTest {
}
@Test
fun handleToolbarOpenInFenixPress() = runBlockingTest {
val controller = createController(scope = this, customTabSession = currentSession)
val item = ToolbarMenu.Item.OpenInFenix
every { currentSession.customTabConfig } returns mockk()
every { activity.startActivity(any()) } just Runs
controller.handleToolbarItemInteraction(item)
verify { sessionFeature.release() }
verify { currentSession.customTabConfig = null }
verify { sessionManager.select(currentSession) }
verify { activity.startActivity(openInFenixIntent) }
verify { activity.finishAndRemoveTask() }
}
@Test
fun handleToolbarQuitPress() = runBlockingTest {
val item = ToolbarMenu.Item.Quit
val testScope = this
val controller = createController(scope = testScope)
controller.handleToolbarItemInteraction(item)
verify { deleteAndQuit(activity, testScope, null) }
}
@Test
fun handleToolbarReaderModeAppearancePress() = runBlockingTest {
val item = ToolbarMenu.Item.ReaderModeAppearance
fun `WHEN New Tab menu item is pressed THEN navigate to a new tab home`() = runBlockingTest {
val item = ToolbarMenu.Item.NewTab
val controller = createController(scope = this)
controller.handleToolbarItemInteraction(item)
verify { readerModeController.showControls() }
verify { metrics.track(Event.ReaderModeAppearanceOpened) }
}
@Test
fun handleToolbarOpenInAppPress() = runBlockingTest {
val item = ToolbarMenu.Item.OpenInApp
val controller = createController(scope = this)
controller.handleToolbarItemInteraction(item)
verify { settings.openInAppOpened = true }
verify {
navController.navigate(
directionsEq(
NavGraphDirections.actionGlobalHome(
focusOnAddressBar = true
)
)
)
}
}
private fun createController(

Loading…
Cancel
Save