एस्प्रेसो का उपयोग रिसाइक्लर व्यू आइटम के अंदर देखने के लिए क्लिक करें


100

मैं एक पुनर्नवीनीकरण आइटम के अंदर एक विशिष्ट दृश्य पर क्लिक करने के लिए एस्प्रेसो का उपयोग कैसे कर सकता हूं ? मुझे पता है कि मैं स्थिति 0 पर आइटम का उपयोग कर क्लिक कर सकता हूं:

onView(withId(R.id.recyclerView)) .perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));

लेकिन मुझे उस आइटम के अंदर एक विशिष्ट दृश्य पर क्लिक करने की आवश्यकता है, न कि आइटम पर ही।

अग्रिम में धन्यवाद।

- संपादित करें -

अधिक सटीक होने के लिए: मेरे पास एक RecyclerView ( R.id.recycler_view) है जो आइटम CardView ( R.id.card_view) हैं। प्रत्येक कार्ड व्यू के अंदर मेरे चार बटन होते हैं (अन्य चीजों के बीच) और मैं एक विशिष्ट बटन पर क्लिक करना चाहता हूं (R.id.bt_deliver ) ।

मैं एस्प्रेसो 2.0 की नई विशेषताओं का उपयोग करना चाहूंगा, लेकिन मुझे यकीन नहीं है कि यह संभव है।

यदि संभव नहीं है, तो मैं कुछ इस तरह का उपयोग करना चाहता हूं (थॉमस केलर कोड का उपयोग करके):

onRecyclerItemView(R.id.card_view, ???, withId(R.id.bt_deliver)).perform(click());

लेकिन मुझे नहीं पता कि प्रश्नवाचक चिन्ह लगाना क्या है।


चेक इस
Skizo-ozᴉʞS

1
नमस्ते, त्वरित उत्तर के लिए टैंक! :-) मैंने वह प्रश्न देखा है, लेकिन मैं क्या चाहता हूँ, यह करने के लिए RecyclerViewActions का उपयोग करने के बारे में कोई मदद नहीं मिल सकती है । क्या मुझे पुराने उत्तर का उपयोग करना चाहिए ? धन्यवाद।
फ़िलिप रामोस

क्या आपको अपनी समस्या का कोई हल मिल गया है?
होवी एचएच

1
@HowieH: नहीं। मैंने हार मान ली, और अब मैं रोबोटियम का उपयोग कर रहा हूं ...
फिलिप रामोस

जवाबों:


136

आप इसे कस्टमाइज़्ड व्यू एक्शन के साथ कर सकते हैं।

public class MyViewAction {

    public static ViewAction clickChildViewWithId(final int id) {
        return new ViewAction() {
            @Override
            public Matcher<View> getConstraints() {
                return null;
            }

            @Override
            public String getDescription() {
                return "Click on a child view with specified id.";
            }

            @Override
            public void perform(UiController uiController, View view) {
                View v = view.findViewById(id);
                v.performClick();
            }
        };
    }

}

फिर आप इसे क्लिक कर सकते हैं

onView(withId(R.id.rv_conference_list)).perform(
            RecyclerViewActions.actionOnItemAtPosition(0, MyViewAction.clickChildViewWithId(R.id. bt_deliver)));

2
मैं अशक्त जांच को हटा दूंगा, ताकि अगर बच्चे को देखने के लिए कोई अपवाद न मिले तो चुपचाप कुछ न करें।
अल्वारो गुटिरेज पेरेस

जवाब के लिए धन्यवाद। लेकिन एक समस्या में मारा। OnPerform () फ़ंक्शन में, यदि मैंने onView (withId ()) फ़ंक्शन का उपयोग किया है, तो फ़ंक्शन मारा जाता है। इस व्यवहार का कारण क्या है?
thedarkpassenger

3
एस्प्रेसो के साथ काम करता है: एस्प्रेसो-कंट्रीब: 2.2.2 लेकिन 2.2.1 के साथ कोई कारण नहीं? मेरे पास कुछ निर्भरता हैं क्योंकि मैं 2.2.2 का उपयोग नहीं कर सकता।
RosAng

3
मुझे मूल रूप से इसके साथ NullPointerException मिल रही थी, इसलिए मुझे इससे बचने के लिए getConstraints () को लागू करना पड़ा। निम्नलिखित ने मेरे लिए काम किया: सार्वजनिक मिलानकर्ता <दृश्य> getConstraints () {वापसी isAssignableFrom (View.class); }
dfinn 18

उपरोक्त समाधान मेरे लिए काम नहीं कर रहा है। मुझे निम्न त्रुटि हो रही है: android.support.test.espresso.PerformException: त्रुटि 'android.support.test.espresso.contrib.RecyclerViewActions>ActionOnItemAtPositionViewAction_fad9df' आईडी के साथ 'adamhurwitz.github.io' : आईडी / recyclerView '।
एडम हर्वित्ज

67

अब android.support.test.espresso.contrib के साथ यह आसान हो गया है:

1) परीक्षण निर्भरता जोड़ें

androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.0') {
    exclude group: 'com.android.support', module: 'appcompat'
    exclude group: 'com.android.support', module: 'support-v4'
    exclude module: 'recyclerview-v7'
}

* 3 मॉड्यूल को बाहर करें, क्योंकि बहुत संभावना है कि आपके पास पहले से ही है

2) फिर कुछ ऐसा करें

onView(withId(R.id.recycler_grid))
            .perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));

या

onView(withId(R.id.recyclerView))
  .perform(RecyclerViewActions.actionOnItem(
            hasDescendant(withText("whatever")), click()));

या

onView(withId(R.id.recycler_linear))
            .check(matches(hasDescendant(withText("whatever"))));

1
धन्यवाद, उन मॉड्यूलों को छोड़कर java.lang.IncompatibleClassChangeError में परिणाम नहीं है।
15:17 पर

8
और क्या करने के लिए क्लिक करें सूची के 5 आइटम में एक विशिष्ट दृश्य कहते हैं? प्रदान किए गए उदाहरणों में, मैं केवल 5 वीं आइटम पर क्लिक करने या अवरोही दृश्य के साथ आइटम पर क्लिक करने के लिए देखता हूं, लेकिन दोनों एक साथ नहीं, या मुझे कुछ याद नहीं है?
डोनफक्सक्स

1
मुझे करना थाexclude group: 'com.android.support' exclude module: 'recyclerview-v7'
Jemshit Iskenderov

1
जब आप RecyclerView के अंदर चेकबॉक्स पर क्लिक करना चाहते हैं तो यह बेकार है।
फरीद

2
कोटलिन में actionOnItemAtPositionएक प्रकार के परम की आवश्यकता होती है। निश्चित नहीं है कि वहाँ क्या रखा जाए।
जीरो डिडाइड

7

यहाँ है, मैंने कोटलिन में समस्या का समाधान कैसे किया:

fun clickOnViewChild(viewId: Int) = object : ViewAction {
    override fun getConstraints() = null

    override fun getDescription() = "Click on a child view with specified id."

    override fun perform(uiController: UiController, view: View) = click().perform(uiController, view.findViewById<View>(viewId))
}

और फिर

onView(withId(R.id.recyclerView)).perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(position, clickOnViewChild(R.id.viewToClickInTheRow)))

मैंने E / TestRunner: java.lang.NullPointerException का सामना किया: एक शून्य संदर्भ पर वर्चुअल विधि 'void android.view.View.getLocationOnScreen (int [])' को लागू करने का प्रयास; किसी भी विचार क्यों?
Sayvortana

6

अगले दृष्टिकोण की कोशिश करें:

    onView(withRecyclerView(R.id.recyclerView)
                    .atPositionOnView(position, R.id.bt_deliver))
                    .perform(click());

    public static RecyclerViewMatcher withRecyclerView(final int recyclerViewId) {
            return new RecyclerViewMatcher(recyclerViewId);
    }

public class RecyclerViewMatcher {
    final int mRecyclerViewId;

    public RecyclerViewMatcher(int recyclerViewId) {
        this.mRecyclerViewId = recyclerViewId;
    }

    public Matcher<View> atPosition(final int position) {
        return atPositionOnView(position, -1);
    }

    public Matcher<View> atPositionOnView(final int position, final int targetViewId) {

        return new TypeSafeMatcher<View>() {
            Resources resources = null;
            View childView;

            public void describeTo(Description description) {
                int id = targetViewId == -1 ? mRecyclerViewId : targetViewId;
                String idDescription = Integer.toString(id);
                if (this.resources != null) {
                    try {
                        idDescription = this.resources.getResourceName(id);
                    } catch (Resources.NotFoundException var4) {
                        idDescription = String.format("%s (resource name not found)", id);
                    }
                }

                description.appendText("with id: " + idDescription);
            }

            public boolean matchesSafely(View view) {

                this.resources = view.getResources();

                if (childView == null) {
                    RecyclerView recyclerView =
                            (RecyclerView) view.getRootView().findViewById(mRecyclerViewId);
                    if (recyclerView != null) {

                        childView = recyclerView.findViewHolderForAdapterPosition(position).itemView;
                    }
                    else {
                        return false;
                    }
                }

                if (targetViewId == -1) {
                    return view == childView;
                } else {
                    View targetView = childView.findViewById(targetViewId);
                    return view == targetView;
                }

            }
        };
    }
}

3

आप कर सकते हैं पर क्लिक करें पर 3 आइटम की recyclerViewतरह इस:

onView(withId(R.id.recyclerView)).perform(
                RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(2,click()))

प्रकार प्रदान करने के लिए मत भूलनाViewHolder ताकि इंजेक्शन विफल न हो।


1
मुझे <RecyclerView.ViewHolder>धन्यवाद याद आ रहा था सर;)
स्किज़ो- oz MayS

0

उपरोक्त सभी उत्तर मेरे काम नहीं आए इसलिए मैंने एक नई विधि का निर्माण किया है जो अनुरोध किए गए आईडी के साथ दृश्य को वापस करने के लिए एक सेल के अंदर सभी विचारों को खोजता है। इसके लिए दो तरीकों की आवश्यकता होती है (एक में जोड़ा जा सकता है):

