Merge pull request #4080 from kiwix/Fixes#4073

Fixed: SearchWidgetTest is flaky in CI.
This commit is contained in:
Kelson 2024-11-15 19:01:42 +01:00 committed by GitHub
commit 3e30741ebe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 128 additions and 95 deletions

View File

@ -28,13 +28,16 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.uiautomator.By import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObjectNotFoundException
import applyWithViewHierarchyPrinting import applyWithViewHierarchyPrinting
import com.adevinta.android.barista.interaction.BaristaSleepInteractions import com.adevinta.android.barista.interaction.BaristaSleepInteractions
import org.hamcrest.core.AllOf.allOf import org.hamcrest.core.AllOf.allOf
import org.kiwix.kiwixmobile.BaseRobot import org.kiwix.kiwixmobile.BaseRobot
import org.kiwix.kiwixmobile.Findable.Text
import org.kiwix.kiwixmobile.SHORT_WAIT
import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.main.KiwixMainActivity import org.kiwix.kiwixmobile.main.KiwixMainActivity
import org.kiwix.kiwixmobile.testutils.TestUtils import org.kiwix.kiwixmobile.testutils.TestUtils.TEST_PAUSE_MS_FOR_DOWNLOAD_TEST
import org.kiwix.kiwixmobile.testutils.TestUtils.testFlakyView import org.kiwix.kiwixmobile.testutils.TestUtils.testFlakyView
fun searchWidget(func: SearchWidgetRobot.() -> Unit) = fun searchWidget(func: SearchWidgetRobot.() -> Unit) =
@ -45,83 +48,81 @@ class SearchWidgetRobot : BaseRobot() {
fun removeWidgetIfAlreadyAdded(uiDevice: UiDevice) { fun removeWidgetIfAlreadyAdded(uiDevice: UiDevice) {
try { try {
val widget = uiDevice.findObject(By.text("Search Kiwix")) val widget = uiDevice.findObject(By.text("Search Kiwix"))
widget.click(1000L) val removeTarget = Point(uiDevice.displayWidth / 2, uiDevice.displayHeight / 10)
uiDevice.waitForIdle()
val center = getScreenCenter(uiDevice)
val widgetBounds = widget.visibleBounds
uiDevice.swipe( widget.drag(removeTarget)
widgetBounds.centerX(),
widgetBounds.centerY(),
center.x,
100,
150
)
uiDevice.waitForIdle() uiDevice.waitForIdle()
} catch (ignore: Exception) { } catch (ignore: Exception) {
// nothing to do since widget is not added // nothing to do since widget is not added
}
}
fun addWidgetToHomeScreen(uiDevice: UiDevice) {
try {
if (uiDevice.findObject(By.text("Search Kiwix")).text == "Search Kiwix") {
// since search widget is already exist we does not require to add it again.
return
}
} catch (ignore: Exception) {
// widget does not exist.
Log.e( Log.e(
"SEARCH_WIDGET", "SEARCH_WIDGET_TEST",
"Could not find the Search widget. Probably it does not exist" "Could not find the Search widget. It likely does not exist."
) )
} }
val center = getScreenCenter(uiDevice)
longPressInCenterOfScreen(uiDevice, center)
clickOnWidgetsText(uiDevice)
var widget = uiDevice.findObject(By.text("Kiwix"))
var maxSwipes = 30
while (widget == null && maxSwipes > 0) {
uiDevice.swipe(center.x, center.y, center.x, 0, 200)
uiDevice.waitForIdle()
widget = uiDevice.findObject(By.text("Kiwix"))
maxSwipes--
}
uiDevice.swipe(center.x, center.y, center.x, 0, 200)
val b = widget.visibleBounds
val c = Point(b.left + 150, b.bottom + 150)
val dest = Point(c.x + 250, c.y + 250)
uiDevice.swipe(arrayOf(c, c, dest), 150)
} }
private fun clickOnWidgetsText(uiDevice: UiDevice) { fun assertAddWidgetToHomeScreenVisible(): Boolean =
try { try {
// Different according to the devices isVisible(Text("Add automatically"))
uiDevice.findObject(By.text("Widgets")).click() true
} catch (ignore: Exception) { } catch (ignore: Exception) {
uiDevice.findObject(By.text("WIDGETS")).click() false
} }
uiDevice.waitForIdle()
fun addWidgetToHomeScreenFromWidgetWindow() {
testFlakyView({ clickOn(Text("Add automatically")) })
} }
fun assertSearchWidgetAddedToHomeScreen(uiDevice: UiDevice) { fun findSearchWidget(uiDevice: UiDevice) {
uiDevice.findObject(By.text("Search Kiwix")) try {
assertSearchWidgetAddedToHomeScreen(2)
} catch (ignore: RuntimeException) {
// the search widget is not on the home screen, swipe right because
// the widget has been added to next window
swipeRightToOpenNextWindow(uiDevice)
}
} }
private fun longPressInCenterOfScreen(uiDevice: UiDevice, center: Point) { private fun swipeRightToOpenNextWindow(uiDevice: UiDevice) {
uiDevice.swipe(arrayOf(center, center), 150) val displayWidth = uiDevice.displayWidth
val displayHeight = uiDevice.displayHeight
val startX = (displayWidth * 0.9).toInt()
val endX = (displayWidth * 0.1).toInt()
val centerY = displayHeight / 2
uiDevice.swipe(startX, centerY, endX, centerY, 20)
} }
private fun getScreenCenter(device: UiDevice): Point { fun assertSearchWidgetAddedToHomeScreen(retryCount: Int = 5) {
val size = device.displaySizeDp testFlakyView({ isVisible(Text("Search Kiwix"), SHORT_WAIT) }, retryCount)
return Point(size.x / 2, size.y / 2)
} }
fun clickOnBookmarkIcon(uiDevice: UiDevice, kiwixMainActivity: KiwixMainActivity) { fun clickOnMicIcon(
uiDevice.findObject( uiDevice: UiDevice,
By.res("${kiwixMainActivity.packageName}:id/search_widget_star") kiwixMainActivity: KiwixMainActivity
).click() ) {
clickOnElementById(uiDevice, kiwixMainActivity, "search_widget_mic")
}
fun closeIfGoogleSearchVisible() {
try {
pauseForBetterTestPerformance()
testFlakyView({ isVisible(Text("Google")) })
pressBack()
Log.e("SEARCH_WIDGET_TEST", "Closed the Google speak dialog")
} catch (ignore: Exception) {
// do nothing since the Google speak is not recognized in this emulator.
Log.e("SEARCH_WIDGET_TEST", "Could not close the Google speak dialog.")
}
}
fun clickOnBookmarkIcon(
uiDevice: UiDevice,
kiwixMainActivity: KiwixMainActivity
) {
clickOnElementById(uiDevice, kiwixMainActivity, "search_widget_star")
} }
fun assertBookmarkScreenVisible() { fun assertBookmarkScreenVisible() {
@ -131,37 +132,41 @@ class SearchWidgetRobot : BaseRobot() {
}) })
} }
fun clickOnMicIcon(uiDevice: UiDevice, kiwixMainActivity: KiwixMainActivity) {
uiDevice.findObject(
By.res("${kiwixMainActivity.packageName}:id/search_widget_mic")
).click()
}
fun closeIfGoogleSearchVisible(uiDevice: UiDevice) {
try {
pauseForBetterTestPerformance()
testFlakyView({ uiDevice.findObject(By.text("Google")) })
pressBack()
Log.e("SEARCH_WIDGET_TEST", "Closed the Google speak dialog")
} catch (ignore: Exception) {
// do nothing since the Google speak is not recognized in this emulator.
Log.e("SEARCH_WIDGET_TEST", "Could not close the Google speak dialog.")
}
}
fun assertSearchScreenVisible() { fun assertSearchScreenVisible() {
testFlakyView({ testFlakyView({
onView(withText(R.string.menu_search_in_text)).check(matches(isDisplayed())) onView(withText(R.string.menu_search_in_text)).check(matches(isDisplayed()))
}) })
} }
fun clickOnSearchText(uiDevice: UiDevice, kiwixMainActivity: KiwixMainActivity) { fun clickOnSearchText(
uiDevice.findObject( uiDevice: UiDevice,
By.res("${kiwixMainActivity.packageName}:id/search_widget_text") kiwixMainActivity: KiwixMainActivity
).click() ) {
clickOnElementById(uiDevice, kiwixMainActivity, "search_widget_text")
}
private fun clickOnElementById(
uiDevice: UiDevice,
kiwixMainActivity: KiwixMainActivity,
elementId: String,
retryCount: Int = 20
) {
var attempts = 0
while (attempts < retryCount) {
try {
uiDevice.findObject(
By.res("${kiwixMainActivity.packageName}:id/$elementId")
).click()
return
} catch (e: UiObjectNotFoundException) {
attempts++
Log.e("SEARCH_WIDGET_TEST", "Attempt $attempts: Failed to click on $elementId")
}
}
throw RuntimeException("Could not find $elementId after $retryCount attempts")
} }
private fun pauseForBetterTestPerformance() { private fun pauseForBetterTestPerformance() {
BaristaSleepInteractions.sleep(TestUtils.TEST_PAUSE_MS_FOR_DOWNLOAD_TEST.toLong()) BaristaSleepInteractions.sleep(TEST_PAUSE_MS_FOR_DOWNLOAD_TEST.toLong())
} }
} }

