with one click
compose-ui-testing-hybrid-espresso
// Hybrid Compose + View testing — mixing Espresso.onView with ComposeTestRule, createAndroidComposeRule, UiAutomator testTagsAsResourceId, and createEmptyComposeRule.
// Hybrid Compose + View testing — mixing Espresso.onView with ComposeTestRule, createAndroidComposeRule, UiAutomator testTagsAsResourceId, and createEmptyComposeRule.
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | compose-ui-testing-hybrid-espresso |
| description | Hybrid Compose + View testing — mixing Espresso.onView with ComposeTestRule, createAndroidComposeRule, UiAutomator testTagsAsResourceId, and createEmptyComposeRule. |
| tech_stack | ["compose","android"] |
| language | ["kotlin"] |
| capability | ["integration-testing"] |
| version | Jetpack Compose 1.2.0-alpha08+ |
| collected_at | "2026-05-01T00:00:00.000Z" |
Source: https://developer.android.com/develop/ui/compose/testing/interoperability, https://developer.android.com/develop/ui/compose/testing
In hybrid apps (Compose + traditional Android Views), you can freely mix
Espresso.onView() with ComposeTestRule.onNode*() in the same test — no
special glue needed. This skill covers the rules, patterns, and pitfalls for
testing mixed View/Compose UIs, including createAndroidComposeRule,
createEmptyComposeRule, and UiAutomator integration via testTagsAsResourceId.
testTagcreateEmptyComposeRule)@get:Rule
val composeTestRule = createAndroidComposeRule<YourActivity>()
@Test
fun androidViewInteropTest() {
// Check View state with Espresso
Espresso.onView(withText("Hello Views")).check(matches(isDisplayed()))
// Interact with Compose
composeTestRule.onNodeWithText("Click here").performClick()
// Verify View updated
Espresso.onView(withText("Hello Compose")).check(matches(isDisplayed()))
}
| Rule factory | When |
|---|---|
createAndroidComposeRule<YourActivity>() | Hybrid: need both Activity access + Compose testing |
createEmptyComposeRule() | Inject Compose into existing View test fixture |
createComposeRule() | Pure Compose, no Activity (use setContent{}) |
androidTestImplementation("androidx.compose.ui:ui-test-junit4:$compose_version")
// Only needed for createComposeRule(), NOT for createAndroidComposeRule:
debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")
// 1. Enable in Compose hierarchy (once, high up)
Scaffold(
modifier = Modifier.semantics { testTagsAsResourceId = true }
) {
LazyColumn(modifier = Modifier.testTag("myLazyColumn")) { /* … */ }
}
// 2. Find in UiAutomator — use By.res(tag), NOT By.res(pkg, id)!
val device = UiDevice.getInstance(getInstrumentation())
val lazyColumn: UiObject2 = device.findObject(By.res("myLazyColumn"))
By.res(resourceName) not By.res(package, id) — the latter formats as
$pkg:id/$id, which differs from Modifier.testTag's value.testTagsAsResourceId requires Jetpack Compose ≥ 1.2.0-alpha08.testTagsAsResourceId once high in the hierarchy — it propagates
down to all nested testTag modifiers.ui-test-manifest dependency is not needed for
createAndroidComposeRule<YourActivity>() — the Activity already provides the
manifest.composeTestRule.waitForIdle() and
waitUntil(), or register Espresso idling resources via
composeTestRule.registerIdlingResource().waitForIdle, waitUntil,
IdlingResource).withText, withId, isDisplayed) are standard
Espresso — this skill only covers the interop boundary.