Android overhaul: one screenshot harness in :core:design's test fixtures; kvitt.android.screenshots wires Roborazzi

Eight modules each had a copy of the same configuration-context harness (ScreenSnapshots/Snapshots); M12f had to fix
the same capture bug in two of them. :core:design's test fixtures (src/testFixtures, package
se.hagstedt.kvitt.design.testing) now hold Variant, TestClock, TestEnvironment, ScreenSnapshots with its three
capture modes (Root; Screen, with the hand-advanced frame clock; ScreenWhenIdle), MainDispatcherRule and withMain.
Test fixtures rather than a :core:testing module: :core:design's own tests can use them without a dependency on
itself, no module is added to the §6.2 graph, and lint treats them as test sources. The architecture check rejects
test fixtures outside test configurations. Modules keep only their own frame (analytics household, settle size and
inline overlays, settings avatar pictures). Every golden is unchanged.

kvitt.android.screenshots applies Roborazzi with outputDir src/test/screenshots and adds the screenshot test
libraries; the feature plugin applies it and adds the test fixtures, so the seven feature build scripts lose their
copied blocks. Removed: roborazzi-junit-rule and roborazzi-compose (never imported), the explicit
lifecycle-viewmodel-compose (feature plugin, :app) and hilt-lifecycle-viewmodel-compose in :app (both still arrive
through the features; release and debug runtime classpaths are identical), and the unused catalog entries
androidx-hilt-navigation-compose and androidx-lifecycle-viewmodel-compose. @Before/@After setMain pairs in nine test
classes use MainDispatcherRule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
2026-10-18 22:54:03 +02:00
parent e4e6e5d792
commit 8229ed60ea
55 changed files with 472 additions and 664 deletions
@@ -11,6 +11,8 @@ import org.robolectric.annotation.GraphicsMode
import se.hagstedt.kvitt.fakes.FakeRepositories
import se.hagstedt.kvitt.fakes.FakeScenario
import se.hagstedt.kvitt.fakes.home.HomeScenarios
import se.hagstedt.kvitt.design.testing.ScreenSnapshots
import se.hagstedt.kvitt.design.testing.withMain
/** One state of a screen: its golden name, whether a 200 % capture is taken, and its content. */
class ScreenState(val name: String, val largeFont: Boolean = false, val content: @Composable () -> Unit)
@@ -87,7 +89,7 @@ class HomeScreenshotTest(private val state: String) {
@Test
fun screen() {
val screen = homeStates.first { it.name == state }
ScreenSnapshots.snap(compose, screen.name, screen.largeFont, screen.content)
ScreenSnapshots.snap(compose, screen.name, screen.largeFont, ScreenSnapshots.Capture.Screen, content = screen.content)
}
companion object {
@@ -11,9 +11,10 @@ import se.hagstedt.kvitt.fakes.FakeScenario
import se.hagstedt.kvitt.fakes.home.HomeScenarios
import se.hagstedt.kvitt.model.DefaultCategoryKey
import se.hagstedt.kvitt.model.SyncRejectionReason
import se.hagstedt.kvitt.model.UpdateRepository
import se.hagstedt.kvitt.model.UpdateCheck
import se.hagstedt.kvitt.model.UpdateRepository
import se.hagstedt.kvitt.model.UpdateState
import se.hagstedt.kvitt.design.testing.withMain
/** Records `install()` calls; the update state is set by the test (no mocking library, CLAUDE.md). */
private class RecordingUpdates(initial: UpdateState) : UpdateRepository {