Android test - Perform back button from device web browser

Viewed 921

Is there any way to perform back button from device web browser in order to return back into app ? App -> browser -> App. Writing test automation for an app using espresso android. This is what steps performing

  • Open link from app
  • Verify link and wait for web page to be loaded
  • Press back in order to go back to the app then repeat the same process for other links.
2 Answers

When you use the Espresso-Intents library, you can launch the web browser (or any other app) for real, using the intended() method. It will not launch as a mock. After the web browser has launched and the UI test method has finished, the Test Runner will automatically return back to your app and put the browser in the background, when the next test runs. So you do not need to manually trigger a Back button press.

Example:

app/build.gradle:

dependencies {
   ...
   androidTestImplementation 'androidx.test.espresso:espresso-intents:3.3.0'
}

LaunchBrowserInUiTest.java

import android.content.Intent;
import androidx.test.espresso.intent.rule.IntentsTestRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import com.company.app.R;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.intent.Intents.intended;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasData;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static org.hamcrest.Matchers.allOf;

@RunWith(AndroidJUnit4.class)
public class LaunchBrowserInUiTest {
    @Rule
    public IntentsTestRule<MyActivity> intentsTestRule = 
        new IntentsTestRule<>(MyActivity.class);

    @Test
    public void launchBrowserFromMyApp() {
        MyActivity activityUnderTest = intentsTestRule.getActivity();

        // Open the link from the app
        onView(withId(R.id.launch_browser)).perform(click());

        // This will launch system web browser with a new Intent.
        // Verify the correct link is launched
        intended(allOf(
                hasAction(Intent.ACTION_VIEW),
                hasData("https://www.website.com")));

        // Allow time for the web page to load in the browser app
        try {
            long FIVE_SECONDS = 5000;
            Thread.sleep(FIVE_SECONDS);
        } catch (InterruptedException e) { }

        // When this test method finishes, the browser will be put into
        // the background automatically. So when a new UI test starts,
        // this app will be brought to the foreground.
    }

    @Test
    public void launchNextTest() {
        MyActivity activityUnderTest = intentsTestRule.getActivity();

        // When the next UI test starts, this app will
        // be brought to the foreground automatically.
    }
}

Guidance:

You can use the built in system back button as a part of espresso to achieve this.

Espresso.pressBack()

I'd also encourage you to check out mocking the link intent so that you don't have to actually launch the web page, but instead validate that clicking the link triggers an intent.

Use a class like this to set up the intent

class LinkIntents() {
    companion object {
        fun generateLinkIntent(linkUri: String): Matcher<Intent> {
            val expectedIntent = allOf(hasAction(Intent.ACTION_VIEW), hasData(linkUri))
            intending(expectedIntent).respondWith(Instrumentation.ActivityResult(0, null))

            return expectedIntent
        }
    }
}

And then something like this to validate that the link was clicked

    fun validateLinkIntent(linkUri: String, viewToClick: ViewInteraction) {
        // Create Intent so that we don't actually launch the web page
        val expectedIntent = LinkIntents.generateLinkIntent(linkUri)
        // Click the link
        onView(viewToClick).perform(click())
        // Validate that the intent was called
        Intents.intended(expectedIntent)
    }
Related