Bug 1845039 - Create new UI Tests for Compose Top Sites

Since the old UI tests don't work for the new Compose Top Sites
elements, new tests have been created.
fenix/119.0
DreVla 10 months ago committed by mergify[bot]
parent 079347af06
commit db09db8d2e

@ -82,6 +82,11 @@ interface FeatureSettingsHelper {
*/
var tabsTrayRewriteEnabled: Boolean
/**
* Enable or disable the Top Sites to Compose rewrite.
*/
var composeTopSitesEnabled: Boolean
fun applyFlagUpdates()
fun resetAllFeatureFlags()

@ -37,6 +37,7 @@ class FeatureSettingsHelperDelegate() : FeatureSettingsHelper {
isOpenInAppBannerEnabled = settings.shouldShowOpenInAppBanner,
etpPolicy = getETPPolicy(settings),
tabsTrayRewriteEnabled = settings.enableTabsTrayToCompose,
composeTopSitesEnabled = settings.enableComposeTopSites,
)
/**
@ -66,6 +67,7 @@ class FeatureSettingsHelperDelegate() : FeatureSettingsHelper {
override var isOpenInAppBannerEnabled: Boolean by updatedFeatureFlags::isOpenInAppBannerEnabled
override var etpPolicy: ETPPolicy by updatedFeatureFlags::etpPolicy
override var tabsTrayRewriteEnabled: Boolean by updatedFeatureFlags::tabsTrayRewriteEnabled
override var composeTopSitesEnabled: Boolean by updatedFeatureFlags::composeTopSitesEnabled
override fun applyFlagUpdates() {
applyFeatureFlags(updatedFeatureFlags)
@ -91,6 +93,7 @@ class FeatureSettingsHelperDelegate() : FeatureSettingsHelper {
settings.userOptOutOfReEngageCookieBannerDialog = !featureFlags.isCookieBannerReductionDialogEnabled
settings.shouldShowOpenInAppBanner = featureFlags.isOpenInAppBannerEnabled
settings.enableTabsTrayToCompose = featureFlags.tabsTrayRewriteEnabled
settings.enableComposeTopSites = featureFlags.composeTopSitesEnabled
setETPPolicy(featureFlags.etpPolicy)
}
}
@ -110,6 +113,7 @@ private data class FeatureFlags(
var isOpenInAppBannerEnabled: Boolean,
var etpPolicy: ETPPolicy,
var tabsTrayRewriteEnabled: Boolean,
var composeTopSitesEnabled: Boolean,
)
internal fun getETPPolicy(settings: Settings): ETPPolicy {

@ -56,6 +56,7 @@ class HomeActivityTestRule(
isOpenInAppBannerEnabled: Boolean = settings.shouldShowOpenInAppBanner,
etpPolicy: ETPPolicy = getETPPolicy(settings),
tabsTrayRewriteEnabled: Boolean = false,
composeTopSitesEnabled: Boolean = false,
) : this(initialTouchMode, launchActivity, skipOnboarding) {
this.isHomeOnboardingDialogEnabled = isHomeOnboardingDialogEnabled
this.isPocketEnabled = isPocketEnabled
@ -70,6 +71,7 @@ class HomeActivityTestRule(
this.isOpenInAppBannerEnabled = isOpenInAppBannerEnabled
this.etpPolicy = etpPolicy
this.tabsTrayRewriteEnabled = tabsTrayRewriteEnabled
this.composeTopSitesEnabled = composeTopSitesEnabled
}
/**
@ -114,6 +116,7 @@ class HomeActivityTestRule(
launchActivity: Boolean = true,
skipOnboarding: Boolean = false,
tabsTrayRewriteEnabled: Boolean = false,
composeTopSitesEnabled: Boolean = false,
) = HomeActivityTestRule(
initialTouchMode = initialTouchMode,
launchActivity = launchActivity,
@ -125,6 +128,7 @@ class HomeActivityTestRule(
isWallpaperOnboardingEnabled = false,
isCookieBannerReductionDialogEnabled = false,
isOpenInAppBannerEnabled = false,
composeTopSitesEnabled = composeTopSitesEnabled,
)
}
}
@ -164,6 +168,7 @@ class HomeActivityIntentTestRule internal constructor(
isOpenInAppBannerEnabled: Boolean = settings.shouldShowOpenInAppBanner,
etpPolicy: ETPPolicy = getETPPolicy(settings),
tabsTrayRewriteEnabled: Boolean = false,
composeTopSitesEnabled: Boolean = false,
) : this(initialTouchMode, launchActivity, skipOnboarding) {
this.isHomeOnboardingDialogEnabled = isHomeOnboardingDialogEnabled
this.isPocketEnabled = isPocketEnabled
@ -178,6 +183,7 @@ class HomeActivityIntentTestRule internal constructor(
this.isOpenInAppBannerEnabled = isOpenInAppBannerEnabled
this.etpPolicy = etpPolicy
this.tabsTrayRewriteEnabled = tabsTrayRewriteEnabled
this.composeTopSitesEnabled = composeTopSitesEnabled
}
private val longTapUserPreference = getLongPressTimeout()
@ -259,6 +265,7 @@ class HomeActivityIntentTestRule internal constructor(
launchActivity: Boolean = true,
skipOnboarding: Boolean = false,
tabsTrayRewriteEnabled: Boolean = false,
composeTopSitesEnabled: Boolean = false,
) = HomeActivityIntentTestRule(
initialTouchMode = initialTouchMode,
launchActivity = launchActivity,
@ -270,6 +277,7 @@ class HomeActivityIntentTestRule internal constructor(
isWallpaperOnboardingEnabled = false,
isCookieBannerReductionDialogEnabled = false,
isOpenInAppBannerEnabled = false,
composeTopSitesEnabled = composeTopSitesEnabled,
)
}
}

@ -0,0 +1,260 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.ui
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.R
import org.mozilla.fenix.customannotations.SmokeTest
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
import org.mozilla.fenix.helpers.HomeActivityTestRule
import org.mozilla.fenix.helpers.RetryTestRule
import org.mozilla.fenix.helpers.TestAssetHelper.getGenericAsset
import org.mozilla.fenix.helpers.TestHelper.clickSnackbarButton
import org.mozilla.fenix.helpers.TestHelper.generateRandomString
import org.mozilla.fenix.helpers.TestHelper.getStringResource
import org.mozilla.fenix.helpers.TestHelper.waitUntilSnackbarGone
import org.mozilla.fenix.ui.robots.browserScreen
import org.mozilla.fenix.ui.robots.homeScreenWithComposeTopSites
import org.mozilla.fenix.ui.robots.navigationToolbar
/**
* Tests Top Sites functionality
*
* - Verifies 'Add to Firefox Home' UI functionality
* - Verifies 'Top Sites' context menu UI functionality
* - Verifies 'Top Site' usage UI functionality
* - Verifies existence of default top sites available on the home-screen
*/
class ComposeTopSitesTest {
private lateinit var mDevice: UiDevice
private lateinit var mockWebServer: MockWebServer
@get:Rule
val composeTestRule =
AndroidComposeTestRule(
HomeActivityTestRule.withDefaultSettingsOverrides(
composeTopSitesEnabled = true,
),
) { it.activity }
@get:Rule
val retryTestRule = RetryTestRule(3)
@Before
fun setUp() {
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
mockWebServer = MockWebServer().apply {
dispatcher = AndroidAssetDispatcher()
start()
}
}
@After
fun tearDown() {
mockWebServer.shutdown()
}
@SmokeTest
@Test
fun verifyAddToFirefoxHome() {
val defaultWebPage = getGenericAsset(mockWebServer, 1)
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
}.openThreeDotMenu {
expandMenu()
verifyAddToShortcutsButton(true)
}.addToFirefoxHome {
verifySnackBarText(getStringResource(R.string.snackbar_added_to_shortcuts))
}.goToHomescreenWithComposeTopSites(composeTestRule) {
verifyExistingTopSitesList()
verifyExistingTopSiteItem(defaultWebPage.title)
}
}
@Test
fun verifyOpenTopSiteNormalTab() {
val defaultWebPage = getGenericAsset(mockWebServer, 1)
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
}.openThreeDotMenu {
expandMenu()
verifyAddToShortcutsButton(true)
}.addToFirefoxHome {
verifySnackBarText(getStringResource(R.string.snackbar_added_to_shortcuts))
}.goToHomescreenWithComposeTopSites(composeTestRule) {
verifyExistingTopSitesList()
verifyExistingTopSiteItem(defaultWebPage.title)
}.openTopSiteTabWithTitle(title = defaultWebPage.title) {
verifyUrl(defaultWebPage.url.toString().replace("http://", ""))
}.goToHomescreenWithComposeTopSites(composeTestRule) {
verifyExistingTopSitesList()
verifyExistingTopSiteItem(defaultWebPage.title)
}.openContextMenuOnTopSitesWithTitle(defaultWebPage.title) {
verifyTopSiteContextMenuItems()
}
// Dismiss context menu popup
mDevice.pressBack()
}
@Test
fun verifyOpenTopSitePrivateTab() {
val defaultWebPage = getGenericAsset(mockWebServer, 1)
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
}.openThreeDotMenu {
expandMenu()
verifyAddToShortcutsButton(true)
}.addToFirefoxHome {
verifySnackBarText(getStringResource(R.string.snackbar_added_to_shortcuts))
}.goToHomescreenWithComposeTopSites(composeTestRule) {
verifyExistingTopSitesList()
verifyExistingTopSiteItem(defaultWebPage.title)
}.openContextMenuOnTopSitesWithTitle(defaultWebPage.title) {
verifyTopSiteContextMenuItems()
}.openTopSiteInPrivate() {
verifyCurrentPrivateSession(composeTestRule.activity.applicationContext)
}
}
@Test
fun verifyRenameTopSite() {
val defaultWebPage = getGenericAsset(mockWebServer, 1)
val newPageTitle = generateRandomString(5)
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
waitForPageToLoad()
}.openThreeDotMenu {
expandMenu()
verifyAddToShortcutsButton(true)
}.addToFirefoxHome {
verifySnackBarText(getStringResource(R.string.snackbar_added_to_shortcuts))
}.goToHomescreenWithComposeTopSites(composeTestRule) {
verifyExistingTopSitesList()
verifyExistingTopSiteItem(defaultWebPage.title)
}.openContextMenuOnTopSitesWithTitle(defaultWebPage.title) {
verifyTopSiteContextMenuItems()
}.renameTopSite(newPageTitle) {
verifyExistingTopSitesList()
verifyExistingTopSiteItem(newPageTitle)
}
}
@Test
fun verifyRemoveTopSite() {
val defaultWebPage = getGenericAsset(mockWebServer, 1)
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
}.openThreeDotMenu {
expandMenu()
verifyAddToShortcutsButton(true)
}.addToFirefoxHome {
verifySnackBarText(getStringResource(R.string.snackbar_added_to_shortcuts))
}.goToHomescreenWithComposeTopSites(composeTestRule) {
verifyExistingTopSitesList()
verifyExistingTopSiteItem(defaultWebPage.title)
}.openContextMenuOnTopSitesWithTitle(defaultWebPage.title) {
verifyTopSiteContextMenuItems()
}.removeTopSite {
verifyNotExistingTopSiteItem(defaultWebPage.title)
}
}
@Test
fun verifyUndoRemoveTopSite() {
val defaultWebPage = getGenericAsset(mockWebServer, 1)
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
}.openThreeDotMenu {
expandMenu()
verifyAddToShortcutsButton(true)
}.addToFirefoxHome {
verifySnackBarText(getStringResource(R.string.snackbar_added_to_shortcuts))
}.goToHomescreenWithComposeTopSites(composeTestRule) {
verifyExistingTopSitesList()
verifyExistingTopSiteItem(defaultWebPage.title)
}.openContextMenuOnTopSitesWithTitle(defaultWebPage.title) {
verifyTopSiteContextMenuItems()
}.removeTopSite {
clickSnackbarButton("UNDO")
verifyExistingTopSiteItem(defaultWebPage.title)
}
}
@Test
fun verifyRemoveTopSiteFromMainMenu() {
val defaultWebPage = getGenericAsset(mockWebServer, 1)
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
}.openThreeDotMenu {
expandMenu()
verifyAddToShortcutsButton(true)
}.addToFirefoxHome {
verifySnackBarText(getStringResource(R.string.snackbar_added_to_shortcuts))
}.goToHomescreenWithComposeTopSites(composeTestRule) {
verifyExistingTopSitesList()
verifyExistingTopSiteItem(defaultWebPage.title)
}.openTopSiteTabWithTitle(defaultWebPage.title) {
}.openThreeDotMenu {
verifyRemoveFromShortcutsButton()
}.clickRemoveFromShortcuts {
}.goToHomescreenWithComposeTopSites(composeTestRule) {
verifyNotExistingTopSiteItem(defaultWebPage.title)
}
}
// Expected for en-us defaults
@Test
fun verifyDefaultTopSitesList() {
homeScreenWithComposeTopSites(composeTestRule) {
verifyExistingTopSitesList()
val topSitesTitles = arrayListOf("Google", "Top Articles", "Wikipedia")
topSitesTitles.forEach { value ->
verifyExistingTopSiteItem(value)
}
}
}
@SmokeTest
@Test
fun addAndRemoveMostViewedTopSiteTest() {
val defaultWebPage = getGenericAsset(mockWebServer, 1)
for (i in 0..1) {
navigationToolbar {
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
waitForPageToLoad()
}
}
browserScreen {
}.goToHomescreenWithComposeTopSites(composeTestRule) {
verifyExistingTopSitesList()
verifyExistingTopSiteItem(defaultWebPage.title)
}.openContextMenuOnTopSitesWithTitle(defaultWebPage.title) {
}.deleteTopSiteFromHistory {
verifySnackBarText(getStringResource(R.string.snackbar_top_site_removed))
waitUntilSnackbarGone()
}.openThreeDotMenu {
}.openHistory {
verifyEmptyHistoryView()
}
}
}

