Testing Android Deep Linking at OpenSooq

In OpenSooq, delivering a high-quality product is of utmost importance. To accomplish this goal, we use automated testing to catch bugs before they reach our users. One of the challenges that we face every release is testing deep linking.

 

 

The main goal of clicking on notification by users is getting the content they want to see. However, the internal process should handle the notification and the deep link inside this notification.  On Others hand, clicking on Add post notification should redirect the user to Add post screen inside the app. The challenge comes from handling the notification and deep link that relates this notification to our app.  At the end of the day,Android is just responsible for launching your app with the bundle that has the tag for you to know which screen/action you should redirect the user to.
OpenSooq is evolving rapidly adding new features every release, changing the designs to keep up to date to the market requirements. Most of these features have deep links to it. So, the problem of tackling the notification handling rises up, especially that we have UI changes on every release that it can break one or two deep links.
Imagine if you need to test 80 deep links and each one needs ~3 mins to test manually. So, the total of testing will become 4 hours, and this is a waste of tester time.  Testing them manually is like transferring the sea water to another sea in a spoon.

Here where Espresso comes to rescue

 

 

Testing leads to failure, and failure leads to Understanding

Why Espresso?

Espresso is targeted at developers, who believe that automated testing is an integral part of the development lifecycle. While it can be used for black-box testing, Espresso’s full power is unlocked by those who are familiar with the codebase under test.

So how we make our assertion to make sure that every deep link is working correctly, lets take a look at how it’s working under the hood

for that we need to solve 2 challenges
  1- We have more than 80 input(deep link) we need to iterate over.
 2- We need to idle the Espresso to wait for the required screen to show up.

let’s talk in code language and see how to translate this

First you have to launch the activity that responsible for catching your links

    @Rule
    public ActivityTestRule activityRule = new ActivityTestRule
            (SplashActivity.class) {
        @Override
        protected Intent getActivityIntent() {

            Intent intent = new Intent();
            String url = schemaConfiguration + deeplinkTestCase.path;
            intent.setAction(Intent.ACTION_VIEW);
            intent.setData(Uri.parse(url));
            return intent;
        }
    };

This rule is responsible for the first action it simulates triggering the android to launch Opensooq with the required deep link
where  schemaConfiguration is your domain

schemaConfiguration = "https://opensooq.com"

but you don’t want to do this for each deep link and this is the tricky part where Burst  will do the iteration for each deeplink
to solve our first problem. Burst is a testing tool made by Square. It’s a “A unit testing library for varying test data.” It helps write unit test that have a lot of different input. The idea is that it abstracts the input from the test case via enums
and this where you can put your all input in

@Burst
DeeplinkTestCase deeplinkTestCase;
public enum DeeplinkTestCase {

    HOME("home"),
    FAV_POSTS("favposts"),
     .....

  public final String path;

        DeeplinkTestCase(String path) {
            this.path =  path;
        }
}

so Burst will iterate this inputs in the rule that we defined to create the test case for you in this line

            String url = schemaConfiguration + deeplinkTestCase.path;
            intent.setAction(Intent.ACTION_VIEW);
            intent.setData(Uri.parse(url));

just create your test and burst will iterate each input for you

@Test
public void testDeeplinks() throws Exception {
    switch (deeplinkTestCase) {
      case HOME:
     //wait for the activity 
    //do your assertion 
 ....
}

Now the second problem we need to wait the screen to show before doing any assertion on it
Espresso tests run optimally fast! It lets you leave your waits, syncs, sleeps, and polls behind while it manipulates and asserts on the application UI when it is at rest.
We need to create an IdleResource that waits until the activity is resumed

and this is the implementation of it

public class WaitActivityIsResumedIdlingResource implements IdlingResource {
    private final ActivityLifecycleMonitor activityMonitor;
    private final String activityToWaitClassName;
    private volatile ResourceCallback resourceCallback;
    boolean resumed = false;
  
    public WaitActivityIsResumedIdlingResource(String activityToWaitClassName) {
        activityMonitor = ActivityLifecycleMonitorRegistry.getInstance();
        this.activityToWaitClassName = activityToWaitClassName;
      
    }

    @Override
    public String getName() {
        return this.getClass().getName();
    }

    @Override
    public boolean isIdleNow() {
        resumed = isActivityLaunched();
        if(resumed && resourceCallback != null) {
            resourceCallback.onTransitionToIdle();
        }

        return resumed;
    }

    private boolean isActivityLaunched() {
        Collection<Activity> activitiesInStage =activityMonitor.getActivitiesInStage(Stage.RESUMED);
 for (Activity activity : activitiesInStage) {
 if(activity.getClass().getName().equals(activityToWaitClassName)){
 return true;
         }
   }
 return false;
 }

 @Override
 public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
 this.resourceCallback = resourceCallback;
 }
}

 

attach this IdleResource before your assertion and you are ready to go

With this technique, the OpenSooq code base can test ~80 deep link  in less than 200 lines of code.  And adding a new test is as simple as that. The output will be as below .