As I discussed, onData() is the right function you should use for testing a viewlist: http://baiduhix.blogspot.co.uk/2015/07/android-espresso-ondata-error.html
However, recently i got an error on CI (i use travis-ci, you can use any ci system you want).
This code causes this error:
onData(allOf(is(instanceOf(DeliveryVO.class)), hasProperty("deliveryReferenceId", is("1235")))) .perform(click());
Actually I can run all my tests on my local PC without any issues.
Finally, I can reproduce it on my local PC by running on a small screen device:
I can exam the text on my button by: ".check(matches(withText("...")))" and enable by ".check(matches(isEnabled()))" and clickable by ".check(matches(isClickable()));"
and visible by " withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE).matches(onData(....."
All exams work as expected, BUT i can click? why???????
I finally realised that i can not see the button on my screen.
And ".check(matches(isCompletelyDisplayed()));" is failed.
As you can see on the above image, the only different is that my previous device has a bigger screen and it can show all things. (left image shows the small screen, and right shows the bigger one.)
The small screen cannot show the buttons.
So I decide to scroll it to show my button.
as "esspresso" mentions:
Note: scrollTo will have no effect if the view is already displayed so you can safely use it in cases when the view is displayed due to larger screen size (for example, when your tests run on both smaller and larger screen resolutions).
So I changed my code to:
onData(allOf(is(instanceOf(DeliveryVO.class)), hasProperty("deliveryReferenceId", is("1235")))) .perform(scrollTo(), click());
However this code is wrong. Because this button is not in a scrollable view directly. The button's parent does (the cell).
And People said onData() will do scroll for you, you don't have to do that.
So I am thinking if I do something on the second cell and espresso helps my to scroll to the second cell, and the buttons of the first cell are just above it so i my can have a chance to see it on the screen.
I forgot one thing to mention is that, incidentally, I successfully use onData() clicked a Label (it is out of the screen as well).
So I do onData() and perform(click()) for the second cell. Surprisedly It does the scrolling but it takes the whole screen without showing the first cell.
That explains the real reason of the error: onData() can scroll, but it will scroll the the top of the cell. if your cell is tooooo high, you will get this error, and you have no solution to solve it!!!!!
Scroll on the list view:
I decide to scroll it on the viewlist:
It works but i still get the error.
after checking the source code of click() in "android/support/test/espresso/action/ViewActions.class:125"
return actionWithAssertions(new GeneralClickAction(Tap.SINGLE, GeneralLocation.CENTER, Press.FINGER, rollbackAction));
it actually use a GeneralClickAction, in that class:
it means if you want to call click() on a button , you should make sure it is display at least 90 percent of it.
However, even I scroll and show it, it doesn't change the percentage value.
The reason is that if you take a look of perform() function in GeneralClickAction, it actually clicks a coordinates instead of clicking a UI component. the coordinates are like this:
119.5, 345.0 is the location of the button i want to click. the location is calculated by coordinatesProvider. However, my screen size is 240* 320, it will never be able to see "y = 345.0". Even I scroll, it will still click 345.0 which is still out side of my screen.
as above snapshots show, not matter I scroll the viewlist or not, the CoordinatesProvider gives the same result always.
So, back to GeneralClickAction, because the location is out of the screen, so it throws a exception:
So we need change this logic, however, GeneralClickAction is final:
So i have to create my own clickaction in my project by copying this class's source code.
change it as below:
Remove the displaying percentage limitation:
Make it better:
make your espresso code like this:
and add this function into your ClickAction.java: