Espresso, clicking on a item at position - android

I'm trying to click on a item at a specific position in a grid view.
onData(instanceOf(MyClass.class))
.inAdapterView(withId(R.id.my_view))
.atPosition(R.integer.my_id)
.perform(click());
but I'm getting this java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
I'm queuing the responses using MockWebServer, even after the UI is on screen with all the list item, I'm getting this error, I'm not sure why.
Also, I want to get the content of the specific item.

Well, I think that's because you're matching class which is only one, not a specific adapter with values.
Please consider this post:
The matcher passed as argument to onData() must match the value as
returned by Adapter.getItem(). So the first version doesn't match,
because of the wrong type being used. It should be:
onData(is(instanceOf(IconRowAdapter.IconRow.class)))
What also can be a pitfall is using equalTo on different kinds of
CharSequences. String is a CharSequence, but if IconRow.getText()
returns CharSequence instead of String, then this can also be
Spannable, Editable, etc in which case equalTo wouldn't match. So if
IconRow.getText() return anything but String, make sure to convert it
into a String before comparison.
This post was taken from How to use Espresso to test item in adapter at a specific position
Your question lacks of code of tested class, so I cannot give you direct answer. I can only recommend to read StackOverflow link above.
Hope it help

You may need to "drill down" a little deeper into the view hierarchy to get to the item in the cell. Put an additional method call before the ".perform" using the id of the item in the grid cell
onChildView(withId(R.id.???)).perform(click());
Use the id of the view that the user would click on.

Related

FindViewWithTag on RecyclerView (AppCompat)

To use ActivityOptionsCompat.MakeScaleUpAnimation(), I need access to the View from where the animation originates. I use MvvmCross, so I need to pass via a MvxFragmentsPresenter (shouldn't be relevant to the problem). A ViewModel request can contain key/value parameters. So I attach a Tag to each RecyclerView item and then pass on that Tag as a parameter in the ViewModel request, as done here. I can access this tag in the presenter.
Now inside the presenter I need to find the RecyclerView item that was clicked. I want to do this as follows:
View contentFrame = Activity.FindViewById(Resource.Id.content_frame);
View recyclerView = contentFrame.FindViewById(Resource.Id.recycler_view);
View item = recyclerView.FindViewWithTag("mytag");
Unfortunately this results in null. I can access the contentFrame and the recyclerView, but not an item by Tag. However I can even get the first item using:
recvddfg.GetChildAt(0);
... and access the Tag! So it's strange that FindViewWithTag isn't working. Does anyone have an idea?
After searching for hours, I decided to post this question. Then looked back at it and found the cause: I was searching for an item with a tag of type string, while I should have been searching for a number... You can use any type you want with a Tag, so in your case it might be different if you have the same problem. You just need to be consistent.

Find multiple elements in web view with espresso

I'm testing a hybrid app, where each view has a web view.
In one of these web views I have a list of elements with the same attribute. They have the same xpath locator that is something like:
//h4[contains(#data-role, 'product-name')]
I want to create a list of these elements and iterate through them, count them, get their attributes.
In the documentation, I found two similar methods:
findElement(locator, value)
and
findMultipleElements(locator, value)
Though it's totally unclear to me how to use it. I tried to find examples on it but with no success.
Could someone help me with this?
Here is the solution that I have found.
#kaqqao is right that findMultipleItems call returns Atom<List<ElementReference>> that is not usable with onWebView() because there you have only withElement() that accepts either Atom<ElementReference> or just ElementReference
What you can do though is perform your action that find multiple items and just get results from your Atom. This is how it works internally if you check the source of doEval method inside Web.java for espresso.
val elements = with(AtomAction(findMultipleElements(
Locator.XPATH,
"YOUR_COMPLEX_XPATH"
), null, null)) {
onView(ViewMatchers.isAssignableFrom(WebView::class.java)).perform(this)
this.get()
}
This code will give you List<ElementMatcher>.
Then just run it as
elements.forEach {
onWebView().forceJavascriptEnabled().withElement(it).perform(webClick())
}
Can you try something like that? Since what you should care about is really the ElementReference and you can iterate the lsit returned from findMultipleElements with simple for/foreach statement:
yourList = findMultipleElements(locator, value);
yourList.size(); //this will get you the count of found elements with that locator
for(Atom<ElementReference> item : yourList ){
item.getAttribute...
//and whatever you want
}

Espresso - check if the TextView exists in the ListView

I want to check displaying of Save €XX in the list. Save €XX is a TextView that can be VISIBLE or INVISIBLE. I use JUnit 4 and Espresso 2.2.1.
I tried to check it like this:
onView(withText(startsWith("Save"))).check(matches(isDisplayed()));
but always get an error:
android.support.test.espresso.AmbiguousViewMatcherException: 'with text: a string starting with "Save"' matches multiple views in the hierarchy.
Is there a way to if the TextView exists in the ListView with Espresso?
UPDATE
I also tried to use onData:
onData(hasToString(startsWith("Save")))
.inAdapterView(withId(R.id.suggestion_list_view)).atPosition(0)
.check(matches(isDisplayed()));
but it seems that onData works with data layer but not the view layer. Therefore, I receive the error:
java.lang.RuntimeException: No data found matching: with toString() a string starting with "Save" contained values: <[Data: ...]>
After several tries, I found the way.
In this case, we should use a combined approach and work with both data and view layers. We access the ListView by ID and choose the first item. Then check it for the 'Save' text.
onData(anything())
.inAdapterView(withId(R.id.list_view))
.atPosition(0)
.onChildView(withId(R.id.suggestion_saving))
.check(matches(withText(startsWith("Save"))));
Works like a charm. Enjoy!

Hard/Fast fling using the swipe to dismiss library and a ContentProvider shows the wrong item

I have been developing an app that has a listview in which items may be removed by the user.
Now I have been trying to use the swipe to dismiss library in my project, by Roman Nurik: https://github.com/romannurik/Android-SwipeToDismiss.
I've successfully implemented a button which removes a row (click), however I am unable to use the swipe to dismiss functionality of the library (swipe). This is all because of the canDismiss check I need to do.
I have a cursor (see ContentProvider and LoaderCallbacks) which I was trying to iterate over and use to determine if a row can be dismissed. However this does not seem to work, 'cause when I fling fast/hard it displays the second to last row twice (it's normal position and the last position) and it does the same thing for the first and second rows.
Has anyone ever done something similar? And how did you solve this issue?
My code:
Cursor cursor = (Cursor) mAdapter.getItem(position);
if (cursor.getInt(Card.CARD_REMOVABLE_COLUMN_INDEX) == 1) {
return true;
}
But everytime I try to use the cursor, the issue seems to appear.
Alright, I guess there is no good solution, other than fetching the required information from the view(s) itself. Unlike with web development, getting the information from the database all the time, is not an option.
I guess you could get the information from the viewtag if you would so desire. I've done something different, using the position I get from the library, I lookup the row in the listview, and check if certain views are visible (every row can be removable, hence they all have the same header(s), I check if a header is visible or not, and handle this).

