onChildView and hasSiblings with Espresso

18,989

Solution 1

Based on your last comment you should use onView() instead of onData(). I think you'll be able to click the button using hasSibling() - example

onView(allOf(withId(R.id.positive), hasSibling(withDesc(someString))))
    .perform(click());

or examples without your custom matcher (sibling view has text):

onView(allOf(withId(R.id.positive), hasSibling(withText(someString))))
    .perform(click());

or (sibling view has content description):

onView(allOf(withId(R.id.positive), hasSibling(withContentDescription(someString))))
    .perform(click());

EDITED:

OK, I'd try these two variants:

onView(allOf(withId(R.id.increaseGoalButton), isDescendantOfA(withId(R.id.timeGoalWidget))))
    .perform(click());

or

onView(allOf(withId(R.id.increaseGoalButton), withParent(withId(R.id.timeGoalWidget))))
    .perform(click());

Solution 2

None of your content descriptions match the string "description" that's why it doesn't find anything.

Share:
18,989
Chad Bingham
Author by

Chad Bingham

Arguing with a software engineer is like wrestling with a pig in the mud; after a while you realize the pig likes it. -Unknown

Updated on July 21, 2022

Comments

  • Chad Bingham
    Chad Bingham over 1 year

    I am trying to access a button from a specific view. The same view is displayed 6 times. This is the code I am using.

    public void testTimeConfig(){
        onData(withDesc("description")).onChildView(withId(R.id.positive)).perform(click());
    }
    
    private static Matcher<Object> withDesc(String desc) {
        return allOf(is(instanceOf(String.class)), is(desc));
    }
    

    When I run, I get an error:

    Error performing 'load adapter data' on view 'is assignable from class: class android.widget.AdapterView'.

    Is this the best way to access a child view? If so, how?

    EDIT

    This is the code I am trying to use now.

       onView(allOf((withContentDescription("description")), hasSibling(withContentDescription("SettingsLayout")), hasSibling(withId(R.id.positive)))).perform(click());
    

    and

       onView(allOf((withContentDescription("description")), hasSibling(withId(R.id.positive)))).perform(click());
    

    With this Error:

       No views in hierarchy found matching
    

    The xml

        <view
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/setAGoalTitle"
            android:layout_alignParentLeft="true"
            class="com.xxx"
            android:layout_marginTop="30dp"
            android:id="@+id/timeGoalWidget"
            app:goalLabel="@string/time_min_upper"
            app:icon="@drawable/ic_icn_summary_time"
            app:step="300"
            app:valueFormat="time"
            android:gravity="center_horizontal"
            android:layout_marginBottom="60dp"
            android:contentDescription="setAGoalTimeConfigurator"/>
    
        <view
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignTop="@id/timeGoalWidget"
            class="com.xxx"
            android:id="@+id/distanceGoalWidget"
            app:goalLabel="@string/distance_upper"
            app:icon="@drawable/ic_icn_summary_track"
            app:step="0.25"
            app:valueFormat="decimal_two"
            android:gravity="center_horizontal"
            android:contentDescription="setAGoalDistanceConfigurator"/>
    
        <view
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/timeGoalWidget"
            android:layout_alignLeft="@id/timeGoalWidget"
            class="com.xxx"
            android:id="@+id/paceGoalWidget"
            app:goalLabel="@string/pace_upper"
            app:icon="@drawable/ic_icn_summary_pace"
            app:valueFormat="time"
            app:step="10"
            android:gravity="center_horizontal"
            android:layout_marginBottom="60dp"
            android:contentDescription="setAGoalPaceConfigurator"/>
    
    
        <view
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignRight="@id/distanceGoalWidget"
            android:layout_alignTop="@id/paceGoalWidget"
            class="com.xxx"
            android:id="@+id/speedGoalWidget"
            app:goalLabel="@string/speed_upper"
            app:icon="@drawable/ic_icn_summary_speed"
            app:step="0.5"
            app:valueFormat="decimal_two"
            android:gravity="center_horizontal"
            android:contentDescription="setAGoalSpeedConfigurator"/>
    
    
        <view
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/paceGoalWidget"
            android:layout_alignLeft="@id/paceGoalWidget"
            class="com.xxx"
            android:id="@+id/inclineGoalWidget"
            app:goalLabel="@string/incline_percent_upper"
            app:icon="@drawable/ic_icn_summary_elevation"
            app:step="0.5"
            app:valueFormat="decimal_two"
            android:gravity="center_horizontal"
            android:contentDescription="setAGoalInclineConfigurator"/>
    
    
        <view
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignRight="@id/speedGoalWidget"
            android:layout_alignTop="@id/inclineGoalWidget"
            class="com.xxx"
            android:id="@+id/caloriesGoalWidget"
            app:goalLabel="@string/calories_upper"
            app:icon="@drawable/ic_icn_summary_calories"
            app:step="10"
            app:valueFormat="decimal_zero"
            android:gravity="center_horizontal"
            android:contentDescription="setAGoalCaloriesConfigurator"/>
    
    
    </RelativeLayout>
    

    The view xml that is used 6 times.

    <ImageButton
        android:id="@+id/increaseGoalButton"
        android:layout_height="@dimen/view_goal_setting_incrementor_button_height_width"
        android:layout_width="@dimen/view_goal_setting_incrementor_button_height_width"
        android:background="@drawable/button_goal_widget"
        android:gravity="center"
        android:src="@drawable/ic_plus"
        android:textSize="@dimen/view_goal_setting_incrementor_button_text_size"
        android:textColor="@color/goal_configuration_widget_button_text_color"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginBottom="1dp"
        android:contentDescription="@string/increase"/>
    
    <ImageButton
        android:id="@+id/decreaseGoalButton"
        android:layout_height="@dimen/view_goal_setting_incrementor_button_height_width"
        android:layout_width="@dimen/view_goal_setting_incrementor_button_height_width"
        android:background="@drawable/button_goal_widget"
        android:gravity="center"
        android:src="@drawable/ic_minus"
        android:textSize="@dimen/view_goal_setting_incrementor_button_text_size"
        android:layout_alignParentRight="true"
        android:textColor="@color/goal_configuration_widget_button_text_color"
        android:layout_below="@id/increaseGoalButton"
        android:contentDescription="@string/decrease"/>
    
    <LinearLayout
        android:id="@+id/goalWidgetValueContainer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_toLeftOf="@id/increaseGoalButton"
        android:layout_centerVertical="true"
        android:gravity="center_vertical|right"
        android:layout_marginRight="@dimen/view_goal_setting_value_margin_right" >
    
        <TextView
            android:id="@+id/goalValueTextView"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:textColor="@color/goal_configuration_widget_value_text_color"
            android:textSize="@dimen/view_goal_setting_value_text_size"
            android:lineSpacingExtra="-10sp"
            app:typeface="proxima_bold"
            android:text="999:00"/>
    
        <TextView
            android:id="@+id/goalValueLabelTextView"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            android:layout_gravity="right"
            android:textSize="@dimen/view_goal_setting_value_label_text_size"
            android:textColor="@color/goal_configuration_widget_value_text_color"
            android:includeFontPadding="false"
            android:lineSpacingExtra="10sp"
            android:text="@string/incline_percent_upper"/>
    
    </LinearLayout>
    

    It is the ImageView with id increaseGoalButton that I am trying to click.

  • Chad Bingham
    Chad Bingham over 10 years
    These three examples are all the same
  • denys
    denys over 10 years
    There are 3 cases: 1st with custom matcher, 2nd for a view with text and 3rd for a view with content description. Does any of them work for you?
  • Chad Bingham
    Chad Bingham over 10 years
    Sorry, I was looking at them on my phone and all I got was onView(allOf(withId(R.id.positive) so they all looked the same. I will play around with this and see if it works
  • Chad Bingham
    Chad Bingham over 10 years
    +1 for mentioning hasSbiling(). Do you know if it matters if the view is inside a RelativeLayout, inside the parent RelativeLayout? So it is two children deep?
  • denys
    denys over 10 years
    Take a look at source code for hasSibling() matcher - link. Seems that they must be in the same parent. Can you also post your layout xml file, since it's hard to judge without it.
  • Chad Bingham
    Chad Bingham over 10 years
    Ok I posted the xml. Take a look. Sorry for the delay. I had to edit it so I am not showing sensitive information.
  • Chad Bingham
    Chad Bingham over 10 years
    Is the com.xxx needed?
  • denys
    denys over 10 years
    No, I just took it from your example. You should replace it with your real package name which you changed to com.xxx in above xml code.
  • Chad Bingham
    Chad Bingham over 10 years
    Right. I am wondering if the com.package is need at all. Right now I am just using R.id. without the com.xx
  • Chad Bingham
    Chad Bingham over 10 years
    hasParent did not work. isDescendantOfA` does. Thanks.
  • lacton
    lacton over 9 years
    hasParent does not exist. There is a withParent method instead.
  • Ruwanka Madhushan
    Ruwanka Madhushan almost 7 years
    +1 for onView(allOf(withId(R.id.increaseGoalButton), isDescendantOfA(withId(R.id.timeGoalWidget)))) .perform(click());