fun performClickOnViewInCell(viewID: Int) = object : ViewAction {
    override fun getConstraints(): org.hamcrest.Matcher<View> = click().constraints
    override fun getDescription() = "Click on a child view with specified id."
    override fun perform(uiController: UiController, view: View) {
        val allChildViews = getAllChildrenBFS(view)
        for (child in allChildViews) {
            if (child.id == viewID) {
                child.callOnClick()
            }
        }
    }
}


private fun  getAllChildrenBFS(v: View): List<View> {
    val visited = ArrayList<View>();
    val unvisited = ArrayList<View>();
    unvisited.add(v);

    while (!unvisited.isEmpty()) {
        val child = unvisited.removeAt(0);
        visited.add(child);
        if (!(child is ViewGroup)) continue;
        val group = child
        val childCount = group.getChildCount();
        for (i in 0 until childCount) { unvisited.add(group.getChildAt(i)) }
    }

    return visited;
}

फिर अंतिम रूप से आप निम्न का उपयोग करके Recycler View पर इसका उपयोग कर सकते हैं:

onView(withId(R.id.recyclerView)).perform(actionOnItemAtPosition<RecyclerView.ViewHolder>(0, getViewFromCell(R.id.cellInnerView) {
            val requestedView = it
}))

यदि आप इसके साथ कुछ और करना चाहते हैं, तो आप कॉलबैक का उपयोग कर सकते हैं या किसी अन्य कार्य को करने के लिए इसके 3-4 अलग-अलग संस्करण बना सकते हैं।


0

मैं यह जानने के लिए विभिन्न तरीकों की कोशिश करता रहा कि क्यों @ ब्लेड का जवाब मेरे लिए काम नहीं कर रहा था, केवल यह महसूस करने के लिए कि मेरे पास एक है OnTouchListener(), मैंने तदनुसार व्यूएशन को संशोधित किया:

fun clickTopicToWeb(id: Int): ViewAction {

        return object : ViewAction {
            override fun getDescription(): String {...}

            override fun getConstraints(): Matcher<View> {...}

            override fun perform(uiController: UiController?, view: View?) {

                view?.findViewById<View>(id)?.apply {

                    //Generalized for OnClickListeners as well
                    if(isEnabled && isClickable && !performClick()) {
                        //Define click event
                        val event: MotionEvent = MotionEvent.obtain(
                          SystemClock.uptimeMillis(),
                          SystemClock.uptimeMillis(),
                          MotionEvent.ACTION_UP,
                          view.x,
                          view.y,
                          0)

                        if(!dispatchTouchEvent(event))
                            throw Exception("Not clicking!")
                    }
                }
            }
        }
    }

0

आप न केवल अधिक कार्यों का समर्थन करने के लिए इस दृष्टिकोण को सामान्य कर सकते हैं click। यहाँ इसके लिए मेरा समाधान है:

fun <T : View> recyclerChildAction(@IdRes id: Int, block: T.() -> Unit): ViewAction {
  return object : ViewAction {
    override fun getConstraints(): Matcher<View> {
      return any(View::class.java)
    }

    override fun getDescription(): String {
      return "Performing action on RecyclerView child item"
    }

    override fun perform(
        uiController: UiController,
        view: View
    ) {
      view.findViewById<T>(id).block()
    }
  }
 
}

और फिर EditTextआप के लिए कुछ इस तरह से कर सकते हैं:

onView(withId(R.id.yourRecyclerView))
        .perform(
            actionOnItemAtPosition<YourViewHolder>(
                0,
                recyclerChildAction<EditText>(R.id.editTextId) { setText("1000") }
            )
        )

-5

सबसे पहले अपने बटन को यूनीक कंटेंट डिसेबल करें, "डिलीवरी बटन पंक्ति 5"।

<button android:contentDescription=".." />

फिर पंक्ति पर स्क्रॉल करें:

onView(withId(R.id.recycler_view)).perform(RecyclerViewActions.scrollToPosition(5));

इसके बाद कंटेंट डिस्क्रिप्शन के आधार पर व्यू का चयन करें।

onView(withContentDescription("delivery button row 5")).perform(click());

सामग्री विवरण एस्प्रेसो के onView का उपयोग करने और अपने ऐप को अधिक सुलभ बनाने का एक शानदार तरीका है।


5
सामग्री विवरण का इस तरह से उपयोग नहीं किया जाना चाहिए - यह आपके ऐप को a11y जरूरतों वाले उपयोगकर्ताओं के लिए तकनीकी या डिबग जानकारी को टालने के लिए अधिक सुलभ नहीं बनाता है - इसके लिए सीडी शायद "ऑर्डर <आइटम सारांश> जैसी होनी चाहिए। बटन "। withText("Order")काम भी करेगा, और आपको परीक्षण के समय यह जानने की आवश्यकता नहीं होगी कि आप क्या आदेश दे रहे हैं।
ataulm
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.