3

I have a composable with a button that launches one of the native activities (Google Settings). To test this before compose (using Robolectric) I would do something like this:

My test:

@Test
fun `MyFragment - when button clicked - starts activity`() {
    // ...
    val shadowActivity: ShadowActivity = Shadow.extract(activity)
    val nextStartedActivity = shadowActivity.nextStartedActivity
    assertNotNull(nextStartedActivity)
    assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, nextStartedActivity.action)
}

With compose tests (not using activity scenario) it's different. There is no activity handle, only a composeTestRule:

My test:

// ...

private val buttonNode get() = composeTestRule.onNodeWithContentDescription("Button")

@Test
fun `MyComposableToTest - when button clicked - starts activity`() {
    composeTestRule.setContent {
        MyComposableToTest()
    }

    buttonNode.assertExists().assertHasClickAction().assertIsEnabled().performClick()

    // No possibility to get current activity
}

How can I assert that a new activity is started when testing a Composable?

Some context:

  • Android Gradle Plugin 7.0.3
  • Robolectric 4.7.3
  • Compose 1.1.0-beta04
Mahozad
  • 18,032
  • 13
  • 118
  • 133
Alix
  • 2,630
  • 30
  • 72

2 Answers2

3

You are able to fetch the context from the ComposeContentTestRule like this:

lateinit var context : Context
composeTestRule.setContent {
    context = LocalContext.current
    MyComposableToTest()
}

and then to assert the next started activity

val shadowActivity: ShadowActivity = Shadow.extract(context as ComponentActivity)
val nextStartedActivity = shadowActivity.nextStartedActivity
assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, nextStartedActivity.action)
promme
  • 66
  • 4
0

This is how I did it for my instrumented test (NOT using Robolectric).

build.gradle[.kts]:

androidTestImplementation("androidx.test.espresso:espresso-intents:3.4.0")

The test class (in src/androidTest/... directory):

import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.Intents.intended
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
// ...

@RunWith(AndroidJUnit4::class)
class MainActivityInstrumentedTest {
    @get:Rule val composeTestRule = createAndroidComposeRule<MainActivity>()

    @Test fun testTheIntent() {
        Intents.init() // IMPORTANT (to be able to use "intended" function)
        composeTestRule.setContent {
            MyAppTheme {
                MainScreen()
            }
        }
        composeTestRule.onNodeWithText("My Button").performClick()
        intended(hasComponent(MySecondActivity::class.java.name))
        Intents.release()
    }
}
Mahozad
  • 18,032
  • 13
  • 118
  • 133