web-dev-qa-db-fra.com

Comment tester les valeurs de TextInputLayout (indice, erreur, etc.) avec Android Espresso?

J'essaie de tester avec Espresso si mes vues TextInputLayout ont un indice spécifique. J'avais utilisé un code comme ci-dessous:

Espresso.onView(ViewMatchers.withId(R.id.edit_text_email))
    .check(ViewAssertions.matches(
        ViewMatchers.withHint(R.string.edit_text_email_hint)))

Cela fonctionne très bien pour les vues EditText normales et non enveloppées dans TextInputLayout. Cependant, quand ça tourne autour, ça ne marche plus.

J'ai essayé d'utiliser la solution de Android Espresso - Comment vérifier l'indice EditText? , mais ça ne marche toujours pas.

J'ai également examiné: https://code.google.com/p/Android/issues/detail?id=191261 qui a signalé le problème, il est indiqué que la solution de contournement est relativement simple en indiquant le code withHint actuel, mais je ne peux pas le faire fonctionner.

Des idées pour résoudre ce problème?

14
Elye

Voici mon matcher personnalisé:

public static Matcher<View> hasTextInputLayoutHintText(final String expectedErrorText) {
        return new TypeSafeMatcher<View>() {

            @Override
            public boolean matchesSafely(View view) {
                if (!(view instanceof TextInputLayout)) {
                    return false;
                }

                CharSequence error = ((TextInputLayout) view).getHint();

                if (error == null) {
                    return false;
                }

                String hint = error.toString();

                return expectedErrorText.equals(hint);
            }

            @Override
            public void describeTo(Description description) {
            }
        };
    }
}

et voici comment utiliser:

@RunWith(AndroidJUnit4.class)
public class MainActivityTest {

    @Rule
    public ActivityTestRule<MainActivity> mRule = new ActivityTestRule<>(MainActivity.class);

    @Test
    public void testMyApp() {
        onView(withId(R.id.textInputLayout)).check
                (matches(hasTextInputLayoutErrorText(mRule.getActivity().getString(R.string
                        .app_name))));

    }

Si vous souhaitez vérifier errorText de TextInputLayout, changez cette ligne:

     CharSequence error = ((TextInputLayout) view).getHint();

avec

     CharSequence error = ((TextInputLayout) view).getError();

J'espère que ça va aider

28
piotrek1543

Solution plus générique qui fonctionnerait avec n'importe quelle vue utilisant la méthode "getHint":

public static Matcher<View> withCustomHint(final Matcher<String> stringMatcher) {
    return new BaseMatcher<View>() {
        @Override
        public void describeTo(Description description) {
        }

        @Override
        public boolean matches(Object item) {
            try {
                Method method = item.getClass().getMethod("getHint");
                return stringMatcher.matches(method.invoke(item));
            } catch (NoSuchMethodException e) {
            } catch (InvocationTargetException e) {
            } catch (IllegalAccessException e) {
            }
            return false;
        }
    };
}

Usage:

onView(withId(R.id.SomeLayout)).check(matches(withCustomHint(is("SomeString"))));
1
Anton Tananaev

Une solution beaucoup plus simple consiste à vérifier si le texte de l'erreur est visible, par exemple:

val text = mTestRule.getActivity().getString(R.string.error_text)
onView(withText(text)).check(matches(isDisplayed()))
0
RobertoAllende

Les solutions ci-dessus ne fonctionnaient pas pour mon cas d'utilisation. Je voulais trouver le TextInputEditText et y taper du texte. Voici ma solution:

    @VisibleForTesting
class WithTextInputLayoutHintMatcher @RemoteMsgConstructor
constructor(@field:RemoteMsgField(order = 0)
            private val stringMatcher: Matcher<String>) : TypeSafeMatcher<View>() {

    override fun describeTo(description: Description) {
        description.appendText("with TextInputLayout hint: ")
        stringMatcher.describeTo(description)
    }

    public override fun matchesSafely(textInputEditText: View): Boolean {
        if (textInputEditText !is TextInputEditText) return false

        return stringMatcher.matches((textInputEditText.parent.parent as? TextInputLayout)?.hint)
    }
}

/**
 * Returns a matcher that matches [TextInputEditText] based on it's hint property value.
 *
 *
 * **Note:** View's sugar for `withHint(is("string"))`.
 *
 * @param hintText [String] with the hint text to match
 */
fun withTextInputHint(hintText: String): Matcher<View> {
    return withTextInputHint(Matchers.`is`(checkNotNull(hintText)))
}

/**
 * Returns a matcher that matches a descendant of [TextInputEditText] that is displaying the hint
 * associated with the given resource id.
 *
 * @param resourceId the string resource the text view is expected to have as a hint.
 */
fun withTextInputHint(resourceId: Int): Matcher<View> {
    return withTextInputHint(getString(resourceId))
}

/**
 * Returns a matcher that matches [TextView]s based on hint property value.
 *
 *
 * **Note:** View's hint property can be `null`, to match against it use `
 * withHint(nullValue(String.class)`
 *
 * @param stringMatcher [`Matcher
`](http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html) *  of [String] with text to match
 */
fun withTextInputHint(stringMatcher: Matcher<String>): Matcher<View> {
    return WithTextInputLayoutHintMatcher(checkNotNull(stringMatcher))
}

Usage:

onView(withTextInputHint(R.string.hint)).perform(ViewActions.typeText("Type text here"))

0
Peter Keefe