Espresso perform click on view in Recyclerview item - java

I tried everything to perform click on view in recyclerview item but not succesfull. Read every option on internet and tried it but still not working. Lately I used:
onView(ViewMatchers.withId(R.id.live_rw_liveMatchList))
.perform(RecyclerViewActions.actionOnItemAtPosition(2, MyViewAction.clickChildViewWithId(R.id.pick_pw_pickLeft)));
But all i get is:
android.support.test.espresso.AmbiguousViewMatcherException: 'with id:
hr.psk.android:id/ticket_list_list' matches multiple views in the
hierarchy. Problem views are marked with '****MATCHES****' below.
And it matches only one view (my recyclerview with 13 childs)
I know this should work but it is not working in my project. Tried to perform only click on recyclerviw item in other recyclerview to make it more simple like this:
onView(withId(R.id.ticket_list_list))
.perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
But it gives me the same message back -> Multiple matches problem
somebody help, I really tried everything

onView(withId(R.id.ticket_list_list))
.perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
The error you're getting means that there's another View somewhere that also uses the id ticket_list_list
Is ticket_list_list your actual list view? (the parent of the things that you want to click)
If it is then is it the only one available on the screen? if it is then use the following
onView(allOf(withId(R.id.ticket_list_list), isDisplayed()))
.perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
Adding the isDisplayed() Matcher makes the targeted View more specific by targeting only those that are displayed and ignoring those that are existing but not displayed
If there really is another matcher displayed (or the above doesn't work for you) that has the same id as the one you're trying to match then use the following
onView(allOf(withId(R.id.ticket_list_list), withParentIndex(index_of_matcher_here)))
.perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
Instead of isDisplayed() withParentIndex(some_number) should more specifically target and give you the view that has the id you're looking for along with the index of it
In the very messy instance that the above still doesn't work, maybe because all the returned Views have the same index possibly because they are the children of another View then you can get creative and do something like
onView(allOf(withId(R.id.ticket_list_list), withParent(allOf(withId(if_of_the_parent), withParentIndex(index_of_matcher_here)))))
.perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
to specify the index of the parent instead.
Just mix 'n match your way through it, just make sure to not go crazy on the Matchers and just keep things readable
Use as little as you can (make sure it's readable and maintainable too and not just made up of indexes), you're not trying to get the coordinates for a missile target- you just want the View

I also face the same problem before few days but finally got the solutions from StackOverflow.
If you want to click recycler custom item view click then implement the following code in your project
You need to write this code in java this will help you a lot and saved your time
ClickOnButtonView is control a view action happened in the list item and
UiController class helps you find custom row item
The code is written in Kotlin
#RunWith(AndroidJUnit4::class)
class CampaignFragmentTest {
#get: Rule
val activityTestRule = ActivityTestRule(TestActivity::class.java)
#Test
fun testCustomListClick() {
clickOnButtonAtRow(0)
}
}
private fun clickOnButtonAtRow(position: Int) {
Espresso.onView(ViewMatchers.withId(R.id.list)).perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>
(position, ClickOnButtonView()))
}
inner class ClickOnButtonView : ViewAction {
internal var click = ViewActions.click()
override fun getConstraints(): Matcher<View> {
return click.constraints
}
override fun getDescription(): String {
return " click on custom button view"
}
override fun perform(uiController: UiController, view: View) {
//btnClickMe -> Custom row item view button
click.perform(uiController, view.findViewById(R.id.btnClickMe))
}
}

That error means that it found multiple views with the id R.id.ticket_list_list. There should also be a view hierarchy log that follows the error message you provided, showing the views that Espresso found with that same id marked with ****MATCHES****.
So you can either change the id of the view you want to test or target the view by providing another ViewMatcher as below:
onView(allOf(withId(recyclerViewID), viewMatcher))
.perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));

You Can also create your own custom click action like this :
fun customActionClickOnItemEvent(
#NonNull targetViewId: Int
): ViewAction {
return object : ViewAction {
val click = ViewActions.click()
override fun getDescription(): String = "Item clicked"
override fun getConstraints(): Matcher<View> = click.constraints
override fun perform(uiController: UiController?, view: View?) {
click.perform(uiController,view?.findViewById(targetViewId))
}
}
}
And Calling this function like this :
onView(withId(R.id.rv_products)).perform(
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
1,
customActionClickOnItemEvent(R.id.img_wish_list)
)
)

Related

Get TreeViewer in RCP from another Plugin

