Espresso does no record any intent if there are no buttons

The solution is to register an idling resource to wait the second activity.

In my case the test will remain as follows:

  @Test
public void shoulddosomething() {
    startActivity();
    String templatePictureActivityClassName = TemplatePictureCaptureActivity.class.getName();
    Espresso.registerIdlingResources(new WaitActivityIsResumedIdlingResource(templatePictureActivityClassName));
    intended(hasComponent(hasClassName(templatePictureActivityClassName)));
}

And here the idling resource.

 private static class WaitActivityIsResumedIdlingResource implements IdlingResource {
    private final ActivityLifecycleMonitor instance;
    private final String activityToWaitClassName;
    private volatile ResourceCallback resourceCallback;
    boolean resumed = false;
    public WaitActivityIsResumedIdlingResource(String activityToWaitClassName) {
        instance = 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 = instance.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;
    }
}

This might be related to a race condition on the Intents component initialization and not with a race condition between the startActivity call and the usage of intended. If you start your activity from the SUT activity onCreate or onResume methods you should take a look at the following test rule.

I've created an IntentsTestRule fixing this issue. https://gist.github.com/pedrovgs/6a305ba4c5e3acfac854ce4c36558d9b

package com.aplazame.utils

import android.app.Activity
import androidx.test.espresso.intent.Intents
import androidx.test.rule.ActivityTestRule

class ExhaustiveIntentsTestRule<T : Activity> : ActivityTestRule<T> {

    private var isInitialized: Boolean = false

    constructor(activityClass: Class<T>) : super(activityClass)

    constructor(activityClass: Class<T>, initialTouchMode: Boolean) : super(activityClass, initialTouchMode)

    constructor(activityClass: Class<T>, initialTouchMode: Boolean, launchActivity: Boolean) : super(
        activityClass,
        initialTouchMode,
        launchActivity
    )

    override fun beforeActivityLaunched() {
        super.beforeActivityLaunched()
        Intents.init()
        isInitialized = true
    }

    override fun afterActivityFinished() {
        super.afterActivityFinished()
        if (isInitialized) {
            // Otherwise will throw a NPE if Intents.init() wasn't called.
            Intents.release()
            isInitialized = false
        }
    }
}

The main difference with the original IntentsTestRule implemented in AndroidX is the Intents.init() initialization. This time is invoked before starting the SUT activity. Keep in mind that this test rule will also record the intent used to start the SUT activity.