Lifecycle of calls when using the SimpleCursorAdapter.setViewImage

OK, trying to get images from my SD card to show in an activity ListView.
I'm reading lots of hints, but I'm missing an important chunk. I'd love to see a short-ish bit of source code that illustrates this, haven't found anything yet.
From my research it sounds like bindview() is called when listview.setadapter(SimpleCursorAdapter adapter) is executed. The documentation says that setImageView is called by bindview if the ViewBinder cannot handle an ImageView.
You specify the field in the FROM array, the id of the TextView in the TO array, the Cursor, and the view group with the TextView. Then set the adapter to the ListView and voila, it happens.
I think the call sequence is then:
listView.setAdapter(SimpleCursorAdapter adapter)->adapter.bindView()->adapter.setTextView
Bindview must determine the view is of type TextView, determine that it can bind it, passes theTextViewand text value from the cursor andsetTextView` does its thing.
So, that makes the call for an ImageView very similar, right?
listViw.setAdapter(SimpleCursorAdapter adapter)->adapter.bindView()->adapter.setImageView
So when bindView comes across and object of type ImageView, what does it do? Is there a default implementation like in setTextView? I'd imagine it would be hard to do that, images vary so much. Text is text, but images have formats, sizes, depths, scale, LOCATIONS, etc, etc. The string passed to the setTextView IS the text, the payload. In an image the string is (probably) the filename, only the starting point of an image.
I think I'll need to build my adapter with the database column name that holds the filename in FROM. The TO array will have just the id of the ImageView in my layout. I think I can use the default viewbinder bindview(), but will have to override setImageView() to take the expected string (filename), and build out the image loading lines to find that image name in the expected application path.
So that will be (maybe):
listView.setAdapter(MyOwnSimpleCursorAdapter myOwnAdapter)->myOwnAdapter.super.bindView()->myOwnAdapter.setImageView()
Does this sound right? If anyone can fill in the missing gaps and/or provide some working source code it would help a lot. By the way, I've written code to do this, but it isn't working. It could be a very simple bug and don't want to stop this thread if it's do-able. I think I just need a little nudge in the right direction.
I don't quite understand what is your question(and yes, you should post the failing piece of code) so here is my answer(you can also see this in the source code of the SimpleCursorAdapter):
In a SimpleCursorAdapter when the ListView requires a new View to be shown the method getView() will be called. This methods delegates the row building to 2 methods: newView()(which will create the View(inflating the xml layout you've set) and set as a tag an array of the Views with the ids from the to array) and bindView()(which will actually bind the data to the View created by newView()).
bindView() will then iterate through the arrays of Views(the Views with the ids from the to array) on which to bind the data. It will also call getString(and only the getString method, this is important) from the cursor to get the data. Next the method checks if a ViewBinder has been set on the adapter, if this is the case it will let that ViewBinder to set the data(the methods setTextView() and setImageView() will not be called if the ViewBinder successfully binds the data).
If a ViewBinder wasn't set on the adapter or the setViewValue method of the ViewBinder returns false(meaning the ViewBinder has failed) then the bindView() method will check and see which type of View it is dealing with(TextView or ImageView) and call either setViewText() or setViewImage().
The implementation of the setViewImage() will try to parse the supplied String as an int (example: an image id R.drawable.image) and if this fails it will then parse the String as an Uri and use setImageUri() on the ImageView. So an int like R.drawable.image or a String like "file://mnt/sdcard/photo100.jpg" should work with the default implementation of the SimpleCursorAdapter, otherwise override the setImageView.

Categories

Resources