I am trying to test using Espresso if my TextInputLayout
views have specific hint. I'd used a code as below:
Espresso.onView(ViewMatchers.withId(R.id.edit_text_email))
.check(ViewAssertions.matches(
ViewMatchers.withHint(R.string.edit_text_email_hint)))
This works fine for the normal EditText
views, not wrapped in TextInputLayout
. However when it wraps around, it no longer works.
I tried to use solution from Android Espresso - How to check EditText hint?, but it still does not working.
I also looked into: https://code.google.com/p/android/issues/detail?id=191261 that reported the issue, it says the workaround is quite easy by pointing to the current withHint
code, but I can't get it to work.
Any ideas to fix this issue?
Here's my custom matcher:
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) {
}
};
}
}
and here's how to use:
@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))));
}
If you would like to check errorText
of TextInputLayout
, change this line:
CharSequence error = ((TextInputLayout) view).getHint();
with
CharSequence error = ((TextInputLayout) view).getError();
Hope it will help
Kotlin version of piotrek1543's answer:
fun hasTextInputLayoutHintText(expectedErrorText: String): Matcher<View> = object : TypeSafeMatcher<View>() {
override fun describeTo(description: Description?) { }
override fun matchesSafely(item: View?): Boolean {
if (item !is TextInputLayout) return false
val error = item.hint ?: return false
val hint = error.toString()
return expectedErrorText == hint
}
}
More generic solution that would work with any View that has "getHint" method:
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"))));
A much more simple solution is to check if the error text is visible, for example:
val text = mTestRule.getActivity().getString(R.string.error_text)
onView(withText(text)).check(matches(isDisplayed()))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With