web-dev-qa-db-fra.com

Vérification du message de douleur dans un expresso Android

Est-ce que quelqu'un saurait comment vérifier l'apparition d'un message Toast dans un espresso Android? Dans robotium, c’est facile et j’ai utilisé mais j’ai commencé à travailler dans l’expresso, mais je n’ai pas reçu la commande exacte.

62
Humayun Rana

Cette déclaration légèrement longue fonctionne pour moi:

import static Android.support.test.espresso.assertion.ViewAssertions.matches;
import static Android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static Android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static Android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
....
onView(withText(R.string.TOAST_STRING)).inRoot(withDecorView(not(is(getActivity().getWindow().getDecorView())))).check(matches(isDisplayed()));
99
kowalcj0

La réponse acceptée est bonne mais n'a pas fonctionné pour moi. J'ai donc cherché un peu et trouvé cet article de blog ..__ Cela m'a donné une idée de la procédure à suivre et j'ai mis à jour la solution ci-dessus.

J'ai d'abord implémenté ToastMatcher:

import Android.os.IBinder;
import Android.support.test.espresso.Root;
import Android.view.WindowManager;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;

public class ToastMatcher extends TypeSafeMatcher<Root> {

  @Override
  public void describeTo(Description description) {
    description.appendText("is toast");
  }

  @Override
  public boolean matchesSafely(Root root) {
    int type = root.getWindowLayoutParams().get().type;
    if (type == WindowManager.LayoutParams.TYPE_TOAST) {
        IBinder windowToken = root.getDecorView().getWindowToken();
        IBinder appToken = root.getDecorView().getApplicationWindowToken();
        if (windowToken == appToken) {
            // windowToken == appToken means this window isn't contained by any other windows.
            // if it was a window for an activity, it would have TYPE_BASE_APPLICATION.
            return true;
        }
    }
    return false;
  }

}

Ensuite, j'ai implémenté mes méthodes de contrôle comme ceci:

public void isToastMessageDisplayed(int textId) {
    onView(withText(textId)).inRoot(MobileViewMatchers.isToast()).check(matches(isDisplayed()));
}

MobileViewMatchers est un conteneur permettant d'accéder aux correspondants. Là, j'ai défini la méthode statique isToast().

public static Matcher<Root> isToast() {
    return new ToastMatcher();
}

Cela fonctionne comme un charme pour moi.

39
Thomas R.

D'abord assurez-vous d'importer:

import static Android.support.test.espresso.Espresso.onView;
import static Android.support.test.espresso.matcher.ViewMatchers.withText;
import static Android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static Android.support.test.espresso.assertion.ViewAssertions.matches;

Dans votre classe, vous avez probablement une règle comme celle-ci:

@Rule
public ActivityTestRule<MyNameActivity> activityTestRule =
            new ActivityTestRule<>(MyNameActivity.class);

Dans votre test:

MyNameActivity activity = activityTestRule.getActivity();
onView(withText(R.string.toast_text)).
    inRoot(withDecorView(not(is(activity.getWindow().getDecorView())))).
    check(matches(isDisplayed()));

Cela a fonctionné pour moi et c'était assez facile à utiliser.

11
lmiguelvargasf

Bien que la question ait une réponse acceptée - ce que BTW ne fonctionne pas pour moi -, j'aimerais ajouter ma solution dans Kotlin, que j'ai tirée de la réponse de Thomas R.:

package somepkg

import Android.support.test.espresso.Espresso.onView
import Android.support.test.espresso.Root
import Android.support.test.espresso.matcher.ViewMatchers.withText
import Android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
import Android.view.WindowManager.LayoutParams.TYPE_TOAST
import org.hamcrest.Description
import org.hamcrest.Matcher
import org.hamcrest.TypeSafeMatcher

/**
 * This class allows to match Toast messages in tests with Espresso.
 *
 * Idea taken from: https://stackoverflow.com/a/33387980
 *
 * Usage in test class:
 *
 * import somepkg.ToastMatcher.Companion.onToast
 *
 * // To assert a toast does *not* pop up:
 * onToast("text").check(doesNotExist())
 * onToast(textId).check(doesNotExist())
 *
 * // To assert a toast does pop up:
 * onToast("text").check(matches(isDisplayed()))
 * onToast(textId).check(matches(isDisplayed()))
 */
class ToastMatcher(private val maxFailures: Int = DEFAULT_MAX_FAILURES) : TypeSafeMatcher<Root>() {

    /** Restrict number of false results from matchesSafely to avoid endless loop */
    private var failures = 0

    override fun describeTo(description: Description) {
        description.appendText("is toast")
    }

    public override fun matchesSafely(root: Root): Boolean {
        val type = root.windowLayoutParams.get().type
        @Suppress("DEPRECATION") // TYPE_TOAST is deprecated in favor of TYPE_APPLICATION_OVERLAY
        if (type == TYPE_TOAST || type == TYPE_APPLICATION_OVERLAY) {
            val windowToken = root.decorView.windowToken
            val appToken = root.decorView.applicationWindowToken
            if (windowToken === appToken) {
                // windowToken == appToken means this window isn't contained by any other windows.
                // if it was a window for an activity, it would have TYPE_BASE_APPLICATION.
                return true
            }
        }
        // Method is called again if false is returned which is useful because a toast may take some time to pop up. But for
        // obvious reasons an infinite wait isn't of help. So false is only returned as often as maxFailures specifies.
        return (++failures >= maxFailures)
    }

