AndroidStudio Running Recorded Espresso Test fails

563 views Asked by At

I'm trying to record an espresso test in AndroidStudio 4.2. The recording seems to work fine. However, when I try to run the recorded tests they run about halfway until there is an activity switch, then it fails because the views aren't found and I keep getting NoMatchingViewException.

I do a bunch of clicks in the first activity, which triggers the loading of a second activity. When running the test trying to find the view in the second activity never works.

@Test
fun firstRecordedTest() {
    val materialButton = onView(
        allOf(
            withId(R.id.key1Button), withText("1"),
            childAtPosition(
                childAtPosition(
                    withClassName(`is`("android.widget.LinearLayout")),
                    0
                ),
                3
            ),
            isDisplayed()
        )
    )
    materialButton.perform(click())
    
    // Activity switches here
    // The following never works

    val matcher: Matcher<View> = allOf(
        withId(R.id.tab_contacts), withContentDescription("Contacts"),
        childAtPosition(
            childAtPosition(
                withId(R.id.navigation_view),
                0
            ),
            1
        ),
        isDisplayed()
    )
    val bottomNavigationItemView = onView(matcher)
    bottomNavigationItemView.perform(click())
    
}

I have tried to put different kinds of timers etc to wait for the view to load, but either it gets stuck or it fails. I have also tried this answer with no luck.

Am I missing something? Is it not possible to continue a test after switching activity even if the espresso recorder allows it?

2

There are 2 answers

0
Shivam Pokhriyal On BEST ANSWER

You don't need timers with espresso. It'll wait until the activity is fully loaded, you can read about it here

Secondly, I haven't used the recorder myself since it creates a lot of noise. For instance the below code

val matcher: Matcher<View> = allOf(
        withId(R.id.tab_contacts), withContentDescription("Contacts"),
        childAtPosition(
            childAtPosition(
                withId(R.id.navigation_view),
                0
            ),
            1
        ),
        isDisplayed()
    )

which I'm assuming here clicks a button in the navigation_view. can simply be replaced with

onView(withId(R.id.tab_contacts)).perform(click())

Now, coming to why your test is failing, it seems like the materialButton click is doing some asynchronous work or doing some sort of animations. You can disable animations in your build.gradle like this

android {
    ...
    testOptions {
        animationsDisabled = true
    }
    ...
}

If you read here, and I summarise, espresso should wait to perform any action(in your case, clicking the tab_contacts) until the message queue is empty, it'll synchronise with async task as well, But espresso isn't aware of other asynchronous long running operations. So, if you're using some asynchronous operations, you should consider using an idling resource to have a reliable test.

But if you want a quick hack, you can use this sleep method:

    private fun sleep(millis: Long): ViewAction {
        return object : ViewAction {
            override fun getConstraints(): Matcher<View> {
                return isRoot()
            }

            override fun getDescription(): String {
                return "Going to sleep for " + millis + "milliseconds"
            }

            override fun perform(uiController: UiController, view: View) {
                uiController.loopMainThreadForAtLeast(millis)
            }
        }
    }

And call above method like this:

    onView(isRoot())
                .perform(sleep(
                        TimeUnit.SECONDS.toMillis(10)
                ))
0
robigroza On

Espresso is sometimes wonky with the views. Did you tried to use another view from the second activity or remove the view that causes tests to fail and run tests without it?