public final class

OpenLinkAction

extends java.lang.Object

implements ViewAction

 java.lang.Object

↳androidx.test.espresso.action.OpenLinkAction

Gradle dependencies

compile group: 'androidx.test.espresso', name: 'espresso-core', version: '3.6.1'

  • groupId: androidx.test.espresso
  • artifactId: espresso-core
  • version: 3.6.1

Artifact androidx.test.espresso:espresso-core:3.6.1 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.test.espresso:espresso-core com.android.support.test.espresso:espresso-core

Androidx class mapping:

androidx.test.espresso.action.OpenLinkAction android.support.test.espresso.action.OpenLinkAction

Overview

Invokes onClick of a link within a TextView (made with Linkify or via another method). Why not issue a real click event to the screen? Unfortunately, it does not seem to be possible (at least using public APIs) to determine the location of the link on the screen.

Summary

Constructors
publicOpenLinkAction(<any> linkTextMatcher, <any> uriMatcher)

Methods
public <any>getConstraints()

public java.lang.StringgetDescription()

public voidperform(UiController uiController, View view)

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public OpenLinkAction(<any> linkTextMatcher, <any> uriMatcher)

Methods

public <any> getConstraints()

public java.lang.String getDescription()

public void perform(UiController uiController, View view)

Source

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.test.espresso.action;

import static androidx.test.espresso.matcher.ViewMatchers.hasLinks;
import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.internal.util.Checks.checkNotNull;
import static androidx.test.internal.util.Checks.checkState;
import static org.hamcrest.Matchers.allOf;

import android.net.Uri;
import android.text.Spanned;
import android.text.style.URLSpan;
import android.view.View;
import android.widget.TextView;
import androidx.test.espresso.PerformException;
import androidx.test.espresso.UiController;
import androidx.test.espresso.ViewAction;
import androidx.test.espresso.util.HumanReadables;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import org.hamcrest.Matcher;

/**
 * Invokes onClick of a link within a TextView (made with Linkify or via another method). Why not
 * issue a real click event to the screen? Unfortunately, it does not seem to be possible (at least
 * using public APIs) to determine the location of the link on the screen.
 */
public final class OpenLinkAction implements ViewAction {
  private final Matcher<String> linkTextMatcher;
  private final Matcher<Uri> uriMatcher;

  public OpenLinkAction(Matcher<String> linkTextMatcher, Matcher<Uri> uriMatcher) {
    this.linkTextMatcher = checkNotNull(linkTextMatcher);
    this.uriMatcher = checkNotNull(uriMatcher);
  }

  @Override
  public Matcher<View> getConstraints() {
    return allOf(isDisplayed(), isAssignableFrom(TextView.class), hasLinks());
  }

  @Override
  public String getDescription() {
    return String.format(
        Locale.ROOT, "open link with text %s and uri %s", linkTextMatcher, uriMatcher);
  }

  @Override
  public void perform(UiController uiController, View view) {
    TextView textView = (TextView) view;
    String allText = textView.getText().toString();
    URLSpan[] urls = textView.getUrls();
    Spanned spanned = (Spanned) textView.getText();

    // TODO: what if we get more than one hit? For now, take the first one...
    // In the future, we may want to support a way to disambiguate (e.g using text around the link).
    List<String> allLinks = new ArrayList<>();
    for (URLSpan url : urls) {
      int start = spanned.getSpanStart(url);
      checkState(start != -1, "Unable to get start of text associated with url: " + url);
      int end = spanned.getSpanEnd(url);
      checkState(end != -1, "Unable to get end of text associated with url: " + url);
      String linkText = allText.substring(start, end);
      allLinks.add(linkText);
      if (linkTextMatcher.matches(linkText) && uriMatcher.matches(Uri.parse(url.getURL()))) {
        url.onClick(view);
        return;
      }
    }
    throw new PerformException.Builder()
        .withActionDescription(this.getDescription())
        .withViewDescription(HumanReadables.describe(view))
        .withCause(
            new RuntimeException(
                String.format(
                    Locale.ROOT,
                    "Link with text '%s' and uri '%s' not found. List of links found in this view:"
                        + " %s\n"
                        + "List of uris: %s",
                    linkTextMatcher,
                    uriMatcher,
                    allLinks,
                    Arrays.asList(urls))))
        .build();
  }
}