I am writing some tests for my Android app based on Espresso. After clicking on a link inside a TextView (created with the Linkify class) I need to assert I am seeing the correct screen.
I tried performing a click on the TextView that contains the link, but the link won't open.
Is there a proper way to test this using Espresso (other than modifying the code to have a separate TextView for the link)?
I found out a simpler way of doing this, there is a method in ViewActions called openLinkWithText, it uses linkTextMatcher as matcher to match link, using this is it very easy to click a textview with multiple links like this :
Espresso.onView(ViewMatchers.withId(R.id.legal_privacy_tv)).perform(ViewActions.openLinkWithText("Privacy Statement"));
In my case i have 1 single text view which is linkify with 2 links, privacy statement and legal statement, using above method i am able to click on them individually without using bound xy or other methods suggested above.
Here's my solution. I'm using reflection and it's ugly, but perhaps it serves someone else.
In my case the spans array contains several types of Spans. The ones I care about are some kind of inner anonymous class, thus getClass().getSimpleName() returns empty string. The instance holds a private field containing the URLSpan
private void clickOnSpan(TextView textView, CharSequence spanContent) {
SpannableString completeText = (SpannableString) textView.getText();
Layout textViewLayout = textView.getLayout();
Object[] spans = completeText.getSpans(0, completeText.length(), Object.class);
Object spanToLocate = null;
for (Object span : spans) {
if (!span.getClass().getSimpleName().equals(""))
continue;
try {
Field[] fields = span.getClass().getDeclaredFields();
fields[1].setAccessible(true);
URLSpan urlSpan = (URLSpan) fields[1].get(span);
if (urlSpan.getURL().equals(spanContent)) {
spanToLocate = span;
break;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
int endOffsetOfClickedText = completeText.getSpanEnd(spanToLocate);
float endXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal(endOffsetOfClickedText);
int clickedTextLine = textViewLayout.getLineForOffset(endOffsetOfClickedText);
int yEndCoordinateOfClickedText = textViewLayout.getLineBottom(clickedTextLine);
onView(withId(textView.getId())).perform(clickXY(Float.valueOf(endXCoordinatesOfClickedText).intValue(), yEndCoordinateOfClickedText / 2));
}
References:
clickXY: Click by bounds / coordinates
How get coordinate of a ClickableSpan inside a TextView?
Does it work when you click the link manually? Espresso sends the save events to the screen as a user tap does, so I'd be surprised if it didn't work (provided it was clicking on the same coordinates). That being said, if your link launches an Activity in an external application, the instrumentation test will fail due to security restrictions. There is currently no way to work around this with Espresso.
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