android - Espresso checking if toasts are displayed (one on top of another) -
i have problem checking if toast displayed using espresso. i'm using class:
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 window isn't contained other windows. // if window activity, have type_base_application. return true; } } return false; } }
and checking toast by:
onview(withtext(r.string.unauthorized)).inroot(new toastmatcher()) .check(matches(isdisplayed()));
everything works fine until try check toast in same class example:
@test public void messageonback() throws exception{ pressback(); onview(withtext(r.string.exit_on_back)).inroot(new toastmatcher()) .check(matches(isdisplayed()));
then first 1 passed second 1 puts error:
android.support.test.espresso.nomatchingviewexception: no views in hierarchy found matching: string resource id: <2131165323>[unauthorized] value: wrong login or password. view hierarchy: +>linearlayout{id=-1, visibility=visible, width=660, height=116, has-focus=false, has-focusable=false, has-window-focus=false, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1} | +->appcompattextview{id=16908299, res-name=message, visibility=visible, width=528, height=58, has-focus=false, has-focusable=false, has-window-focus=false, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=66.0, y=29.0, text=please click again exit., input-type=0, ime-target=false, has-links=false} | @ dalvik.system.vmstack.getthreadstacktrace(native method)
what weird, when comment out 1 of tests second 1 works fine without changes. espresso seems stupid when 1 toast displayed on top of another. ideas how solve this?
the nomatchingviewexception
seeing means toastmatcher
find root view type_toast
, cannot find requested view inside root (otherwise, you'd nomatchingrootexception
).
i guess reason android not showing toasts on top of each other, one after other. thus, view finds in toast-root first toast (your second toast has not yet been shown). thus, before checking second toast have somehow wait until first toast has disappeared. isn't trivial, unfortunately (see below), , believe cannot around changing production code.
a possible solution given in https://stackoverflow.com/a/32023568/1059766. basic idea attach onattachstatechangedlistener
toast's view before showing toast, , use listener track when view attached , detached view hierarchy. can used implement custom idlingresource
can wait toast disappear.
the way espresso waits things means of idlingresource
s. cannot see how create custom idling resource wait toast without changing production code. therefore, along lines of aformentioned answer best can think of, though required change production code not appealing.
that being said, note toastmatcher
solution (that's suggested on stackoverflow , blogs) not reliable way test toasts. works in situations, not always. consider e.g. following snippet:
new asynctask<void, void, void>() { public void doinbackground(...) { // start background work 10s (or thread.sleep(10000)) } }.execute() toast.make(context, r.string.mytoast, toast.length_short).show()
as espresso waits until ui thread , async-tasks idle, in above example wait (about) 10s until isdisplayed()
check performed. @ point toast have disappeared , therefore check fails. hope enough illustrate inherent problem approach. following statement valera zakharov in https://groups.google.com/d/msg/android-test-kit-discuss/uahdxuvm-bw/cuqasd3pdpgj seems confirm there no easy solution test toasts espresso:
short answer: unfortunately, there no thread-safe way of doing in android, don't provide capability in espresso.
details: way toasts implemented makes possible detect toast has been displayed. there no way see if toast has been requested, thru call show()) or block between period of time between show() , when toast has become visible. opens unresolvable timing issues (that can address thru sleep & hope) [...].
zakharov suggests add hooks production code (as far understand that). thus, guess adding idlingresource
based on production code hooks best can (this might make toast testing more stable in general, can test toasts outlined zakharov).
Comments
Post a Comment