Reputation: 995
I have the following case. We are using the Gherkin language to drive our native ui automation with Espresso. In our Gherkin lines we've got a line called:
And I tap on button "Next"
Where "Next" is a variable String we pass into our glue code (we are using the Cucumber framework).
As it happens, our app has many "Next" buttons with different resources ids. I ended up by using gherkin lines with variables like:
And I tap on button "Next in screen 1"
And I tap on button "Next in screen 2"
Now I want to use only the Gherkin variable "Next" in my code. I get an Integer array which contains all the resources ids from all the Next buttons, but when I want to check which id is displayed on the screen I got a NoMatchingViewException.
This is my current solution for now:
final int[] uiElementIds = getArrayWithIdsFromUIElement("Next");
int testId = 0;
for(int id : uiElementIds) {
try {
onView(withId(id)).check(matches(isDisplayed()));
testId = id;
break;
} catch(NoMatchingViewException ex) {
// do nothing
}
}
final int uiElementId = testId;
onView(withId(uiElementId)).withFailureHandler(new FailureHandler() {
@Override
public void handle(Throwable error, Matcher<View> viewMatcher) {
onView(withId(uiElementId)).perform(scrollTo(), click());
}
}).perform(click());
As you can see I just catch the thrown NoMatchingViewException and do nothing with it until it finds the right id and break out of the for-loop.
My question is:
Is there a better approach which we can use to loop through it to see which id is displayed and if so click on it?
In my mind I came up with this idea, but it is not integrated in Espresso:
for(int id : uiElementIds) {
if(onView(withId(id)).exist()) {
performClick();
}
}
Upvotes: 4
Views: 1199
Reputation: 19351
According to your question
My question is:
Is there a better approach which we can use to loop through it to see which id is displayed and if so click on it?
In my mind I came up with this idea, but it is not integrated in Espresso:
for(int id : uiElementIds) { if(onView(withId(id)).exist()) { performClick(); } }
Here's my old Espresso
framework Activity
tests:
@RunWith(AndroidJUnit4.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class DetailsActivityTest {
@Rule
public ActivityTestRule<MainActivity_> mRule = new ActivityTestRule<>(MainActivity_.class);
//TODO: Write tests to check if views are visible
private final int[] allDetailsActivityViewsIdis = {
R.id.dItem,
R.id.dDayAndDate,
R.id.dDay,
R.id.dDate,
R.id.dCity,
R.id.dTempAndIcon,
R.id.dTemperature,
R.id.dHighTemp,
R.id.dLowTemp,
R.id.dDescriptionLayout,
R.id.dDescription,
R.id.dForecast,
R.id.dHumidityLayout,
R.id.dHumidityDesc,
R.id.dHumidityVal,
R.id.dPressureLayout,
R.id.dPressureDesc,
R.id.dPressureVal,
R.id.dWindLayout,
R.id.dWindDesc,
R.id.dWindVal
};
private final int[] detailsActivityTextViewsIdis = {
R.id.dDay,
R.id.dDate,
R.id.dHighTemp,
R.id.dLowTemp,
R.id.dDescription,
R.id.dHumidityVal,
R.id.dPressureVal,
R.id.dWindVal,
};
private final int[] detailsActivityTextViewsDefaultValues = {
R.string.day,
R.string.date,
R.string.high_temp,
R.string.low_temp,
R.string.description,
R.string.humidity_val,
R.string.pressure_val,
R.string.wind_val,
};
@Before
//TODO: Rewrite this code using espresso-intents
public void checkIfAllDetailActivityViewsAreDisplayed() throws InterruptedException {
for (int viewId : allDetailsActivityViewsIdis)
onView(withId(viewId)).perform(click());
}
@Test
public void checkIfDetailsActivityViewsHaveNoDefaultValue() throws InterruptedException {
for (int viewId : detailsActivityTextViewsIdis)
for (int valueId : detailsActivityTextViewsDefaultValues)
onView(withId(viewId)).check(matches(not(withText(valueId))));
}
}
As you see, using foreach
with Espresso is possible, but instead of exists()
use check(matches(...)
with value: isDisplayed
, isDisplayedAtLeast
or isCompletelyDisplayed
Hope it would help you
Upvotes: 1