Skip to content

Commit

Permalink
Merge pull request #4080 from kiwix/Fixes#4073
Browse files Browse the repository at this point in the history
Fixed: SearchWidgetTest is flaky in CI.
  • Loading branch information
kelson42 authored Nov 15, 2024
2 parents c343e5d + 61fe23a commit 3e30741
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObjectNotFoundException
import applyWithViewHierarchyPrinting
import com.adevinta.android.barista.interaction.BaristaSleepInteractions
import org.hamcrest.core.AllOf.allOf
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.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

fun searchWidget(func: SearchWidgetRobot.() -> Unit) =
Expand All @@ -45,102 +48,68 @@ class SearchWidgetRobot : BaseRobot() {
fun removeWidgetIfAlreadyAdded(uiDevice: UiDevice) {
try {
val widget = uiDevice.findObject(By.text("Search Kiwix"))
widget.click(1000L)
uiDevice.waitForIdle()
val center = getScreenCenter(uiDevice)
val widgetBounds = widget.visibleBounds

uiDevice.swipe(
widgetBounds.centerX(),
widgetBounds.centerY(),
center.x,
100,
150
)
val removeTarget = Point(uiDevice.displayWidth / 2, uiDevice.displayHeight / 10)

widget.drag(removeTarget)

uiDevice.waitForIdle()
} catch (ignore: Exception) {
// 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(
"SEARCH_WIDGET",
"Could not find the Search widget. Probably it does not exist"
"SEARCH_WIDGET_TEST",
"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 {
// Different according to the devices
uiDevice.findObject(By.text("Widgets")).click()
isVisible(Text("Add automatically"))
true
} catch (ignore: Exception) {
uiDevice.findObject(By.text("WIDGETS")).click()
false
}
uiDevice.waitForIdle()
}

fun assertSearchWidgetAddedToHomeScreen(uiDevice: UiDevice) {
uiDevice.findObject(By.text("Search Kiwix"))
fun addWidgetToHomeScreenFromWidgetWindow() {
testFlakyView({ clickOn(Text("Add automatically")) })
}

private fun longPressInCenterOfScreen(uiDevice: UiDevice, center: Point) {
uiDevice.swipe(arrayOf(center, center), 150)
fun findSearchWidget(uiDevice: UiDevice) {
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 getScreenCenter(device: UiDevice): Point {
val size = device.displaySizeDp
return Point(size.x / 2, size.y / 2)
}
private fun swipeRightToOpenNextWindow(uiDevice: UiDevice) {
val displayWidth = uiDevice.displayWidth
val displayHeight = uiDevice.displayHeight

fun clickOnBookmarkIcon(uiDevice: UiDevice, kiwixMainActivity: KiwixMainActivity) {
uiDevice.findObject(
By.res("${kiwixMainActivity.packageName}:id/search_widget_star")
).click()
val startX = (displayWidth * 0.9).toInt()
val endX = (displayWidth * 0.1).toInt()
val centerY = displayHeight / 2

uiDevice.swipe(startX, centerY, endX, centerY, 20)
}

fun assertBookmarkScreenVisible() {
testFlakyView({
onView(allOf(withText(R.string.bookmarks), isDescendantOfA(withId(R.id.toolbar))))
.check(matches(isDisplayed()))
})
fun assertSearchWidgetAddedToHomeScreen(retryCount: Int = 5) {
testFlakyView({ isVisible(Text("Search Kiwix"), SHORT_WAIT) }, retryCount)
}

fun clickOnMicIcon(uiDevice: UiDevice, kiwixMainActivity: KiwixMainActivity) {
uiDevice.findObject(
By.res("${kiwixMainActivity.packageName}:id/search_widget_mic")
).click()
fun clickOnMicIcon(
uiDevice: UiDevice,
kiwixMainActivity: KiwixMainActivity
) {
clickOnElementById(uiDevice, kiwixMainActivity, "search_widget_mic")
}

fun closeIfGoogleSearchVisible(uiDevice: UiDevice) {
fun closeIfGoogleSearchVisible() {
try {
pauseForBetterTestPerformance()
testFlakyView({ uiDevice.findObject(By.text("Google")) })
testFlakyView({ isVisible(Text("Google")) })
pressBack()
Log.e("SEARCH_WIDGET_TEST", "Closed the Google speak dialog")
} catch (ignore: Exception) {
Expand All @@ -149,19 +118,55 @@ class SearchWidgetRobot : BaseRobot() {
}
}

fun clickOnBookmarkIcon(
uiDevice: UiDevice,
kiwixMainActivity: KiwixMainActivity
) {
clickOnElementById(uiDevice, kiwixMainActivity, "search_widget_star")
}

fun assertBookmarkScreenVisible() {
testFlakyView({
onView(allOf(withText(R.string.bookmarks), isDescendantOfA(withId(R.id.toolbar))))
.check(matches(isDisplayed()))
})
}

fun assertSearchScreenVisible() {
testFlakyView({
onView(withText(R.string.menu_search_in_text)).check(matches(isDisplayed()))
})
}

fun clickOnSearchText(uiDevice: UiDevice, kiwixMainActivity: KiwixMainActivity) {
uiDevice.findObject(
By.res("${kiwixMainActivity.packageName}:id/search_widget_text")
).click()
fun clickOnSearchText(
uiDevice: UiDevice,
kiwixMainActivity: KiwixMainActivity
) {
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() {
BaristaSleepInteractions.sleep(TestUtils.TEST_PAUSE_MS_FOR_DOWNLOAD_TEST.toLong())
BaristaSleepInteractions.sleep(TEST_PAUSE_MS_FOR_DOWNLOAD_TEST.toLong())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@

package org.kiwix.kiwixmobile.widgets

import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.os.Build
import android.os.Bundle
import android.widget.RemoteViews
import androidx.lifecycle.Lifecycle
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.accessibility.AccessibilityChecks
Expand All @@ -33,8 +37,10 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.kiwix.kiwixmobile.BaseActivityTest
import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.main.KiwixMainActivity
import org.kiwix.kiwixmobile.main.KiwixSearchWidget
import org.kiwix.kiwixmobile.testutils.RetryRule
import org.kiwix.kiwixmobile.testutils.TestUtils

Expand Down Expand Up @@ -89,22 +95,44 @@ class SearchWidgetTest : BaseActivityTest() {
}
searchWidget {
pressHome()
addWidgetToHomeScreen(uiDevice)
assertSearchWidgetAddedToHomeScreen(uiDevice)
clickOnBookmarkIcon(uiDevice, kiwixMainActivity)
assertBookmarkScreenVisible()
pressBack()
pressHome()
clickOnMicIcon(uiDevice, kiwixMainActivity)
closeIfGoogleSearchVisible(uiDevice)
assertSearchScreenVisible()
pressBack()
pressHome()
clickOnSearchText(uiDevice, kiwixMainActivity)
assertSearchScreenVisible()
pressHome()
removeWidgetIfAlreadyAdded(uiDevice)
uiDevice.waitForIdle()
if (addWidgetToHomeScreen()) {
if (assertAddWidgetToHomeScreenVisible()) {
addWidgetToHomeScreenFromWidgetWindow()
assertSearchWidgetAddedToHomeScreen()
clickOnBookmarkIcon(uiDevice, kiwixMainActivity)
assertBookmarkScreenVisible()
pressBack()
pressHome()
findSearchWidget(uiDevice)
clickOnMicIcon(uiDevice, kiwixMainActivity)
closeIfGoogleSearchVisible()
assertSearchScreenVisible()
pressBack()
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
}
}
}

0 comments on commit 3e30741

Please sign in to comment.