Issue #26286: adds UI test for the Language menu

pull/543/head
sv-ohorvath 2 years ago committed by mergify[bot]
parent 67d8a2c749
commit 0a2d1c63f1

@ -2,6 +2,8 @@
* 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/. */
@file:Suppress("DEPRECATION")
package org.mozilla.fenix.helpers
import android.app.ActivityManager
@ -10,6 +12,7 @@ import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
@ -31,6 +34,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withParent
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.ActivityTestRule
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObject
@ -38,6 +42,8 @@ import androidx.test.uiautomator.UiObjectNotFoundException
import androidx.test.uiautomator.UiScrollable
import androidx.test.uiautomator.UiSelector
import androidx.test.uiautomator.Until
import java.util.Locale
import java.util.regex.Pattern
import junit.framework.AssertionFailedError
import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.support.ktx.android.content.appName
@ -46,6 +52,7 @@ import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.Matcher
import org.junit.Assert
import org.junit.Assert.assertTrue
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.customtabs.ExternalAppBrowserActivity
import org.mozilla.fenix.ext.components
@ -56,7 +63,7 @@ import org.mozilla.fenix.helpers.ext.waitNotNull
import org.mozilla.fenix.helpers.idlingresource.NetworkConnectionIdlingResource
import org.mozilla.fenix.ui.robots.BrowserRobot
import org.mozilla.fenix.utils.IntentUtils
import java.util.regex.Pattern
import org.mozilla.gecko.util.ThreadUtils
object TestHelper {
@ -329,4 +336,39 @@ object TestHelper {
.map { kotlin.random.Random.nextInt(0, charPool.size) }
.map(charPool::get)
.joinToString("")
/**
* Changes the default language of the entire device, not just the app.
* Runs the test in its testBlock.
* Cleans up and sets the default locale after it's are done.
*/
fun runWithSystemLocaleChanged(locale: Locale, testRule: ActivityTestRule<HomeActivity>, testBlock: () -> Unit) {
val defaultLocale = Locale.getDefault()
try {
setSystemLocale(locale)
testBlock()
ThreadUtils.runOnUiThread { testRule.activity.recreate() }
} catch (e: Exception) {
e.printStackTrace()
} finally {
setSystemLocale(defaultLocale)
}
}
/**
* Changes the default language of the entire device, not just the app.
*/
private fun setSystemLocale(locale: Locale) {
val activityManagerNative = Class.forName("android.app.ActivityManagerNative")
val am = activityManagerNative.getMethod("getDefault", *arrayOfNulls(0))
.invoke(activityManagerNative, *arrayOfNulls(0))
val config = InstrumentationRegistry.getInstrumentation().context.resources.configuration
config.javaClass.getDeclaredField("locale")[config] = locale
config.javaClass.getDeclaredField("userSetLocale").setBoolean(config, true)
am.javaClass.getMethod(
"updateConfiguration",
Configuration::class.java
).invoke(am, config)
}
}

@ -5,27 +5,40 @@
package org.mozilla.fenix.ui
import android.content.res.Configuration
import androidx.test.espresso.IdlingRegistry
import java.time.LocalDate
import java.util.Locale
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.FenixApplication
import org.mozilla.fenix.R
import org.mozilla.fenix.customannotations.SmokeTest
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
import org.mozilla.fenix.helpers.FeatureSettingsHelper
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
import org.mozilla.fenix.helpers.RecyclerViewIdlingResource
import org.mozilla.fenix.helpers.TestAssetHelper
import org.mozilla.fenix.helpers.TestAssetHelper.getLoremIpsumAsset
import org.mozilla.fenix.ui.SettingsBasicsTest.creditCard.MOCK_CREDIT_CARD_NUMBER
import org.mozilla.fenix.ui.SettingsBasicsTest.creditCard.MOCK_EXPIRATION_MONTH
import org.mozilla.fenix.ui.SettingsBasicsTest.creditCard.MOCK_EXPIRATION_YEAR
import org.mozilla.fenix.ui.SettingsBasicsTest.creditCard.MOCK_LAST_CARD_DIGITS
import org.mozilla.fenix.ui.SettingsBasicsTest.creditCard.MOCK_NAME_ON_CARD
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeLong
import org.mozilla.fenix.helpers.TestHelper.runWithSystemLocaleChanged
import org.mozilla.fenix.helpers.TestHelper.getStringResource
import org.mozilla.fenix.helpers.TestHelper.mDevice
import org.mozilla.fenix.ui.SettingsBasicsTest.CreditCard.MOCK_CREDIT_CARD_NUMBER
import org.mozilla.fenix.ui.SettingsBasicsTest.CreditCard.MOCK_EXPIRATION_MONTH
import org.mozilla.fenix.ui.SettingsBasicsTest.CreditCard.MOCK_EXPIRATION_YEAR
import org.mozilla.fenix.ui.SettingsBasicsTest.CreditCard.MOCK_LAST_CARD_DIGITS
import org.mozilla.fenix.ui.SettingsBasicsTest.CreditCard.MOCK_NAME_ON_CARD
import org.mozilla.fenix.ui.robots.checkTextSizeOnWebsite
import org.mozilla.fenix.ui.robots.homeScreen
import org.mozilla.fenix.ui.robots.navigationToolbar
import java.time.LocalDate
import org.mozilla.fenix.ui.util.FRENCH_LANGUAGE_HEADER
import org.mozilla.fenix.ui.util.FRENCH_SYSTEM_LOCALE_OPTION
import org.mozilla.fenix.ui.util.FR_SETTINGS
import org.mozilla.fenix.ui.util.ROMANIAN_LANGUAGE_HEADER
/**
* Tests for verifying the General section of the Settings menu
@ -35,8 +48,9 @@ class SettingsBasicsTest {
/* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping.
private lateinit var mockWebServer: MockWebServer
private val featureSettingsHelper = FeatureSettingsHelper()
private var localeListIdlingResource: RecyclerViewIdlingResource? = null
object creditCard {
object CreditCard {
const val MOCK_CREDIT_CARD_NUMBER = "5555555555554444"
const val MOCK_LAST_CARD_DIGITS = "4444"
const val MOCK_NAME_ON_CARD = "Mastercard"
@ -64,6 +78,10 @@ class SettingsBasicsTest {
// resetting modified features enabled setting to default
featureSettingsHelper.resetAllFeatureFlags()
if (localeListIdlingResource != null) {
IdlingRegistry.getInstance().unregister(localeListIdlingResource)
}
}
private fun getUiTheme(): Boolean {
@ -250,4 +268,68 @@ class SettingsBasicsTest {
verifyAddCreditCardsButton()
}
}
@SmokeTest
@Test
fun switchLanguageTest() {
val enLanguageHeaderText = getStringResource(R.string.preferences_language)
homeScreen {
}.openThreeDotMenu {
}.openSettings {
}.openLanguageSubMenu {
localeListIdlingResource =
RecyclerViewIdlingResource(
activityIntentTestRule.activity.findViewById(R.id.locale_list),
2
)
IdlingRegistry.getInstance().register(localeListIdlingResource)
selectLanguage("Romanian")
verifyLanguageHeaderIsTranslated(ROMANIAN_LANGUAGE_HEADER)
selectLanguage("Français")
verifyLanguageHeaderIsTranslated(FRENCH_LANGUAGE_HEADER)
selectLanguage(FRENCH_SYSTEM_LOCALE_OPTION)
verifyLanguageHeaderIsTranslated(enLanguageHeaderText)
IdlingRegistry.getInstance().unregister(localeListIdlingResource)
}
}
@Test
fun searchInLanguagesListTest() {
val systemLocaleDefault = getStringResource(R.string.default_locale_text)
homeScreen {
}.openThreeDotMenu {
}.openSettings {
}.openLanguageSubMenu {
verifyLanguageListIsDisplayed()
openSearchBar()
typeInSearchBar("French")
verifySearchResultsContains(systemLocaleDefault)
clearSearchBar()
typeInSearchBar("French")
selectLanguageSearchResult("Français")
verifyLanguageHeaderIsTranslated(FRENCH_LANGUAGE_HEADER)
// Add this step when https://github.com/mozilla-mobile/fenix/issues/26733 is fixed
// verifyLanguageListIsDisplayed()
}
}
@Ignore("Failing due to app translation bug, see: https://github.com/mozilla-mobile/fenix/issues/26729")
@Test
fun frenchSystemLocaleTest() {
val frenchLocale = Locale("fr", "FR")
runWithSystemLocaleChanged(frenchLocale, activityIntentTestRule) {
mDevice.waitForIdle(waitingTimeLong)
homeScreen {
}.openThreeDotMenu {
}.openSettings(localizedText = FR_SETTINGS) {
}.openLanguageSubMenu(localizedText = FRENCH_LANGUAGE_HEADER) {
verifyLanguageHeaderIsTranslated(FRENCH_LANGUAGE_HEADER)
verifySelectedLanguage(FRENCH_SYSTEM_LOCALE_OPTION)
}
}
}
}

@ -47,9 +47,6 @@ import org.mozilla.fenix.ui.robots.navigationToolbar
import org.mozilla.fenix.ui.robots.notificationShade
import org.mozilla.fenix.ui.robots.openEditURLView
import org.mozilla.fenix.ui.robots.searchScreen
import org.mozilla.fenix.ui.util.FRENCH_LANGUAGE_HEADER
import org.mozilla.fenix.ui.util.FRENCH_SYSTEM_LOCALE_OPTION
import org.mozilla.fenix.ui.util.ROMANIAN_LANGUAGE_HEADER
import org.mozilla.fenix.ui.util.STRING_ONBOARDING_TRACKING_PROTECTION_HEADER
/**
@ -68,7 +65,6 @@ class SmokeTest {
private var recentlyClosedTabsListIdlingResource: RecyclerViewIdlingResource? = null
private var readerViewNotification: ViewVisibilityIdlingResource? = null
private var bookmarksListIdlingResource: RecyclerViewIdlingResource? = null
private var localeListIdlingResource: RecyclerViewIdlingResource? = null
private val customMenuItem = "TestMenuItem"
private lateinit var browserStore: BrowserStore
private val featureSettingsHelper = FeatureSettingsHelper()
@ -129,10 +125,6 @@ class SmokeTest {
IdlingRegistry.getInstance().unregister(readerViewNotification)
}
if (localeListIdlingResource != null) {
IdlingRegistry.getInstance().unregister(localeListIdlingResource)
}
// resetting modified features enabled setting to default
featureSettingsHelper.resetAllFeatureFlags()
}
@ -953,28 +945,6 @@ class SmokeTest {
}
}
@Test
fun switchLanguageTest() {
homeScreen {
}.openThreeDotMenu {
}.openSettings {
}.openLanguageSubMenu {
localeListIdlingResource =
RecyclerViewIdlingResource(
activityTestRule.activity.findViewById(R.id.locale_list),
2
)
IdlingRegistry.getInstance().register(localeListIdlingResource)
selectLanguage("Romanian")
verifyLanguageHeaderIsTranslated(ROMANIAN_LANGUAGE_HEADER)
selectLanguage("Français")
verifyLanguageHeaderIsTranslated(FRENCH_LANGUAGE_HEADER)
selectLanguage(FRENCH_SYSTEM_LOCALE_OPTION)
verifyLanguageHeaderIsTranslated("Language")
IdlingRegistry.getInstance().unregister(localeListIdlingResource)
}
}
@Test
fun goToHomeScreenBottomToolbarTest() {
val genericURL = TestAssetHelper.getGenericAsset(mockWebServer, 1)

@ -192,12 +192,15 @@ class SettingsRobot {
return SettingsSubMenuAccessibilityRobot.Transition()
}
fun openLanguageSubMenu(interact: SettingsSubMenuLanguageRobot.() -> Unit): SettingsSubMenuLanguageRobot.Transition {
fun openLanguageSubMenu(
localizedText: String = getStringResource(R.string.preferences_language),
interact: SettingsSubMenuLanguageRobot.() -> Unit
): SettingsSubMenuLanguageRobot.Transition {
onView(withId(R.id.recycler_view))
.perform(
RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
hasDescendant(
withText(R.string.preferences_language)
withText(localizedText)
),
ViewActions.click()
)

@ -7,13 +7,16 @@ package org.mozilla.fenix.ui.robots
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.uiautomator.UiScrollable
import androidx.test.uiautomator.UiSelector
import junit.framework.TestCase.assertTrue
import org.hamcrest.CoreMatchers
import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.helpers.TestHelper.mDevice
import org.mozilla.fenix.helpers.TestHelper.packageName
import org.mozilla.fenix.helpers.click
class SettingsSubMenuLanguageRobot {
fun selectLanguage(language: String) {
@ -23,9 +26,45 @@ class SettingsSubMenuLanguageRobot {
.click()
}
fun selectLanguageSearchResult(languageName: String) {
language(languageName).waitForExists(waitingTime)
language(languageName).click()
}
fun verifyLanguageHeaderIsTranslated(translation: String) =
assertTrue(mDevice.findObject(UiSelector().text(translation)).waitForExists(waitingTime))
fun verifySelectedLanguage(language: String) {
languagesList.waitForExists(waitingTime)
assertTrue(
languagesList
.getChildByText(UiSelector().text(language), language, true)
.getFromParent(UiSelector().resourceId("$packageName:id/locale_selected_icon"))
.waitForExists(waitingTime)
)
}
fun openSearchBar() {
onView(withId(R.id.search)).click()
}
fun typeInSearchBar(text: String) {
searchBar.waitForExists(waitingTime)
searchBar.text = text
}
fun verifySearchResultsContains(languageName: String) {
assertTrue(language(languageName).waitForExists(waitingTime))
}
fun clearSearchBar() {
onView(withId(R.id.search_close_btn)).click()
}
fun verifyLanguageListIsDisplayed() {
assertTrue(languagesList.waitForExists(waitingTime))
}
class Transition {
fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition {
@ -47,3 +86,8 @@ private val languagesList =
.resourceId("$packageName:id/locale_list")
.scrollable(true)
)
private fun language(name: String) = mDevice.findObject(UiSelector().text(name))
private val searchBar =
mDevice.findObject(UiSelector().resourceId("$packageName:id/search_src_text"))

@ -33,6 +33,7 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.Constants.RETRY_COUNT
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeLong
import org.mozilla.fenix.helpers.TestHelper.getStringResource
import org.mozilla.fenix.helpers.TestHelper.mDevice
import org.mozilla.fenix.helpers.TestHelper.packageName
import org.mozilla.fenix.helpers.click
@ -145,13 +146,16 @@ class ThreeDotMenuMainRobot {
}
class Transition {
fun openSettings(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition {
fun openSettings(
localizedText: String = getStringResource(R.string.browser_menu_settings),
interact: SettingsRobot.() -> Unit
): SettingsRobot.Transition {
// We require one swipe to display the full size 3-dot menu. On smaller devices
// such as the Pixel 2, we require two swipes to display the "Settings" menu item
// at the bottom. On larger devices, the second swipe is a no-op.
threeDotMenuRecyclerView().perform(swipeUp())
threeDotMenuRecyclerView().perform(swipeUp())
settingsButton().click()
settingsButton(localizedText).click()
SettingsRobot().interact()
return SettingsRobot.Transition()
@ -405,7 +409,9 @@ private fun threeDotMenuRecyclerViewExists() {
threeDotMenuRecyclerView().check(matches(isDisplayed()))
}
private fun settingsButton() = mDevice.findObject(UiSelector().text("Settings"))
private fun settingsButton(localizedText: String = getStringResource(R.string.browser_menu_settings)) =
mDevice.findObject(UiSelector().text(localizedText))
private fun assertSettingsButton() = assertTrue(settingsButton().waitForExists(waitingTime))
private fun customizeHomeButton() =

@ -8,5 +8,6 @@ const val STRING_ONBOARDING_ACCOUNT_SIGN_IN_HEADER = "Sync Firefox between devic
const val STRING_ONBOARDING_TRACKING_PROTECTION_HEADER = "Always-on privacy"
const val STRING_ONBOARDING_TOOLBAR_PLACEMENT_HEADER = "Pick your toolbar placement"
const val FRENCH_LANGUAGE_HEADER = "Langues"
const val ROMANIAN_LANGUAGE_HEADER = "Limbă"
const val FR_SETTINGS = "Paramètres"
const val FRENCH_SYSTEM_LOCALE_OPTION = "Utiliser la langue de lappareil"
const val ROMANIAN_LANGUAGE_HEADER = "Limbă"

Loading…
Cancel
Save