I'm working at a Plugin for a Eclipse-RCP. There is another Plugin with a TreeViewer and I want to select an Item from my Plugin. I don't know how to get access it, is this even possible?
I think can get the correct view with:
IViewReference home;
IViewReference [] viewRefs = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getViewReferences();
for (int i = 0; i < viewRefs.length; i++) {
if(viewRefs[i].getId()==myid){
home = viewRefs[i];
break;
}
}
But home is not a TreeViewer and I cant cast it. How can I get the TreeViewer?
home.getTreeViewer() //Doesn't work cause of casting issues
I am a newbie to rcp, so I would be nice for some explanation.
You need to find your view using:
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
IViewPart viewPart = page.findView("your view id");
You can then cast the view part to your view class and call a method that you write on that class:
if (viewPart != null) {
MyViewClass myViewPart = (MyViewClass)viewPart;
myViewPart.getTreeViewer();
}
where MyViewClass is your ViewPart class. You will have to write the getTreeViewer method.
If the view is not currently open you can use showView:
viewPart = page.showView("your view id");
You have to cast home to the type of your other view. Then you can get the TreeViewer.
You can find the ViewPart directly from your active IWorkbenchPage using IWorkbenchPage#findView(java.lang.String).
If you have the object you want to be selected, get the View's Site, get the Site's selection provider, and then tell the selection provider what should be selected (with a StructuredSelection instance containing the object). This only works if the tree, or whatever is in the part (you shouldn't have to care or know that it's a tree), actually contains the object that you're telling it to select.

Android - RecyclerView with one layout, multiple setVisibility

I have a basically all in one layout which has everything needed for my app's main feed. All variable items (images, video thumbnails.. Etc.) are set to GONE at first and set to VISIBLE when it is needed.
The problem is sometimes, might be due to RecyclerView's recycling behavior, the item which is supposedto be GONE is VISIBLE in the wrong places.
Example :
Item no 1 contains Text
Item no 2 contains Image
Item no 3 contains Image
I keep scrolling down to item no x, then scroll back up and here's what I get :
Item no 1 contains Image from item no x, sometimes item no 3
Item no 2 contains Image
Item no 3 contains Image
I'm using a custom ViewHolder which extends RecyclerView.ViewHolder.
The purpose of the CustomViewHolder is for layout declaration and initialization.
ProgressBar progressBar;
View viewDimmer;
RelativeLayout postListWrapper;
...
public ObjectViewHolder(View v) {
super(v);
progressBar = (ProgressBar)v.findViewById(R.id.post_inscroll_progressBar);
viewDimmer = (View)v.findViewById(R.id.post_inscroll_viewDimmer);
postListWrapper = (RelativeLayout)v.findViewById(R.id.post_inscroll_postListWrapper);
}
An example of how I load the image :
Picasso.with(context)
.load(youtubeThumbnailUrl)
.fit()
.centerCrop()
.into(
((ObjectViewHolder) holder).userPostYoutubeImage
);
I've set each visibility to GONE if no url is obtained from the server
((ObjectViewHolder) holder).userPostImageWrapper.setVisibility(View.GONE);
((ObjectViewHolder) holder).userPostYoutubeImageWrapper.setVisibility(View.GONE);
But somehow the image is still reused on the previous items (yes, not only Item no 1). Sometimes image are also in the wrong ImageView. Image D is supposed to be in ImageView D, but it's in ImageView A instead.
Any guide for setting RecyclerView up and going nicely?
If I miss anything, or need to supply more code, please do inform me :D
You need to put the else condition too. Like the example below.
// if no url is found from server
if(url == null){
((ObjectViewHolder) holder).userPostImageWrapper.setVisibility(View.GONE);
((ObjectViewHolder) holder).userPostYoutubeImageWrapper.setVisibility(View.GONE);
} else {
// Some url has found
((ObjectViewHolder) holder).userPostImageWrapper.setVisibility(View.VISIBLE);
((ObjectViewHolder) holder).userPostYoutubeImageWrapper.setVisibility(View.VISIBLE);
}
Do this for each of the items you've got there as the list item in case of you're setting their visibilities in runtime.
All your if conditions in onBindViewHolder() must have an else block too.
Don't leave any if condition without else. You can provide a default behaviour in the else block when if condition becomes false.

Set Canvas to Eclipse View?

I've created an (empty until now) View in my Eclipse Plugin. I'm also using Eclipse Cloudio. This library provides the following object (description taken from the linked site):
A TagCloud is a special org.eclipse.swt.widgets.Canvas, dedicated to display a tag cloud.
Basically it's an image showing a WordCloud. Now there are snippets on the site on how to show such TagClouds in a shell / popup.
But I'd like to show them in a view (this function is supposed to be used often and I think it's bad style to spam popup-windows).
What I do not know tho is how to set this TagCloud (which is a Canvas) to the View / make the View display the Canvas. Maybe someone can help me with this?
Edit:
gregs Answer works like a charm! It just needs another setWords() function which is called from where-ever which contains .setWords to set the words when neccessary.
You just need to add the control to the view in the view createPartControl. At the simplest that would be:
#Override
public void createPartControl(final Composite parent)
{
TagCloud cloud = new TagCloud(parent, SWT.NONE);
... set up the cloud as in the example
}

Robotium - Trying to click home button in app

