Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Espresso and Linkify

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)?

like image 240
argenkiwi Avatar asked Mar 11 '14 02:03

argenkiwi


3 Answers

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.

like image 77
Pranay Airan Avatar answered Nov 07 '22 05:11

Pranay Airan


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?

like image 35
Maragues Avatar answered Nov 07 '22 07:11

Maragues


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.

like image 30
ValeraZakharov Avatar answered Nov 07 '22 05:11

ValeraZakharov