From cfbdbc4edc6479ede902c3751cea176f896553fd Mon Sep 17 00:00:00 2001 From: Federico Iosue Date: Tue, 4 Aug 2020 17:52:38 +0200 Subject: [PATCH] Faced missing displayed views in Espresso tests They seem to only depends on MaterialDialog timings... I'd like to avoid writing code in packaged classes just to manage timing as Idling Resources or BusyBee require. --- .../omninotes/ui/BaseEspressoTest.java | 53 ++++++++++++++++++- .../omninotes/ui/CategoryLifecycleTest.java | 10 ++-- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/omniNotes/src/androidTest/java/it/feio/android/omninotes/ui/BaseEspressoTest.java b/omniNotes/src/androidTest/java/it/feio/android/omninotes/ui/BaseEspressoTest.java index b09be7c56a..388bc46f03 100644 --- a/omniNotes/src/androidTest/java/it/feio/android/omninotes/ui/BaseEspressoTest.java +++ b/omniNotes/src/androidTest/java/it/feio/android/omninotes/ui/BaseEspressoTest.java @@ -18,32 +18,37 @@ package it.feio.android.omninotes.ui; -import static androidx.test.espresso.Espresso.onData; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard; import static androidx.test.espresso.action.ViewActions.replaceText; import static androidx.test.espresso.action.ViewActions.scrollTo; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isRoot; import static androidx.test.espresso.matcher.ViewMatchers.withClassName; import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withParent; import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.anything; import static org.hamcrest.Matchers.is; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import androidx.core.view.GravityCompat; +import androidx.test.espresso.PerformException; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; import androidx.test.espresso.ViewInteraction; import androidx.test.espresso.contrib.RecyclerViewActions; import androidx.test.espresso.matcher.ViewMatchers; +import androidx.test.espresso.util.HumanReadables; +import androidx.test.espresso.util.TreeIterables; import androidx.test.rule.ActivityTestRule; import it.feio.android.omninotes.BaseAndroidTestCase; import it.feio.android.omninotes.MainActivity; import it.feio.android.omninotes.R; +import java.util.concurrent.TimeoutException; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.Matchers; @@ -129,4 +134,48 @@ void navigateUpSettings () { 1), isDisplayed())).perform(click()); } + /** + * Perform action of waiting for a specific view id. + * @param viewId The id of the view to wait for. + * @param millis The timeout of until when to wait for. + */ + public static ViewAction waitId(final int viewId, final long millis) { + return new ViewAction() { + @Override + public Matcher getConstraints() { + return isRoot(); + } + + @Override + public String getDescription() { + return "wait for a specific view with id <" + viewId + "> during " + millis + " millis."; + } + + @Override + public void perform(final UiController uiController, final View view) { + uiController.loopMainThreadUntilIdle(); + final long startTime = System.currentTimeMillis(); + final long endTime = startTime + millis; + final Matcher viewMatcher = withId(viewId); + + do { + for (View child : TreeIterables.breadthFirstViewTraversal(view)) { + if (viewMatcher.matches(child)) { + return; + } + } + + uiController.loopMainThreadForAtLeast(50); + } + while (System.currentTimeMillis() < endTime); + + throw new PerformException.Builder() + .withActionDescription(this.getDescription()) + .withViewDescription(HumanReadables.describe(view)) + .withCause(new TimeoutException()) + .build(); + } + }; + } + } diff --git a/omniNotes/src/androidTest/java/it/feio/android/omninotes/ui/CategoryLifecycleTest.java b/omniNotes/src/androidTest/java/it/feio/android/omninotes/ui/CategoryLifecycleTest.java index b38a934ba9..6b092b426c 100644 --- a/omniNotes/src/androidTest/java/it/feio/android/omninotes/ui/CategoryLifecycleTest.java +++ b/omniNotes/src/androidTest/java/it/feio/android/omninotes/ui/CategoryLifecycleTest.java @@ -27,6 +27,7 @@ import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.isRoot; import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withParent; @@ -44,7 +45,6 @@ import androidx.appcompat.widget.AppCompatImageView; import androidx.test.espresso.matcher.ViewMatchers; import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.FlakyTest; import androidx.test.filters.LargeTest; import it.feio.android.omninotes.R; import java.util.Calendar; @@ -77,9 +77,11 @@ public void addNewCategory () throws InterruptedException { onView(allOf(withId(R.id.menu_category), withContentDescription(R.string.category), isDisplayed())).perform( click()); + // Materialdialog "Add Category" + onView(isRoot()).perform(waitId(R.id.md_buttonDefaultPositive, 5000)); + onView((withText(R.string.add_category))).perform(click()); - sleep(1000); onView(withId(R.id.category_title)).perform(replaceText(categoryName), closeSoftKeyboard()); onView(allOf(withId(R.id.save), withText("Ok"), isDisplayed())).perform(click()); @@ -97,11 +99,9 @@ public void addNewCategory () throws InterruptedException { onView(allOf(withContentDescription(R.string.drawer_open), withParent(withId(R.id.toolbar)), isDisplayed())).perform(click()); - } @Test - @FlakyTest(detail = "Fixme with Idling Resources or BusyBee") // FIXME public void checkCategoryCreation () throws InterruptedException { addNewCategory(); @@ -157,11 +157,9 @@ public void categoryColorChange () throws InterruptedException { onView(allOf(withId(R.id.color_chooser), isDisplayed())).check( matches(withBackgroundColor(Color.parseColor("#FF263238")))); - } @Test - @FlakyTest(detail = "Fixme with Idling Resources or BusyBee") // FIXME public void categoryDeletion () throws InterruptedException { addNewCategory();