@ -1057,6 +1057,21 @@ class BrowserRobot {
return HomeScreenRobot.Transition()
}
fun goToHomescreenWithComposeTopSites(composeTestRule: HomeActivityComposeTestRule, interact: ComposeTopSitesRobot.() -> Unit): ComposeTopSitesRobot.Transition {
clickPageObject(itemWithDescription("Home screen"))
mDevice.findObject(UiSelector().resourceId("$packageName:id/homeLayout"))
.waitForExists(waitingTime) ||
mDevice.findObject(
UiSelector().text(
getStringResource(R.string.onboarding_home_screen_jump_back_contextual_hint_2),
),
).waitForExists(waitingTime)
ComposeTopSitesRobot(composeTestRule).interact()
return ComposeTopSitesRobot.Transition(composeTestRule)
}
fun goBack(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
mDevice.pressBack()

@ -0,0 +1,171 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.ui.robots
import android.widget.EditText
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.filter
import androidx.compose.ui.test.hasAnyChild
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.longClick
import androidx.compose.ui.test.onAllNodesWithTag
import androidx.compose.ui.test.onFirst
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollTo
import androidx.compose.ui.test.performTouchInput
import androidx.test.espresso.Espresso
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.matcher.ViewMatchers
import org.hamcrest.CoreMatchers
import org.hamcrest.Matchers
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.HomeActivityComposeTestRule
import org.mozilla.fenix.helpers.MatcherHelper.itemContainingText
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.home.topsites.TopSitesTestTag
/**
* Implementation of Robot Pattern for the Compose Top Sites.
*/
class ComposeTopSitesRobot(private val composeTestRule: HomeActivityComposeTestRule) {
fun verifyExistingTopSitesList() =
composeTestRule.onNodeWithTag(TopSitesTestTag.topSites).assertExists()
@OptIn(ExperimentalTestApi::class)
fun verifyExistingTopSiteItem(vararg titles: String) {
titles.forEach { title ->
itemContainingText(title).waitForExists(waitingTime)
composeTestRule.waitUntilAtLeastOneExists(hasText(title), waitingTime)
composeTestRule.topSiteItem(title).assertExists()
}
}
fun verifyNotExistingTopSiteItem(vararg titles: String) {
titles.forEach { title ->
itemContainingText(title).waitForExists(waitingTime)
composeTestRule.topSiteItem(title).assertDoesNotExist()
}
}
fun verifyTopSiteContextMenuItems() {
verifyTopSiteContextMenuOpenInPrivateTabButton()
verifyTopSiteContextMenuRemoveButton()
verifyTopSiteContextMenuRenameButton()
}
fun verifyTopSiteContextMenuOpenInPrivateTabButton() {
composeTestRule.contextMenuItemOpenInPrivateTab().assertExists()
}
fun verifyTopSiteContextMenuRenameButton() {
composeTestRule.contextMenuItemRename().assertExists()
}
fun verifyTopSiteContextMenuRemoveButton() {
composeTestRule.contextMenuItemRemove().assertExists()
}
class Transition(private val composeTestRule: HomeActivityComposeTestRule) {
fun openTopSiteTabWithTitle(
title: String,
interact: BrowserRobot.() -> Unit,
): BrowserRobot.Transition {
composeTestRule.topSiteItem(title).performScrollTo().performClick()
BrowserRobot().interact()
return BrowserRobot.Transition()
}
fun openTopSiteInPrivate(
interact: BrowserRobot.() -> Unit,
): BrowserRobot.Transition {
composeTestRule.contextMenuItemOpenInPrivateTab().performClick()
composeTestRule.waitForIdle()
BrowserRobot().interact()
return BrowserRobot.Transition()
}
fun openContextMenuOnTopSitesWithTitle(
title: String,
interact: ComposeTopSitesRobot.() -> Unit,
): Transition {
composeTestRule.topSiteItem(title).performScrollTo().performTouchInput {
longClick()
}
ComposeTopSitesRobot(composeTestRule).interact()
return Transition(composeTestRule)
}
fun renameTopSite(
title: String,
interact: ComposeTopSitesRobot.() -> Unit,
): Transition {
composeTestRule.contextMenuItemRename().performClick()
Espresso.onView(
Matchers.allOf(
ViewMatchers.withId(R.id.top_site_title),
CoreMatchers.instanceOf(EditText::class.java),
),
)
.perform(ViewActions.replaceText(title))
Espresso.onView(ViewMatchers.withId(android.R.id.button1))
.perform((ViewActions.click()))
ComposeTopSitesRobot(composeTestRule).interact()
return Transition(composeTestRule)
}
@OptIn(ExperimentalTestApi::class)
fun removeTopSite(
interact: ComposeTopSitesRobot.() -> Unit,
): Transition {
composeTestRule.contextMenuItemRemove().performClick()
composeTestRule.waitUntilDoesNotExist(hasTestTag(TopSitesTestTag.remove), waitingTime)
ComposeTopSitesRobot(composeTestRule).interact()
return Transition(composeTestRule)
}
@OptIn(ExperimentalTestApi::class)
fun deleteTopSiteFromHistory(
interact: BrowserRobot.() -> Unit,
): BrowserRobot.Transition {
composeTestRule.contextMenuItemRemove().performClick()
composeTestRule.waitUntilDoesNotExist(hasTestTag(TopSitesTestTag.remove), waitingTime)
BrowserRobot().interact()
return BrowserRobot.Transition()
}
}
}
/**
* Obtains the top site with the provided [title].
*/
private fun ComposeTestRule.topSiteItem(title: String) =
onAllNodesWithTag(TopSitesTestTag.topSiteItemRoot).filter(hasAnyChild(hasText(title))).onFirst()
/**
* Obtains the option to open in private tab the top site
*/
private fun ComposeTestRule.contextMenuItemOpenInPrivateTab() =
onAllNodesWithTag(TopSitesTestTag.openInPrivateTab).onFirst()
/**
* Obtains the option to rename the top site
*/
private fun ComposeTestRule.contextMenuItemRename() = onAllNodesWithTag(TopSitesTestTag.rename).onFirst()
/**
* Obtains the option to remove the top site
*/
private fun ComposeTestRule.contextMenuItemRemove() = onAllNodesWithTag(TopSitesTestTag.remove).onFirst()

@ -781,6 +781,11 @@ fun homeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition
return HomeScreenRobot.Transition()
}
fun homeScreenWithComposeTopSites(composeTestRule: HomeActivityComposeTestRule, interact: ComposeTopSitesRobot.() -> Unit): ComposeTopSitesRobot.Transition {
ComposeTopSitesRobot(composeTestRule).interact()
return ComposeTopSitesRobot.Transition(composeTestRule)
}
private fun homeScreenList() =
UiScrollable(
UiSelector()

@ -55,7 +55,8 @@ object FeatureFlags {
/**
* Enables compose on the top sites.
*/
const val composeTopSites = false
// const val composeTopSites = false
const val composeTopSites = true
/**
* Enables new search settings UI with two extra fragments, for managing the default engine

@ -34,6 +34,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
@ -43,8 +44,11 @@ import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@ -87,9 +91,9 @@ private const val TOP_SITES_FAVICON_SIZE = 36
* @param onSponsorPrivacyClicked Invoked when the user clicks on the "Our sponsors & your privacy"
* menu item.
*/
@OptIn(ExperimentalFoundationApi::class)
@OptIn(ExperimentalFoundationApi::class, ExperimentalComposeUiApi::class)
@Composable
@Suppress("LongParameterList")
@Suppress("LongParameterList", "LongMethod")
fun TopSites(
topSites: List<TopSite>,
topSiteColors: TopSiteColors = TopSiteColors.colors(),
@ -101,12 +105,19 @@ fun TopSites(
onSettingsClicked: () -> Unit,
onSponsorPrivacyClicked: () -> Unit,
) {
val pageCount = ceil((topSites.size.toDouble() / TOP_SITES_PER_PAGE)).toInt()
Column(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.semantics {
testTagsAsResourceId = true
}
.testTag(TopSitesTestTag.topSites),
horizontalAlignment = Alignment.CenterHorizontally,
) {
val pagerState = rememberPagerState(
pageCount = { ceil((topSites.size.toDouble() / TOP_SITES_PER_PAGE)).toInt() },
pageCount = { pageCount },
)
Box(
@ -230,8 +241,8 @@ data class TopSiteColors(
* @param onTopSiteClick Invoked when the user clicks on a top site.
* @param onTopSiteLongClick Invoked when the user long clicks on a top site.
*/
@Suppress("LongParameterList")
@OptIn(ExperimentalFoundationApi::class)
@Suppress("LongParameterList", "LongMethod")
@OptIn(ExperimentalFoundationApi::class, ExperimentalComposeUiApi::class)
@Composable
private fun TopSiteItem(
topSite: TopSite,
@ -243,7 +254,13 @@ private fun TopSiteItem(
) {
var menuExpanded by remember { mutableStateOf(false) }
Box {
Box(
modifier = Modifier
.semantics {
testTagsAsResourceId = true
}
.testTag(TopSitesTestTag.topSiteItemRoot),
) {
Column(
modifier = Modifier
.combinedClickable(
@ -282,6 +299,11 @@ private fun TopSiteItem(
}
Text(
modifier = Modifier
.semantics {
testTagsAsResourceId = true
}
.testTag(TopSitesTestTag.topSiteTitle),
text = topSite.title ?: topSite.url,
color = topSiteColors.titleTextColor,
overflow = TextOverflow.Ellipsis,
@ -304,6 +326,8 @@ private fun TopSiteItem(
}
ContextualMenu(
modifier = Modifier
.testTag(TopSitesTestTag.topSiteContextualMenu),
menuItems = menuItems,
showMenu = menuExpanded,
onDismissRequest = { menuExpanded = false },
@ -428,6 +452,7 @@ private fun getMenuItems(
result.add(
MenuItem(
title = stringResource(id = R.string.bookmark_menu_open_in_private_tab_button),
testTag = TopSitesTestTag.openInPrivateTab,
onClick = { onOpenInPrivateTabClicked(topSite) },
),
)
@ -436,6 +461,7 @@ private fun getMenuItems(
result.add(
MenuItem(
title = stringResource(id = R.string.rename_top_site),
testTag = TopSitesTestTag.rename,
onClick = { onRenameTopSiteClicked(topSite) },
),
)
@ -451,6 +477,7 @@ private fun getMenuItems(
R.string.delete_from_history
},
),
testTag = TopSitesTestTag.remove,
onClick = { onRemoveTopSiteClicked(topSite) },
),
)
@ -460,6 +487,7 @@ private fun getMenuItems(
result.add(
MenuItem(
title = stringResource(id = R.string.delete_from_history),
testTag = TopSitesTestTag.remove,
onClick = { onRemoveTopSiteClicked(topSite) },
),
)

@ -0,0 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.home.topsites
internal object TopSitesTestTag {
const val topSites = "top_sites_list"
const val topSiteItemRoot = "$topSites.top_site_item"
const val topSiteTitle = "$topSiteItemRoot.top_site_title"
// Contextual/DropDown menu
const val topSiteContextualMenu = "$topSites.top_site_contextual_menu"
const val openInPrivateTab = "$topSiteContextualMenu.open_in_private_tab"
const val rename = "$topSiteContextualMenu.rename"
const val remove = "$topSiteContextualMenu.remove"
}
Loading…
Cancel
Save