a bit more reliability for tests

This commit is contained in:
Matthieu 2021-05-20 13:39:11 +02:00
parent a7351b2cf1
commit d1db225ffb
2 changed files with 9 additions and 5 deletions

View File

@ -12,6 +12,7 @@ import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiDevice
import org.hamcrest.Matchers.allOf
import org.pixeldroid.app.testUtility.* import org.pixeldroid.app.testUtility.*
import org.pixeldroid.app.utils.db.AppDatabase import org.pixeldroid.app.utils.db.AppDatabase
import org.junit.After import org.junit.After
@ -107,8 +108,10 @@ class DrawerMenuTest {
// Start the screen of your activity. // Start the screen of your activity.
onView(withText(R.string.menu_account)).perform(click()) onView(withText(R.string.menu_account)).perform(click())
// Check that profile activity was opened. // Check that profile activity was opened.
waitForView(R.id.editButton)
onView(withId(R.id.editButton)).check(matches(isDisplayed())) onView(withId(R.id.editButton)).check(matches(isDisplayed()))
val followersText = context.resources.getQuantityString(R.plurals.nb_followers, 2, 2) val followersText = context.resources.getQuantityString(R.plurals.nb_followers, 2, 2)
waitForView(R.id.nbFollowingTextView, allOf(withId(R.id.nbFollowersTextView), withText(followersText)))
onView(withText(followersText)).perform(click()) onView(withText(followersText)).perform(click())
waitForView(R.id.account_entry_avatar) waitForView(R.id.account_entry_avatar)
@ -120,8 +123,10 @@ class DrawerMenuTest {
// Start the screen of your activity. // Start the screen of your activity.
onView(withText(R.string.menu_account)).perform(click()) onView(withText(R.string.menu_account)).perform(click())
// Check that profile activity was opened. // Check that profile activity was opened.
waitForView(R.id.editButton)
onView(withId(R.id.editButton)).check(matches(isDisplayed())) onView(withId(R.id.editButton)).check(matches(isDisplayed()))
val followingText = context.resources.getQuantityString(R.plurals.nb_following, 3, 3) val followingText = context.resources.getQuantityString(R.plurals.nb_following, 3, 3)
waitForView(R.id.nbFollowingTextView, allOf(withId(R.id.nbFollowingTextView), withText(followingText)))
onView(withText(followingText)).perform(click()) onView(withText(followingText)).perform(click())
waitForView(R.id.account_entry_avatar) waitForView(R.id.account_entry_avatar)

View File

@ -66,15 +66,15 @@ fun ViewInteraction.isDisplayed(): Boolean {
* Doesn't work if the root changes (since it operates on the root!) * Doesn't work if the root changes (since it operates on the root!)
* @param viewId The id of the view to wait for. * @param viewId The id of the view to wait for.
*/ */
fun waitForView(viewId: Int) { fun waitForView(viewId: Int, viewMatcher: Matcher<View> = withId(viewId)) {
Espresso.onView(isRoot()).perform(waitForViewViewAction(viewId)) Espresso.onView(isRoot()).perform(waitForViewViewAction(viewId, viewMatcher))
} }
/** /**
* This ViewAction tells espresso to wait till a certain view is found in the view hierarchy. * This ViewAction tells espresso to wait till a certain view is found in the view hierarchy.
* @param viewId The id of the view to wait for. * @param viewId The id of the view to wait for.
*/ */
private fun waitForViewViewAction(viewId: Int): ViewAction { private fun waitForViewViewAction(viewId: Int, viewMatcher: Matcher<View>): ViewAction {
// The maximum time which espresso will wait for the view to show up (in milliseconds) // The maximum time which espresso will wait for the view to show up (in milliseconds)
val timeOut = 5000 val timeOut = 5000
return object : ViewAction { return object : ViewAction {
@ -90,7 +90,6 @@ private fun waitForViewViewAction(viewId: Int): ViewAction {
uiController.loopMainThreadUntilIdle() uiController.loopMainThreadUntilIdle()
val startTime = System.currentTimeMillis() val startTime = System.currentTimeMillis()
val endTime = startTime + timeOut val endTime = startTime + timeOut
val viewMatcher = withId(viewId)
do { do {
// Iterate through all views on the screen and see if the view we are looking for is there already // Iterate through all views on the screen and see if the view we are looking for is there already
@ -103,7 +102,7 @@ private fun waitForViewViewAction(viewId: Int): ViewAction {
// Loops the main thread for a specified period of time. // Loops the main thread for a specified period of time.
// Control may not return immediately, instead it'll return after the provided delay has passed and the queue is in an idle state again. // Control may not return immediately, instead it'll return after the provided delay has passed and the queue is in an idle state again.
uiController.loopMainThreadForAtLeast(100) uiController.loopMainThreadForAtLeast(100)
} while (System.currentTimeMillis() < endTime) // in case of a timeout we throw an exception -&gt; test fails } while (System.currentTimeMillis() < endTime) // in case of a timeout we throw an exception - test fails
throw PerformException.Builder() throw PerformException.Builder()
.withCause(TimeoutException()) .withCause(TimeoutException())
.withActionDescription(this.description) .withActionDescription(this.description)