Skip to main content

compose-tests

Use when writing Compose UI tests in stripe-android — covers composeRule setup, Robolectric annotations, node assertions, and test tag patterns

Ir a la instalación

Datos de origen

Repositorio
stripe/stripe-android
Última actividad en el origen
15 de julio de 2026 a las 12:58
Idioma detectado de SKILL.md
inglés
Estrellas
1537
Forks
736

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
compose-tests
description
Use when writing Compose UI tests in stripe-android — covers composeRule setup, Robolectric annotations, node assertions, and test tag patterns
# Compose UI Tests Patterns for testing Jetpack Compose UI in the Stripe Android SDK. ## Test Class Setup Every Compose test needs three rules and Robolectric: ```kotlin @RunWith(RobolectricTestRunner::class) internal class MyComposableTest { @get:Rule val composeRule = createComposeRule() @get:Rule val composeCleanupRule = createComposeCleanupRule() @get:Rule val coroutineTestRule = CoroutineTestRule(UnconfinedTestDispatcher()) } ``` - `createComposeRule()` — provides the Compose test harness - `createComposeCleanupRule()` — workaround for Robolectric resource leak (import from `com.stripe.android.testing`) - `CoroutineTestRule` — controls coroutine dispatching in tests ## runScenario for Compose Tests Use the same `runScenario` pattern from `write-unit-tests`, wrapping `composeRule.setContent`: ```kotlin @Test fun `required fields are visible`() = runScenario { page.country.assertIsDisplayed() page.zipCode.assertIsDisplayed() page.line1.assertDoesNotExist() } @Test fun `input changes update state`() = runScenario( addressCollectionMode = AddressCollectionMode.Full, ) { page.zipCode.performTextReplacement("94100") assertThat(formState?.postalCode?.value).isEqualTo("94100") } private fun runScenario( addressCollectionMode: AddressCollectionMode = AddressCollectionMode.Automatic, block: TestScenario.() -> Unit, ) { composeRule.setContent { MyComposableUI(addressCollectionMode = addressCollectionMode) } block(TestScenario(MyPage(composeRule))) } private data class TestScenario(val page: MyPage) ``` ## Finding Nodes | Finder | Use when | |--------|----------| | `onNodeWithTag(TAG)` | Element has a test tag (preferred) | | `onNodeWithContentDescription("desc")` | Testing accessibility only — prefer test tags otherwise | | `onAllNodesWithTag(TAG)` | Multiple elements share a tag | | `onNode(hasTestTag(TAG).and(hasText("x")))` | Combining matchers | ## Assertions | Assertion | Purpose | |-----------|---------| | `assertIsDisplayed()` | Element is visible | | `assertExists()` | Element exists (may not be visible) | | `assertDoesNotExist()` | Element not in hierarchy | | `assertIsNotDisplayed()` | Exists but not visible | | `assertIsEnabled()` / `assertIsNotEnabled()` | Enabled state | | `assertTextContains("text")` | Text field contains value | | `assertContentDescriptionContains("desc")` | Accessibility description | | `assert(hasText("text"))` | General matcher assertion | ## Actions | Action | Purpose | |--------|---------| | `performClick()` | Tap element | | `performTextReplacement("text")` | Set text field value | | `performScrollTo()` | Scroll element into view | ## Test Tags Define tags as constants in production code, use `Modifier.testTag()`: ```kotlin // In production code: internal const val SAVE_BUTTON_TEST_TAG = "save_button" Box(modifier = Modifier.testTag(SAVE_BUTTON_TEST_TAG)) { ... } // In test code: composeRule.onNodeWithTag(SAVE_BUTTON_TEST_TAG).assertIsDisplayed() ``` ## Waiting for Recomposition ```kotlin // Wait for pending recompositions composeRule.waitForIdle() // Wait for async content with timeout composeRule.waitUntil(timeoutMillis = DEFAULT_UI_TIMEOUT.inWholeMilliseconds) { composeRule.onAllNodesWithTag(MY_TAG).fetchSemanticsNodes().isNotEmpty() } ``` ## Common Mistakes - **Missing `composeCleanupRule`** — causes resource leaks with Robolectric, flaky tests - **Missing `@RunWith(RobolectricTestRunner::class)`** — Compose tests need Android framework - **Using `onNodeWithText` for dynamic content** — prefer test tags for stability - **Not calling `waitForIdle()` after state changes** — assertions may run before recomposition
Ver en GitHub