I'm new to robotium and i'm trying to write a quick and dirty script to run through all screens in an app.
The problem i have mainly with the 'home button' in the app. I've tried lots of options but i cant seem to get it to click there except with index, which is not what i want.
When i check out the button with the hierarchyviewer it looks like this:
Link
However when i try for example:
assertTrue(
"Wait for text (id: myapp.R.id.home) failed.",
solo.waitForImageById("myapp.R.id.home", 20000));
solo.clickOnImage((ImageView) solo.findViewById("myapp.R.id.home"));
solo.waitForActivity("MenuActivity");
It fails at the waitForImageByID line. Ive tried multiple options like waitForImageButton etc, but i just cant seem to get it clicked. What am i missing here?
junit.framework.AssertionFailedError: View with id: '0' is not found!
at com.jayway.android.robotium.solo.Solo.getView(Solo.java:1990)
at com.jayway.android.robotium.solo.Solo.getView(Solo.java:1970)
at com.bitbar.recorder.extensions.OtherUtils.a(OtherUtils.java:246)
at com.bitbar.recorder.extensions.OtherUtils.b(OtherUtils.java:241)
at com.bitbar.recorder.extensions.v.a(Waiter.java:71)
at com.bitbar.recorder.extensions.ExtSolo.waitForImageButtonById(ExtSolo.java:4176)
at com.example.android.apis.test.Test.testRecorded(Test.java:137)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:214)
at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:199)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:554)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1740)
Use the following line to press the home button in the action bar
solo.clickOnActionBarHomeButton();
The issue is that the id that it is referring is not in your application, it is in androids default R file, try android.R.id.home and it should work fine. It is worth noting though that if your application uses action bar sherlock to support the action bar pre 4.0 that this will have a different ID there and you will have to handle this in your test.
You can see this for yourself looking at: http://developer.android.com/reference/android/R.id.html
When you are using ActionBarSherlock there are two different Ids you have to check, android.R.id.home for API-Level>11 and abs__home for lower levels (provided by ActionBarSherlock):
View homeButton = activity.findViewById(android.R.id.home);
if (homeButton == null) {
homeButton = activity.findViewById(R.id.abs__home);
}
What about this code:
ArrayList<LinearLayout> ll = solo.getCurrentViews(LinearLayout.class);
//You can change 1 with the ordinal number of LinearLayout you want to click.
solo.clickOnView(ll.get(1));
or also
ArrayList<ImageView> iv = solo.getCurrentViews(ImageView.class);
//You can change 0 with the ordinal number of Image you want to click.
solo.clickOnView(iv.get(0));
I think if you identify the correct id for view or linear layout or image view it should work.
Dave C's answer was working only partially for me. The button was clicked but before the preceding screen was loaded assertions had started and thus were always false. The solution is to run "home click" on the main thread (Robotium 5.2.1):
getInstrumentation().runOnMainSync(new Runnable() {
#Override
public void run() {
solo.clickOnActionBarHomeButton();
}
});
From your question I can see that it is an image view. You can click on any view using the following piece of code.
View view = solo.getView("View_name_from_hierachy_viewer");
solo.clickOnView(view);
View_name_from_hierachy_viewer in your case will be "home".
Let me know if this does not work.

Eclipse (XText) SelectionListener registration

I have implemented a view which shall register itself as listner for changes in the XText editor and related outline. To this end I am adding this line
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().addSelectionListener(this);
in the createPartControl method of the view (which implements the ISelectionListener interface). In the selectionChanged method I therefore check whether the selection is a ITextSelection, the case in which it comes from the XTextEditor, or an IStructuredSelection, the case in which it come sfrom the Outline.
The problem is that, doing so, when I start Eclipse the outline is said to be "unavailable". If I click on the outline it is refreshed, the contents are shown and the listening view correctly updated.
What am I doing wrong and what should I do to avoid the initial "unavailability" of the outline?
I have been recently faced with this exact problem and have solved it by implementing IPartListener2 in the class that extends ViewPart then adding a part listener in the createPartcontrol method like this :
getSite().getWorkbenchWindow().getPartService().addPartListener(this);
Now by using something like this in your partOpened method (that has to be implemented before you can actually use the part listener you will get the view contents to be avaiable initially :
public void partOpened(IWorkbenchPartReference partRef) {
if(partRef.getPage().getActiveEditor() instanceof XtextEditor) {
somepart=partRef.getPage().getActiveEditor();
final XtextEditor editor = (XtextEditor)somepart;
final IXtextDocument document = editor.getDocument();
document.readOnly(new IUnitOfWork.Void<XtextResource>(){
public void process (XtextResource resource) throws Exception {
IParseResult parseResult = resource.getParseResult();
if(parseResult ==null)
return;
CompositeNode rootNode=(CompositeNode) parseResult.getRootNode();
LeafNode node = (LeafNode)NodeModelUtils.findLeafNodeAtOffset(rootNode, 0);
EObject object =NodeModelUtils.findActualSemanticObjectFor(node);
view.setInput(object);
}
});
}
}
this will make the view you're implementing get it's contents when you activate the XtextEditor (that is specific to your DSL).
In order to make the view change contents in real time as you change anything in the file active in the editor you should implement an IDocumentListener and override the DocumentChanged method. If you do this you won't be dependant on the SelectionListener anymore because the view should update automatically when something changes in your document
Hope this helps!

Categories