ワンクリックで
compose-tests
// Use when writing Compose UI tests in stripe-android — covers composeRule setup, Robolectric annotations, node assertions, and test tag patterns
// Use when writing Compose UI tests in stripe-android — covers composeRule setup, Robolectric annotations, node assertions, and test tag patterns
Use when writing NetworkRule integration tests in stripe-android — covers testBodyFromFile, inline JSON modification, request matchers, and fixture patterns
Use when writing or structuring unit tests in stripe-android — covers runScenario pattern, fakes, Turbine Flow testing, and Truth assertions
Use when writing or running Paparazzi screenshot tests in stripe-android — covers PaparazziRule setup, recording/verifying commands, and test structure
Use when creating a fake test implementation in stripe-android — covers FakeClassName pattern, Turbine call tracking, ViewActionRecorder, and ensureAllEventsConsumed validation
| name | compose-tests |
| description | Use when writing Compose UI tests in stripe-android — covers composeRule setup, Robolectric annotations, node assertions, and test tag patterns |
Patterns for testing Jetpack Compose UI in the Stripe Android SDK.
Every Compose test needs three rules and Robolectric:
@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 harnesscreateComposeCleanupRule() — workaround for Robolectric resource leak (import from com.stripe.android.testing)CoroutineTestRule — controls coroutine dispatching in testsUse the same runScenario pattern from write-unit-tests, wrapping composeRule.setContent:
@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)
| 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 |
| 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 |
| Action | Purpose |
|---|---|
performClick() | Tap element |
performTextReplacement("text") | Set text field value |
performScrollTo() | Scroll element into view |
Define tags as constants in production code, use Modifier.testTag():
// 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()
// 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()
}
composeCleanupRule — causes resource leaks with Robolectric, flaky tests@RunWith(RobolectricTestRunner::class) — Compose tests need Android frameworkonNodeWithText for dynamic content — prefer test tags for stabilitywaitForIdle() after state changes — assertions may run before recomposition