View File

@ -18,7 +18,11 @@
package org.kiwix.kiwixmobile.widgets package org.kiwix.kiwixmobile.widgets
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.os.Build import android.os.Build
import android.os.Bundle
import android.widget.RemoteViews
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.test.core.app.ActivityScenario import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.accessibility.AccessibilityChecks import androidx.test.espresso.accessibility.AccessibilityChecks
@ -33,8 +37,10 @@ import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.kiwix.kiwixmobile.BaseActivityTest import org.kiwix.kiwixmobile.BaseActivityTest
import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.main.KiwixMainActivity import org.kiwix.kiwixmobile.main.KiwixMainActivity
import org.kiwix.kiwixmobile.main.KiwixSearchWidget
import org.kiwix.kiwixmobile.testutils.RetryRule import org.kiwix.kiwixmobile.testutils.RetryRule
import org.kiwix.kiwixmobile.testutils.TestUtils import org.kiwix.kiwixmobile.testutils.TestUtils
@ -89,22 +95,44 @@ class SearchWidgetTest : BaseActivityTest() {
} }
searchWidget { searchWidget {
pressHome() pressHome()
addWidgetToHomeScreen(uiDevice) uiDevice.waitForIdle()
assertSearchWidgetAddedToHomeScreen(uiDevice) if (addWidgetToHomeScreen()) {
clickOnBookmarkIcon(uiDevice, kiwixMainActivity) if (assertAddWidgetToHomeScreenVisible()) {
assertBookmarkScreenVisible() addWidgetToHomeScreenFromWidgetWindow()
pressBack() assertSearchWidgetAddedToHomeScreen()
pressHome() clickOnBookmarkIcon(uiDevice, kiwixMainActivity)
clickOnMicIcon(uiDevice, kiwixMainActivity) assertBookmarkScreenVisible()
closeIfGoogleSearchVisible(uiDevice) pressBack()
assertSearchScreenVisible() pressHome()
pressBack() findSearchWidget(uiDevice)
pressHome() clickOnMicIcon(uiDevice, kiwixMainActivity)
clickOnSearchText(uiDevice, kiwixMainActivity) closeIfGoogleSearchVisible()
assertSearchScreenVisible() assertSearchScreenVisible()
pressHome() pressBack()
removeWidgetIfAlreadyAdded(uiDevice) pressHome()
findSearchWidget(uiDevice)
clickOnSearchText(uiDevice, kiwixMainActivity)
assertSearchScreenVisible()
pressHome()
removeWidgetIfAlreadyAdded(uiDevice)
}
}
} }
} }
} }
private fun addWidgetToHomeScreen(): Boolean {
val mAppWidgetManager: AppWidgetManager? =
context.getSystemService(AppWidgetManager::class.java)
val myProvider = ComponentName(context, KiwixSearchWidget::class.java)
return if (mAppWidgetManager?.isRequestPinAppWidgetSupported == true) {
val remoteViews =
RemoteViews(context.packageName, R.layout.kiwix_search_widget)
val bundle = Bundle()
bundle.putParcelable(AppWidgetManager.EXTRA_APPWIDGET_PREVIEW, remoteViews)
mAppWidgetManager.requestPinAppWidget(myProvider, bundle, null)
} else {
false
}
}
} }