dragthor / android-test-kit

Automatically exported from code.google.com/p/android-test-kit
0 stars 0 forks source link

withText not working with CollapsingToolbarLayout #172

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Create a layout that uses the AppBarLayout, CollapsingToolbarLayout, and 
Toolbar from the Design Support Library
2. In the activity set the title for the CollapsingToolbarLayout to "Test"
3. Use the following Espresso tests for the activity: 
   onView(withText("Test")).check(matches(isDisplayed()));
  onView(withId(R.id.collapsing_tool_bar)).check(matches(withText("Test")));

What is the expected output? What do you see instead?

I expect the two tests to pass, but they do not. 

What version of the product are you using? On what operating system?

'com.android.support.test:runner:0.2'
'com.android.support.test:rules:0.2'
'com.android.support.test.espresso:espresso-core:2.2'
'com.android.support:design:22.2.0'
compileSdkVersion 22
buildToolsVersion "22.0.1"

Tried on android emulators using API 18, 20, and 21

Please provide any additional information below.

Sample project that isolates this issue can be found here: 
https://github.com/oakesja/espresso-design-support-library

Failing message for the tests: 

android.support.test.espresso.NoMatchingViewException: No views in hierarchy 
found matching: with text: is "Test"

View Hierarchy:
+>DecorView{id=-1, visibility=VISIBLE, width=1080, height=1776, 
has-focus=false, has-focusable=false, has-window-focus=true, 
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}
|
+->LinearLayout{id=-1, visibility=VISIBLE, width=1080, height=1776, 
has-focus=false, has-focusable=false, has-window-focus=true, 
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=2}
|
+-->ViewStub{id=16909112, visibility=GONE, width=0, height=0, has-focus=false, 
has-focusable=false, has-window-focus=true, is-clickable=false, 
is-enabled=true, is-focused=false, is-focusable=false, 
is-layout-requested=true, is-selected=false, root-is-layout-requested=false, 
has-input-connection=false, x=0.0, y=0.0}
|
+-->FrameLayout{id=-1, visibility=VISIBLE, width=1080, height=1701, 
has-focus=false, has-focusable=false, has-window-focus=true, 
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=75.0, child-count=1}
|
+--->FitWindowsLinearLayout{id=2131492946, res-name=action_bar_root, 
visibility=VISIBLE, width=1080, height=1701, has-focus=false, 
has-focusable=false, has-window-focus=true, 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=2}
|
+---->ViewStubCompat{id=2131492947, res-name=action_mode_bar_stub, 
visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, 
has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, 
is-focusable=false, is-layout-requested=true, is-selected=false, 
root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}
|
+---->ContentFrameLayout{id=16908290, res-name=content, visibility=VISIBLE, 
width=1080, height=1701, has-focus=false, has-focusable=false, 
has-window-focus=true, 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}
|
+----->CoordinatorLayout{id=-1, visibility=VISIBLE, width=1080, height=1701, 
has-focus=false, has-focusable=false, has-window-focus=true, 
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}
|
+------>AppBarLayout{id=-1, visibility=VISIBLE, width=1080, height=600, 
has-focus=false, has-focusable=false, has-window-focus=true, 
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}
|
+------->CollapsingToolbarLayout{id=2131492966, res-name=collapsing_tool_bar, 
visibility=VISIBLE, width=1080, height=600, has-focus=false, 
has-focusable=false, has-window-focus=true, 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}
|
+-------->Toolbar{id=2131492967, res-name=toolbar, visibility=VISIBLE, 
width=1080, height=168, has-focus=false, has-focusable=false, 
has-window-focus=true, 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=3}
|
+--------->TextView{id=-1, visibility=VISIBLE, width=0, height=80, 
has-focus=false, has-focusable=false, has-window-focus=true, 
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=48.0, y=44.0, text=EspressoDesignSupportLib, 
input-type=0, ime-target=false, has-links=false}
|
+--------->View{id=-1, visibility=VISIBLE, width=1032, height=168, 
has-focus=false, has-focusable=false, has-window-focus=true, 
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=48.0, y=0.0}
|
+--------->ActionMenuView{id=-1, visibility=VISIBLE, width=0, height=168, 
has-focus=false, has-focusable=false, has-window-focus=true, 
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=1080.0, y=0.0, child-count=0}
|
at dalvik.system.VMStack.getThreadStackTrace(Native Method)
at java.lang.Thread.getStackTrace(Thread.java:579)
at 
android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(De
faultFailureHandler.java:82)
at 
android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHa
ndler.java:53)
at 
android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInt
eraction.java:184)
at android.support.test.espresso.ViewInteraction.check(ViewInteraction.java:158)
at 
com.example.joakes.espressodesignsupportlib.MainActivityTest.testOne(MainActivit
yTest.java:29)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at 
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java
:50)
at 
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:
12)
at 
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:4
7)
at 
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17
)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at 
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78
)
at 
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57
)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at 
android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:54)
at 
android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:2
28)
at 
android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1701)

