test(compose): Robolectric JVM tests for rich-text format controls (#376) #394

Merged
JMR-dev merged 2 commits from test-376-robolectric-richtext into main 2026-07-07 01:09:41 +00:00
JMR-dev commented 2026-07-07 00:50:39 +00:00 (Migrated from github.com)

Batch 1/9 of the Robolectric Compose umbrella (#373). Converts the stateless rich-text format controls to Robolectric JVM Compose tests in the test source set and drops them from jacocoNonJvmTestableSurface.

Closes #376.

Tests added (src/test, JVM — no emulator)

Each mirrors its existing instrumented androidTest counterpart (which stays as the on-device E2E), following the #375 PoC pattern: @RunWith(RobolectricTestRunner) + @GraphicsMode(NATIVE) + @Config(sdk=[36]), v2 createComposeRule().

New JVM test Covers Line coverage
ColorSwatchRowJvmTest ColorSwatchRow.kt, ColorSwatch.kt 40/46
FontPickerJvmTest FontPicker.kt 43/43
FontSizePickerJvmTest FontSizePicker.kt 43/43
ParagraphAlignmentControlJvmTest ParagraphAlignmentControl.kt 34/34

They assert render, selected/unselected state, dropdown open, and the null-vs-value onSelect branch — genuine coverage, not smoke tests. (The 6 uncovered ColorSwatchRow lines are the Canvas slash-draw lambda for the "no color" swatch, which Robolectric's NATIVE graphics doesn't run in the draw phase; the kept instrumented test exercises real-device rendering.)

Removed from jacocoNonJvmTestableSurface

**/ColorSwatch*, **/FontPicker*, **/FontSizePicker*, **/ParagraphAlignmentControl* (replaced with a breadcrumb comment). FontRegistry.kt stays out of the list — it is plain logic, already JVM-covered by FontRegistryTest.

⚠️ Infra fix folded in (heads-up for siblings 2/9–9/9)

While validating, I found the #375 infra was silently recording zero JaCoCo coverage for every Robolectric-run composable — including the PoC AddAnotherAccountScreen. Cause: the JaCoCo agent skips classes with no code-source location, which is exactly how Robolectric loads the classes-under-test through its sandbox classloader. #375's single 40-line PoC didn't breach the 0.79 floor, so the gap stayed hidden; this 4-file (166-line) batch is the first to expose it (verification failed at 0.78).

Fix: isIncludeNoLocationClasses = true (+ jdk.internal.* exclude) on the Test tasks. With it, Robolectric coverage registers and the scoped bundle rises ~0.80 → 0.8217. This is a one-time fix that unblocks the whole epic (coverage now rises as batches land, as #386's re-ratchet assumes) — siblings should not duplicate it. It lives near the jacoco {} block, away from the exclusion list, so it won't add to the trivial exclusion-list conflicts between batches.

Per the ticket, the floor stays at 0.79 (the re-ratchet is #386).

Gate (JVM, local)

assembleDebug + testDebugUnitTest (19 new tests green) + jacocoTestCoverageVerification (0.8217 ≥ 0.79) + compileDebugAndroidTestKotlin + lintDebug + ktlintCheck + detekt — all green.

🤖 Generated with Claude Code

Batch 1/9 of the Robolectric Compose umbrella (#373). Converts the stateless rich-text format controls to **Robolectric JVM Compose tests** in the `test` source set and drops them from `jacocoNonJvmTestableSurface`. Closes #376. ## Tests added (`src/test`, JVM — no emulator) Each mirrors its existing instrumented `androidTest` counterpart (which stays as the on-device E2E), following the #375 PoC pattern: `@RunWith(RobolectricTestRunner)` + `@GraphicsMode(NATIVE)` + `@Config(sdk=[36])`, v2 `createComposeRule()`. | New JVM test | Covers | Line coverage | |---|---|---| | `ColorSwatchRowJvmTest` | `ColorSwatchRow.kt`, `ColorSwatch.kt` | 40/46 | | `FontPickerJvmTest` | `FontPicker.kt` | 43/43 | | `FontSizePickerJvmTest` | `FontSizePicker.kt` | 43/43 | | `ParagraphAlignmentControlJvmTest` | `ParagraphAlignmentControl.kt` | 34/34 | They assert render, selected/unselected state, dropdown open, and the null-vs-value `onSelect` branch — genuine coverage, not smoke tests. (The 6 uncovered `ColorSwatchRow` lines are the `Canvas` slash-draw lambda for the "no color" swatch, which Robolectric's NATIVE graphics doesn't run in the draw phase; the kept instrumented test exercises real-device rendering.) ## Removed from `jacocoNonJvmTestableSurface` `**/ColorSwatch*`, `**/FontPicker*`, `**/FontSizePicker*`, `**/ParagraphAlignmentControl*` (replaced with a breadcrumb comment). `FontRegistry.kt` stays out of the list — it is plain logic, already JVM-covered by `FontRegistryTest`. ## ⚠️ Infra fix folded in (heads-up for siblings 2/9–9/9) While validating, I found the #375 infra was **silently recording zero JaCoCo coverage for every Robolectric-run composable — including the PoC `AddAnotherAccountScreen`**. Cause: the JaCoCo agent skips classes with no code-source location, which is exactly how Robolectric loads the classes-under-test through its sandbox classloader. #375's single 40-line PoC didn't breach the 0.79 floor, so the gap stayed hidden; this 4-file (166-line) batch is the first to expose it (verification failed at **0.78**). Fix: `isIncludeNoLocationClasses = true` (+ `jdk.internal.*` exclude) on the `Test` tasks. With it, Robolectric coverage registers and the scoped bundle rises **~0.80 → 0.8217**. This is a one-time fix that unblocks the whole epic (coverage now *rises* as batches land, as #386's re-ratchet assumes) — **siblings should not duplicate it.** It lives near the `jacoco {}` block, away from the exclusion list, so it won't add to the trivial exclusion-list conflicts between batches. Per the ticket, the **floor stays at 0.79** (the re-ratchet is #386). ## Gate (JVM, local) `assembleDebug` + `testDebugUnitTest` (19 new tests green) + `jacocoTestCoverageVerification` (0.8217 ≥ 0.79) + `compileDebugAndroidTestKotlin` + `lintDebug` + `ktlintCheck` + `detekt` — all green. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.