test(compose): Robolectric JVM Compose testing infra + PoC (#373) #375

Merged
JMR-dev merged 4 commits from robolectric-compose-scope into main 2026-07-06 23:36:36 +00:00
JMR-dev commented 2026-07-06 20:02:30 +00:00 (Migrated from github.com)

What

Lands the infrastructure + a runnable PoC for Robolectric-backed JVM unit testing of Jetpack Compose UI (umbrella #373). Robolectric runs the Android framework on the JVM, so createComposeRule() can drive composables with no emulator — bringing render-only screens into the JaCoCo JVM-testable + counted surface, so the jacocoNonJvmTestableSurface exclusions can shrink.

Feasibility: proven on this exact stack

Verified on AGP 9.2 (built-in Kotlin), Kotlin 2.4.0, Compose BOM 2026.06.00, JDK 21, JUnit4:

  • AddAnotherAccountScreenJvmTest — 3 tests, green on :app:testDebugUnitTest, no emulator. First test ~5s (Robolectric + NATIVE-graphics warmup), the rest <0.1s each.
  • Uses the v2 API androidx.compose.ui.test.junit4.v2.createComposeRule (v1 is deprecated in this BOM).

Changes

  • Robolectric 4.16.1 in test scope + Compose ui-test-junit4 / ui-test-manifest (reusing the BOM the app already applies).
  • testOptions.unitTests.isIncludeAndroidResources = true so stringResource(...) + Material3 theming resolve on the JVM.
  • app/src/test/resources/robolectric.properties pins sdk=36 — targetSdk 37 is a preview level Robolectric 4.16 ships no sandbox for (API 37 unsupported).
  • PoC test AddAnotherAccountScreenJvmTest (@RunWith(RobolectricTestRunner) + @GraphicsMode(NATIVE) + @Config(sdk = [36])).
  • Removed **/AddAnotherAccountScreen* from jacocoNonJvmTestableSurface (now genuinely JVM-covered); the bucket comment now documents the shrink-one-screen-at-a-time mechanism.

Not in this PR (deferred)

  • The remaining ~26 excluded Compose UI files are converted in per-area tickets under #373 (format controls, onboarding/lock, account setup, mail lists, settings, reader, compose editor, mailbox, app shell).
  • The JaCoCo floor re-ratchet is the final step of #373, after all conversions are stable — deliberately NOT touched here (floor stays 0.79).
  • Existing instrumented androidTest Compose tests are kept as-is (the instrumented E2E stays).

Gate

assembleDebug + testDebugUnitTest + jacocoTestCoverageVerification + compileDebugAndroidTestKotlin + lintDebug + ktlintCheck + detekt — all green locally.

No auto-merge (per spike instructions).

🤖 Generated with Claude Code

## What Lands the **infrastructure + a runnable PoC** for Robolectric-backed JVM unit testing of Jetpack Compose UI (umbrella #373). Robolectric runs the Android framework on the JVM, so `createComposeRule()` can drive composables with no emulator — bringing render-only screens into the JaCoCo JVM-testable + counted surface, so the `jacocoNonJvmTestableSurface` exclusions can shrink. ## Feasibility: proven on this exact stack Verified on AGP 9.2 (built-in Kotlin), Kotlin 2.4.0, Compose BOM 2026.06.00, JDK 21, JUnit4: - `AddAnotherAccountScreenJvmTest` — 3 tests, **green on `:app:testDebugUnitTest`**, no emulator. First test ~5s (Robolectric + NATIVE-graphics warmup), the rest <0.1s each. - Uses the **v2** API `androidx.compose.ui.test.junit4.v2.createComposeRule` (v1 is deprecated in this BOM). ## Changes - **Robolectric 4.16.1** in `test` scope + Compose `ui-test-junit4` / `ui-test-manifest` (reusing the BOM the app already applies). - `testOptions.unitTests.isIncludeAndroidResources = true` so `stringResource(...)` + Material3 theming resolve on the JVM. - `app/src/test/resources/robolectric.properties` pins `sdk=36` — targetSdk 37 is a preview level Robolectric 4.16 ships no sandbox for (API 37 unsupported). - PoC test `AddAnotherAccountScreenJvmTest` (`@RunWith(RobolectricTestRunner)` + `@GraphicsMode(NATIVE)` + `@Config(sdk = [36])`). - Removed `**/AddAnotherAccountScreen*` from `jacocoNonJvmTestableSurface` (now genuinely JVM-covered); the bucket comment now documents the shrink-one-screen-at-a-time mechanism. ## Not in this PR (deferred) - The remaining ~26 excluded Compose UI files are converted in **per-area tickets under #373** (format controls, onboarding/lock, account setup, mail lists, settings, reader, compose editor, mailbox, app shell). - **The JaCoCo floor re-ratchet is the final step of #373**, after all conversions are stable — deliberately NOT touched here (floor stays `0.79`). - Existing instrumented `androidTest` Compose tests are kept as-is (the instrumented E2E stays). ## Gate `assembleDebug` + `testDebugUnitTest` + `jacocoTestCoverageVerification` + `compileDebugAndroidTestKotlin` + `lintDebug` + `ktlintCheck` + `detekt` — all green locally. **No auto-merge** (per spike instructions). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.