    companion object {

        /** Default for maximum number of retries to wait for the toast to pop up */
        private const val DEFAULT_MAX_FAILURES = 5

        fun onToast(text: String, maxRetries: Int = DEFAULT_MAX_FAILURES) = onView(withText(text)).inRoot(isToast(maxRetries))!!

        fun onToast(textId: Int, maxRetries: Int = DEFAULT_MAX_FAILURES) = onView(withText(textId)).inRoot(isToast(maxRetries))!!

        fun isToast(maxRetries: Int = DEFAULT_MAX_FAILURES): Matcher<Root> {
            return ToastMatcher(maxRetries)
        }
    }

}

J'espère que cela aidera les lecteurs ultérieurs - l'utilisation est décrite dans le commentaire.

2
yasd

Créez d’abord un cutom Toast Matcher que nous pourrons utiliser dans nos cas de test -

public class ToastMatcher extends TypeSafeMatcher<Root> {

    @Override    public void describeTo(Description description) {
        description.appendText("is toast");
    }

    @Override    public boolean matchesSafely(Root root) {
        int type = root.getWindowLayoutParams().get().type;
        if ((type == WindowManager.LayoutParams.TYPE_TOAST)) {
            IBinder windowToken = root.getDecorView().getWindowToken();
            IBinder appToken = root.getDecorView().getApplicationWindowToken();
            if (windowToken == appToken) {
              //means this window isn't contained by any other windows. 
            }
        }
        return false;
    }

1. Vérifier si le message de pain grillé est affiché 

onView(withText(R.string.mssage)).inRoot(new ToastMatcher())
.check(matches(isDisplayed()));

2. Vérifier si le message de pain grillé n'est pas affiché

onView(withText(R.string.mssage)).inRoot(new ToastMatcher())
.check(matches(not(isDisplayed())));

3. Identifiant du test que Toast contient un message texte spécifique

onView(withText(R.string.mssage)).inRoot(new ToastMatcher())
.check(matches(withText("Invalid Name"));

Merci, Anuja

Remarque - cette réponse provient de This POST.

1
anuja jain

Si vous utilisez le plus récent Outils de test Android from Jetpack , vous savez que ActivityTestRule est obsolète et vous devez utiliser ActivityScenario ou ActivityScenarioRule (qui contient le premier).

Conditions préalables. Créez la variable decorView et assignez-la avant les tests;

    @Rule
    public ActivityScenarioRule<FeedActivity> activityScenarioRule = new ActivityScenarioRule<>(FeedActivity.class);

    private View decorView;

    @Before
    public void setUp() {
        activityScenarioRule.getScenario().onActivity(new ActivityScenario.ActivityAction<FeedActivity>() {
            @Override
            public void perform(FeedActivityactivity) {
                decorView = activity.getWindow().getDecorView();
            }
        });
}

Se tester

@Test
public void given_when_thenShouldShowToast() {
    String expectedWarning = getApplicationContext().getString(R.string.error_empty_list);
    onView(withId(R.id.button))
            .perform(click());

    onView(withText(expectedWarning))
            .inRoot(withDecorView(not(decorView)))// Here we use decorView
            .check(matches(isDisplayed()));
}

getApplicationContext () peut être tiré de androidx.test.core.app.ApplicationProvider.getApplicationContext;

0
Akbolat SSS

Je dirais pour les messages de pain grillé d'abord définir votre règle 

 @Rule
   public ActivityTestRule<AuthActivity> activityTestRule =
   new ActivityTestRule<>(AuthActivity.class);

quel que soit le texte du message toast que vous recherchez, saisissez-le entre guillemets. Par exemple, j'ai utilisé "Adresse email invalide"

   onView(withText("Invalid email address"))
    .inRoot(withDecorView(not(activityTestRule.getActivity().getWindow().getDecorView())))
    .check(matches(isDisplayed()));
0
keti

J'écris mon matcher toast personnalisé:

import Android.view.WindowManager
import androidx.test.espresso.Root
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
class ToastMatcher : TypeSafeMatcher<Root>() {

    override fun describeTo(description: Description) {
        description.appendText("is toast")
    }

    override fun matchesSafely(root: Root): Boolean {
        val type = root.getWindowLayoutParams().get().type
        if (type == WindowManager.LayoutParams.TYPE_TOAST) {
            val windowToken = root.getDecorView().getWindowToken()
            val appToken = root.getDecorView().getApplicationWindowToken()
            if (windowToken === appToken) {
                return true
            }
        }
        return false
    }
}

Et utilisez comme ceci:

onView(withText(R.string.please_input_all_fields)).inRoot(ToastMatcher()).check(matches(isDisplayed()))
0
Alexei

Je suis plutôt nouveau dans ce domaine, mais j'ai créé une classe de base 'BaseTest' qui contient toutes mes actions (balayage, clic, etc.) et vérifications (vérification du contenu des vues, etc.).

protected fun verifyToastMessageWithText(text: String, activityTestRule: ActivityTestRule<*>) {
        onView(withText(text)).inRoot(withDecorView(not(activityTestRule.activity.window.decorView))).check(matches(isDisplayed()))
    }

protected fun verifyToastMessageWithStringResource(id: Int, activityTestRule: ActivityTestRule<*>) {
        onView(withText(id)).inRoot(withDecorView(not(activityTestRule.activity.window.decorView))).check(matches(isDisplayed()))
    }
0
user1791622