Android Espresso - Click checkbox if not checked

前端 未结 5 996
长情又很酷
长情又很酷 2021-02-18 13:58

I have onView(withId(R.id.check_box)).perform(click()), but i only want to do this if the check box is not already checked. How can I do this in espresso?

相关标签:
5条回答
  • 2021-02-18 14:02

    This seems to be part of your test, that the checkbox needs to be checked.

    You can check this by:

    onView(withId(R.id.checkbox)).check(matches(not(isChecked())));
    

    If this fails, your test will fail, which may be good in your case. Then, you can perform the click you want after this case matches.

    If this is not the situation you want, can you explain more on what you are trying to do in this Espresso Test?

    0 讨论(0)
  • 2021-02-18 14:08

    I had the same problem an wrote an own ViewAction that always unchecks my SwitchCompat

    class UncheckViewAction implements ViewAction{
    
        @Override
        public Matcher<View> getConstraints() {
            return new Matcher<View>() {
                @Override
                public boolean matches(Object item) {
                    return isA(SwitchCompat.class).matches(item);
                }
    
                @Override
                public void describeMismatch(Object item, Description mismatchDescription) {
    
                }
    
                @Override
                public void _dont_implement_Matcher___instead_extend_BaseMatcher_() {
    
                }
    
                @Override
                public void describeTo(Description description) {
    
                }
            };
        }
    
        @Override
        public String getDescription() {
            return null;
        }
    
        @Override
        public void perform(UiController uiController, View view) {
            SwitchCompat scView = (SwitchCompat) view;
            scView.setChecked(false);
        }
    }
    

    and used it like this:

    onView(withId(R.id.check_box)).perform(new UncheckViewAction())
    

    now i can be sure that the found switch is always unchecked, no matter if it was checked or unchecked before.

    0 讨论(0)
  • 2021-02-18 14:16

    Just as @FrostRocket suggested but written in Kotlin.

    We define a custom action that can only performed on checkable items (as specified in constraints). So we safely cast the view to Checkable to access setCheckable method.

    fun setChecked(checked: Boolean) = object : ViewAction {
        val checkableViewMatcher = object : BaseMatcher<View>() {
            override fun matches(item: Any?): Boolean = isA(Checkable::class.java).matches(item)
            override fun describeTo(description: Description?) {
                description?.appendText("is Checkable instance ")
            }
        }
    
        override fun getConstraints(): BaseMatcher<View> = checkableViewMatcher
        override fun getDescription(): String? = null
        override fun perform(uiController: UiController?, view: View) {
            val checkableView: Checkable = view as Checkable
            checkableView.isChecked = checked
        }
    }
    
    0 讨论(0)
  • 2021-02-18 14:18

    I also wanted to toggle a checkbox/switch depending on it's previous state. At first, I tried this to toggle ON a checkbox that was OFF:

    onView(withId(R.id.checkbox)).check(matches(isNotChecked())).perform(scrollTo(), click());
    

    ...and this to toggle OFF a checkbox that was ON:

    onView(withId(R.id.checkbox)).check(matches(isChecked())).perform(scrollTo(), click());
    

    However, this doesn't work, since Espresso will be looking for a specific toggle state before it performs the action. Sometimes, you don't know whether it's ON or OFF beforehand.

    My solution is to use a custom ViewAction to turn OFF/ON any checkable object (Switch, Checkbox, etc.) that isn't dependent on previous state. So, if it's already ON, it'll stay ON. If it's OFF, it'll toggle ON. Here's the ViewAction:

    public static ViewAction setChecked(final boolean checked) {
        return new ViewAction() {
            @Override
            public BaseMatcher<View> getConstraints() {
                return new BaseMatcher<View>() {
                    @Override
                    public boolean matches(Object item) {
                        return isA(Checkable.class).matches(item);
                    }
    
                    @Override
                    public void describeMismatch(Object item, Description mismatchDescription) {}
    
                    @Override
                    public void describeTo(Description description) {}
                };
            }
    
            @Override
            public String getDescription() {
                return null;
            }
    
            @Override
            public void perform(UiController uiController, View view) {
                Checkable checkableView = (Checkable) view;
                checkableView.setChecked(checked);
            }
        };
    }
    

    And here's how you use it (in this example, when you want to toggle to ON):

    onView(withId(R.id.toggle)).perform(scrollTo(), setChecked(true));
    
    0 讨论(0)
  • 2021-02-18 14:27

    You have something like this in your code:

    @Rule
    public ActivityTestRule<ActivityMain> ActivityMainRule = new ActivityTestRule<>(ActivityMain.class);
    

    Try

    if (!ActivityMainRule.getActivity().findViewById(R.id.check_box).isChecked()) {
        onView(withId(R.id.check_box)).perform(click())    
    }
    
    0 讨论(0)
提交回复
热议问题