Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActivityScenario: expectations for Activity.isTaskRoot() behavior #427

Open
ssaqua opened this issue Aug 15, 2019 · 9 comments
Open

ActivityScenario: expectations for Activity.isTaskRoot() behavior #427

ssaqua opened this issue Aug 15, 2019 · 9 comments

Comments

@ssaqua
Copy link

ssaqua commented Aug 15, 2019

Description

When using ActivityScenario to test activities, the activity under test is not considered as the task root. I guess this is by design since FLAG_ACTIVITY_NEW_TASK is masked when launched via BootstrapActivity in InstrumentationActivityInvoker. For activities that make use of Activity.isTaskRoot() this could lead to unexpected behaviors during testing since the activity under test isn't actually the root of the task. This is a behavior change compared to running the test with ActivityTestRule or in some cases compared to running the real application. Is it reasonable to expect the activity under test to be considered as the task root even if it is somehow faked or configurable to return true?

Steps to Reproduce

minimal sample:

// in main source set as the launcher activity
class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (!isTaskRoot) {
            finish()
        }
    }
}

// in test sources
class MainActivityTest {
    @Test
    fun scenario() {
        ActivityScenario.launch(MainActivity::class.java).onActivity { }
    }

    @Test
    fun testRule() {
        val rule = ActivityTestRule(MainActivity::class.java, true, false)
        rule.launchActivity(null)
        assertTrue(rule.activity.isTaskRoot)
    }
}

Expected Results

Be able to test activities that are making use of isTaskRoot() reliably.

Actual Results

scenario test case cannot run onActivity since the activity is immediately finished.
testRule test case works as expected.

AndroidX Test and Android OS Versions

1.2.1-alpha02, API 28

@EliyahuShwartz
Copy link

EliyahuShwartz commented Jan 8, 2020

You can start the activity with intent ( isTaskRoot() will be true ) :

 val intent = Intent(
           ApplicationProvider.getApplicationContext<%mainApplication%>(),
           %yourActivity%::class.java
       )

       val activityScenario = ActivityScenario.launch<%yourActivity%>(intent)

works for me

@ssaqua
Copy link
Author

ssaqua commented Jan 8, 2020

You can start the activity with intent ( isTaskRoot() will be true ) :

 val intent = Intent(
           ApplicationProvider.getApplicationContext<%mainApplication%>(),
           %yourActivity%::class.java
       )

       val activityScenario = ActivityScenario.launch<%yourActivity%>(intent)

works for me

The issue occurs when you call onActivity after launch. The test will pass if you just call launch by itself regardless of whether you pass an intent or actvity class.

java.lang.NullPointerException: Cannot run onActivity since Activity has been destroyed already

launch(Class<A> activityClass) internally just calls the intent version anyway, so I don't believe we should expect a different result.

@lwasyl
Copy link

lwasyl commented Feb 5, 2020

I'm not sure this is directly related, but once I migrated to ActivityScenario, my tests involving opening deep links started failing, since NavigationComponent will now recreate the stack, but not pop it when pressing back button for example. The only change was to migrate to ActivityScenario, and we did pass Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK in the intent previously to make sure NavComponent recreates the backstack properly

@lwasyl
Copy link

lwasyl commented Apr 28, 2020

Is there any update on this? Seeing as ActivityTestRule is deprecated, it'd be nice to have a clear migration for tests using deep links with navigation component

@guillermomuntaner
Copy link

Similar situation here, we have very large tests flowing through several activities. We have a launcher activity that relies on isTaskRoot and migrating from ActivityTestRule to androidx testing is a problem

@gosr
Copy link

gosr commented Mar 11, 2021

@brettchabot can you please provide an update here? It stops all of us from migrating from ActivityTestRule for tests using deep links.

@RegFacu
Copy link

RegFacu commented Mar 12, 2021

Same here ! I want to test if the Activity A is shown after I open the Activity B with a Deeplink and close the Activity B

@milhauscz
Copy link

milhauscz commented Apr 16, 2021

I've made a custom workaround, which registers ActivityLifecycleCallbacks and saves / removes Activities to a stack. Then I check whether a given Activity is the task root as follows:

    **
     * Returns whether the given Activity is the root of the task while ignoring BootstrapActivity
     * started by UI tests.
     */
    public static boolean isTaskRoot(Activity activity) {
        Activity root = mActivityStack.peekLast();
        if (root != null && Objects.equals(root.getLocalClassName(), "androidx.test.core.app.InstrumentationActivityInvoker$BootstrapActivity")) {
            // BootstrapActivity is the real root -> return true if our Activity is second
            return mActivityStack.size() >= 2 && mActivityStack.get(mActivityStack.size() - 2) == activity;
        } else {
            // there is no BootstrapActivity -> just use isTaskRoot()
            return activity.isTaskRoot();
        }
    }

@mattinger
Copy link

What i've done to solve this issue is to use a bundle argument to disable the check:

if (!isTaskRoot && !intent.getBooleanExtra("ignoreTaskRootCheck", false)) {

and when i launch:

        val scenario = ActivityScenario.launch<SplashActivity>(
            Intent(ApplicationProvider.getApplicationContext(), SplashActivity::class.java).apply {
                putExtra("ignoreTaskRootCheck", true)
            }
        )

It's a bit hacky, but it works.

Zemotacqy pushed a commit to Zemotacqy/android-test that referenced this issue May 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants