Skip to content

Commit a1c4dbe

Browse files
Deflakes DrawerActionsIntegrationTest by using DrawerListener for waiting for close.
testOpenDrawer_clickItem was flaking 3/200 times. With these changes, it doesn't flake after 2000 runs. clickItem now uses a drawerListener to listen for the close to happen so there's no race condition. PiperOrigin-RevId: 608675813
1 parent e1b9481 commit a1c4dbe

File tree

4 files changed

+76
-8
lines changed

4 files changed

+76
-8
lines changed

espresso/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ The following artifacts were released:
2121

2222
**New Features**
2323

24+
* Add waitForClose to DrawerActions.
25+
2426
**Breaking Changes**
2527

2628
**API Changes**

espresso/contrib/java/androidx/test/espresso/contrib/DrawerActions.java

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ private DrawerActions() {
6060
}
6161

6262
private abstract static class DrawerAction implements ViewAction {
63-
6463
@Override
6564
public final Matcher<View> getConstraints() {
6665
return isAssignableFrom(DrawerLayout.class);
@@ -84,7 +83,6 @@ public final void perform(UiController uiController, View view) {
8483
drawer.addDrawerListener(idlingListener);
8584
IdlingRegistry.getInstance().register(idlingListener);
8685
}
87-
8886
performAction(uiController, drawer);
8987
uiController.loopMainThreadUntilIdle();
9088

@@ -194,17 +192,81 @@ protected Matcher<View> checkAction() {
194192
}
195193

196194
@Override
197-
protected void performAction(UiController uiController, DrawerLayout view) {
198-
view.closeDrawer(gravity);
195+
public void performAction(UiController uiController, DrawerLayout drawer) {
196+
IdlingDrawerClosedListener closeListener = new IdlingDrawerClosedListener();
197+
drawer.addDrawerListener(closeListener);
198+
drawer.closeDrawer(gravity);
199199
uiController.loopMainThreadUntilIdle();
200-
// If still open wait some more...
201-
if (view.isDrawerVisible(gravity)) {
202-
uiController.loopMainThreadForAtLeast(300);
203-
}
200+
// Need to wait extra time after it closes to reduce flakiness.
201+
uiController.loopMainThreadForAtLeast(300);
202+
drawer.removeDrawerListener(closeListener);
203+
}
204+
};
205+
}
206+
207+
/**
208+
* Creates an action that will wait for the drawer to close. Use this in cases where the closing
209+
* of the drawer is implicit, such as selecting an item in the drawer. No operation if the drawer
210+
* is closed. This uses an idling resource to wait for close, so it will fail if it does not close
211+
* within the idling resource timeout.
212+
*/
213+
public static ViewAction waitForClose() {
214+
return new DrawerAction() {
215+
@Override
216+
public String getDescription() {
217+
return "waiting for drawer to close";
218+
}
219+
220+
@Override
221+
protected Matcher<View> checkAction() {
222+
return isOpen();
223+
}
224+
225+
@Override
226+
public void performAction(UiController uiController, DrawerLayout drawer) {
227+
// Add a listener that waits for the drawer to be closed, wait for it to idle,
228+
// and then remove the listener immediately.
229+
IdlingDrawerClosedListener closeListener = new IdlingDrawerClosedListener();
230+
drawer.addDrawerListener(closeListener);
231+
uiController.loopMainThreadUntilIdle();
232+
drawer.removeDrawerListener(closeListener);
204233
}
205234
};
206235
}
207236

237+
/** Drawer listener that functions as an {@link IdlingResource} for Espresso. */
238+
private static final class IdlingDrawerClosedListener extends SimpleDrawerListener
239+
implements IdlingResource {
240+
241+
private final int id = nextId.getAndIncrement();
242+
243+
private ResourceCallback callback;
244+
private boolean isClosed = false;
245+
246+
@Override
247+
public void onDrawerClosed(View view) {
248+
isClosed = true;
249+
if (callback != null) {
250+
callback.onTransitionToIdle();
251+
}
252+
}
253+
254+
@Override
255+
public String getName() {
256+
return "IdlingDrawerListener::" + id;
257+
}
258+
259+
@Override
260+
public boolean isIdleNow() {
261+
return isClosed;
262+
}
263+
264+
@Override
265+
public void registerIdleTransitionCallback(ResourceCallback callback) {
266+
this.callback = callback;
267+
}
268+
}
269+
208270
/** Drawer listener that functions as an {@link IdlingResource} for Espresso. */
209271
private static final class IdlingDrawerListener extends SimpleDrawerListener
210272
implements IdlingResource {

espresso/contrib/java/androidx/test/espresso/contrib/api/current_public.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package androidx.test.espresso.contrib {
2020
method public static androidx.test.espresso.ViewAction! open(int);
2121
method @Deprecated public static void openDrawer(int);
2222
method @Deprecated public static void openDrawer(int, int);
23+
method public static androidx.test.espresso.ViewAction! waitForClose();
2324
}
2425

2526
public final class DrawerMatchers {

espresso/contrib/javatests/androidx/test/espresso/contrib/DrawerActionsIntegrationTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import static androidx.test.espresso.assertion.ViewAssertions.matches;
2525
import static androidx.test.espresso.contrib.DrawerActions.close;
2626
import static androidx.test.espresso.contrib.DrawerActions.open;
27+
import static androidx.test.espresso.contrib.DrawerActions.waitForClose;
2728
import static androidx.test.espresso.contrib.DrawerMatchers.isClosed;
2829
import static androidx.test.espresso.contrib.DrawerMatchers.isOpen;
2930
import static androidx.test.espresso.matcher.ViewMatchers.withId;
@@ -91,6 +92,8 @@ public void testOpenDrawer_clickItem() {
9192
String rowContents = DrawerActivity.DRAWER_CONTENTS[rowIndex];
9293
onData(allOf(is(instanceOf(String.class)), is(rowContents))).perform(click());
9394

95+
onView(withId(R.id.drawer_layout)).perform(waitForClose());
96+
9497
// clicking the item should close the drawer.
9598
onView(withId(R.id.drawer_layout)).check(matches(isClosed()));
9699

0 commit comments

Comments
 (0)