UIAutomator click listview based on index - android

I'm trying to implement an UIAutomator testcase with a general method to perform a click on a ListView item (regardless of the type of viewgroup holding the listitem).
Currently I have following code, but it keeps on clicking the first item.
public void clickListViewItem(int index) throws UiObjectNotFoundException {
UiObject listview = new UiObject(new UiSelector().className("android.widget.ListView"));
if(index <= listview.getChildCount()){
listview.getChild(new UiSelector().index(index)).click();
}else{
throw new UIObjectNotFoundException("Index is greater than listSize");
}
}

I got it to work with following code, it is based on the clickable attribute of an UISelector:
listview.getChild(new UiSelector().clickable(true).index(index)).click();

The developer page implements a similar scenario, found here - although this assumes there is some identifying feature that exists in the child by which to select (like in example below, a string "Apps"):
If more than one matching element is found, the first matching element in the layout hierarchy is returned as the target UiObject. When constructing a UiSelector, you can chain together multiple properties to refine your search. If no matching UI element is found, a UiAutomatorObjectNotFoundException is thrown.
You can use the childSelector() method to nest multiple UiSelector instances. For example, the following code example shows how your test might specify a search to find the first ListView in the currently displayed UI, then search within that ListView to find a UI element with the text property Apps.
val appItem: UiObject = device.findObject(
UiSelector().className("android.widget.ListView")
.instance(0)
.childSelector(
UiSelector().text("Apps")
)
)

Related

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, clicking on a item at position

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.

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!

Appium, Android - Finding element inside another element

I am trying to check if element exist, but appium seems to ignore searching an element when we specified that it should be inside another element. For example:
driver.findElementByAccessibilityId("First element").findElementByAccessibilityId("Second element");
It should work somehow since there is option in Appium inspector called Locator where after selecting strategy and choosing search from selected element option it finds what I expect.
What is the proper way of finding such elements ?
You can use a xpath for the same. Sample xpath for the situation will be like :
driver.findElement(By.xpath("//*[#accessibility-id='FirstElement']//*[#accessibility-id='FirstElement']"))
The // between first element and second element indicates first element is the base element for start searching the second element. So it will search for the second element between the scope of the first element
Simple solution but not the cleanest below:
I am using TestNG framework which I suppose do not allow declarations such as
private WebElement element= driver.findElementByAccessibilityId("First element").findElementByAccessibilityId("Second element");
Simple solution but not the best is to declare only parents as:
#FindBy(name="Parent")
private WebElement ParentElement;
Then in test case for example:
ParentElement.findElement(By.name("childElement")).isDisplayed())
Put the first element as parent and second element as child -
MobileElement parentButtonList = (MobileElement)driver.findElementById(parentClassIdentifier);
List<MobileElement> childButtonList = parentButtonList.findElementsById(childClassIdentifier);

ListView with headers (LongListSelector) for Xamarin.Forms

I'm looking for a view known as LongListSelector on the Windows Phone. It's a list view with group headers. Tapping a group header displays only a list of groups. Tapping a group on the list of groups hides the list of groups and scrolls the view to the selected group. It's a very useful way of groupping long lists with easy navigation between groups. If there are alternatives fit for the same purpose that would be also great.
You can do this easily :)
The first thing you need to do is make sure your data source is a collection of collections. I would suggest an ObservableCollection> if you want maximum binding goodness. Then we can construct our listView as follows:
var listView = new ListView ();
listView.SetBinding (ListView.ItemsSourceProperty, "Data");
listView.ItemTemplate = new DataTemplate (typeof (MyCell));
listView.GroupHeaderTemplate = new DataTemplate (typeof (MyHeaderCell));
listView.IsGroupingEnabled = true;
listView.GroupShortNameBinding = new Binding ("Title");
In order, we first bind in our data, I am assuming the BindingContext here will be inherited from the page. Our data should be the collection of collections already mentioned.
Then we bind in our ItemTemplate as normal, we make a GroupHeaderTemplate, this will be the template shown in the list during normal scrolling. Next we enable grouping to tell the list to use the data as a grouped collection rather than a flat list.
Finally with all that done, we provide a binding for the GroupShortName. This binding is run against the collection for each group to grab out a string (or an object that will have ToString called on it) to produce the jump list as you showed in your screenshots.
For performance reasons you may want to ensure the ItemsSource is not set until everything else has been set to avoid the ListView attempting to realizing Cells in a partially configured state. This will not actually result in bugs, it just forces the ListView to do more work.

Categories

Resources