and

android.support.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCaus
eError: 'with text: is "Test"' doesn't match the selected view.
Expected: with text: is "Test"
Got: "CollapsingToolbarLayout{id=2131492966, res-name=collapsing_tool_bar, 
visibility=VISIBLE, width=1080, height=600, has-focus=false, 
has-focusable=false, has-window-focus=true, 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}"

at dalvik.system.VMStack.getThreadStackTrace(Native Method)
at java.lang.Thread.getStackTrace(Thread.java:579)
at 
android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(De
faultFailureHandler.java:82)
at 
android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHa
ndler.java:53)
at 
android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInt
eraction.java:184)
at android.support.test.espresso.ViewInteraction.check(ViewInteraction.java:158)
at 
com.example.joakes.espressodesignsupportlib.MainActivityTest.testTwo(MainActivit
yTest.java:34)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at 
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java
:50)
at 
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:
12)
at 
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:4
7)
at 
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17
)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at 
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78
)
at 
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57
)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at 
android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:54)
at 
android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:2
28)
at 
android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1701)
Caused by: junit.framework.AssertionFailedError: 'with text: is "Test"' doesn't 
match the selected view.
Expected: with text: is "Test"
Got: "CollapsingToolbarLayout{id=2131492966, res-name=collapsing_tool_bar, 
visibility=VISIBLE, width=1080, height=600, has-focus=false, 
has-focusable=false, has-window-focus=true, 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}"

at 
android.support.test.espresso.matcher.ViewMatchers.assertThat(ViewMatchers.java:
1013)
at 
android.support.test.espresso.assertion.ViewAssertions$2.check(ViewAssertions.ja
va:89)
at android.support.test.espresso.ViewInteraction$2.run(ViewInteraction.java:170)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at 
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)

Original issue reported on code.google.com by jacoboak...@gmail.com on 19 Aug 2015 at 12:48

gnumilanix commented 8 years ago

Here's how you can do it: First we create custom matcher

public static Matcher<Object> withCollapsibleToolbarTitle(final Matcher<String> textMatcher) {
        return new BoundedMatcher<Object, CollapsingToolbarLayout>(CollapsingToolbarLayout.class) {
            @Override
            public void describeTo(Description description) {
                description.appendText("with toolbar title: ");
                textMatcher.describeTo(description);
            }
            @Override
            protected boolean matchesSafely(CollapsingToolbarLayout toolbarLayout) {
                return textMatcher.matches(toolbarLayout.getTitle());
            }
        };
    }

Then we match it:

onView(isAssignableFrom(CollapsingToolbarLayout.class)).
                check(matches(withCollapsibleToolbarTitle(is(getString(R.string.message_hello)))));
frugoman commented 5 years ago

Is there any update on this issue? I used @gnumilanix solution btw and worked perfectly but it's not the most straight forward way to do it and it's still a workaround

milosmns commented 4 years ago

Stumbled upon this after a while, basically yeah, what @gnumilanix gave is right. I wouldn't say it's a workaround though, but rather that it's just a new/custom view that doesn't have Matcher support yet. Anyway, I converted that to Kotlin and cleaned it up a bit:


object CustomMatchers {

  fun withCollapsingToolbarTitle(@StringRes titleId: Int) =
    object : TypedBoundedMatcher<Any, CollapsingToolbarLayout>(CollapsingToolbarLayout::class) {
      // used for descriptions
      private lateinit var context: Context
      private lateinit var titleText: String
      private lateinit var titleResName: String

      override fun matchesSafely(view: CollapsingToolbarLayout): Boolean {
        context = view.context
        titleText = context.getString(titleId)
        titleResName = context.resources.getResourceName(titleId)
        return view.title == titleText
      }

      override fun describeTo(description: Description?) = description.use {
        appendText("with collapsing toolbar title ID: ")
        appendValue(titleId)
      }

      override fun describeMismatchTyped(item: CollapsingToolbarLayout, description: Description) = description.use {
        appendText("with collapsing toolbar title ID: ")
        appendValue(titleResName)
        appendText("resolved as: ")
        appendValue(titleText)
        appendText("and actual title: ")
        appendValue(item.title)
      }
    }

}

// Adds type safety to describe callbacks
abstract class TypedBoundedMatcher<T : Any, S : T>(
  private val expectedType: KClass<out S>
) : BoundedMatcher<T, S>(expectedType.java) {

  @Suppress("UNCHECKED_CAST")
  override fun describeMismatch(item: Any?, description: Description) = when {
    item == null || !expectedType.java.isInstance(item) -> super.describeMismatch(item, description)
    else -> describeMismatchTyped(item as S, description)
  }

  abstract fun describeMismatchTyped(item: S, description: Description)
}

fun Description?.use(block: Description.() -> Any?) = this?.let(block)?.let { Unit } ?: Unit

Ofc you can go with the type-unsafe bounded matcher, but.. Kotlin is so type-safe with awesome type inference, so I'll use it.