Conversation
…plugin - Add experimental screenshot testing flag to gradle.properties - Add screenshot testing plugin (v0.0.1-alpha12) to version catalog - Configure screenshot plugin in app/build.gradle.kts - Add screenshot testing dependencies (screenshotTestImplementation) - Set image difference threshold to 1% This is Phase 1 of the screenshot testing integration, enabling the framework for upcoming preview screenshot tests.
Modified preview functions (private → internal, descriptive names): - LineIndicator: 1 preview (LineIndicatorPreview) - InfoBannerComponent: 4 previews (with @PreviewLightDark support) - BusArrivalListItem: 6 state variations Created screenshotTest wrappers with @previewTest: - LineIndicatorScreenshotTests.kt - InfoBannerComponentScreenshotTests.kt - BusArrivalListItemScreenshotTests.kt This implements the wrapper pattern: previews stay in main source (preserving IDE visibility) while minimal wrappers in screenshotTest enable screenshot testing without code duplication. Phase 2 complete. Next: validation (build, generate references).
…enshots Phase 3 fixes and completion: - Fix artifact coordinates: com.android.tools.screenshot (not com.android.compose.screenshot) - Add @Preview annotation requirement for @previewTest (both annotations needed) - Upgrade project to Java 21 for screenshot testing compatibility - Add screenshotTest AndroidManifest.xml - Generate 11 reference screenshots for 3 pilot components: * LineIndicatorScreenshotTests: 1 screenshot * InfoBannerComponentScreenshotTests: 4 screenshots (including @PreviewLightDark variants) * BusArrivalListItemScreenshotTests: 6 state variations Reference images stored in: app/src/screenshotTestDebug/reference/ All screenshot tests now passing ✅
- Replace all Random.nextLong() calls with deterministic counter - Replace all .shuffled() calls with fixed index-based selections - Replace all .random() calls with fixed index selections in arrivals - Update routesWithStops to use deterministic stop selections - Update searchResults to use fixed stop/line indices - Update cardInfoTransactions with fixed serial numbers - Remove unused Random import This ensures screenshot tests produce consistent, reproducible results across test runs. Different edge cases are still covered (varying numbers of lines per stop, different card types, etc.) but in a predictable way.
- Add new "Screenshot Testing" section with complete workflow - Document wrapper pattern for maintaining IDE preview visibility - Include step-by-step guide for adding new screenshot tests - Add troubleshooting section for common issues - Document deterministic test data requirements - Include configuration details and directory structure - Add screenshot test commands to Testing and Quality section The guide covers: - Creating preview functions with internal visibility - Creating test wrappers in screenshotTest source set - Generating and validating reference screenshots - Best practices for deterministic test data - Examples from existing tests (BusArrivalListItem, InfoBanner, LineIndicator)
Phase 4 - Complete migration of all @Preview functions to screenshot tests. ## Changes Summary ### Main Source Files (38 files modified) - Changed all preview functions from `private` to `internal` visibility - Fixed non-deterministic data patterns in 5 files: - StopDetailScreen.kt: replaced .shuffled().take() with fixed indices - FavoriteListItem.kt: replaced .shuffled().take() with fixed indices - NearbyListItem.kt: replaced .shuffled().take() with fixed indices - LineRouteScreen.kt: replaced .shuffled() with deterministic data - RoundedSearchBar.kt: replaced .random() with fixed indices - Resolved naming conflicts (8 preview functions): - Renamed generic Preview() → ComponentNamePreview() - Renamed generic LoadingPreview() → ComponentNameLoadingPreview() - Updated: ArrivalTimeElement, CircularIconButton, RouteTabsSelector, SegmentedControl, FavoriteListItem, FavoritesWidget, NearbyListItem, NearbyWidget ### Test Files (93 new test wrapper files) - Created screenshot test wrappers for all preview functions - Pattern: app/src/screenshotTest/kotlin/[same/package/path]/ComponentScreenshotTests.kt - All test wrappers use @Preview + @previewTest annotations - Test function names use camelCase, preview functions use PascalCase ### Reference Screenshots (76 PNG files) - Generated in app/src/screenshotTestDebug/reference/ - Covers UI components, feature screens, and infrastructure components - 55 tests passing, 1 failing (CardsScreen - layoutlib issue), 1 skipped ### Configuration - gradle.properties: Increased heap from 2GB → 6GB for screenshot rendering ## Test Coverage **Components with screenshot tests:** - UI Components (17): BusArrivalListItem, InfoBanner, LineIndicator, AppUpdateButton, IconPicker, SevNavigationBar, FakeReviewDialog, SurfaceButton, RouteTabsSelector, SegmentedControl, ArrivalTimeElement, CircularIconButton, StopCardElement, LineElement - Features (19): ForYouScreen, FavoritesWidget, NearbyWidget, FavoriteListItem, NearbyListItem, AlertWidget, CardsScreen, CardBalanceItem, CardInfoElement, CardTransactionsElement, CardsHelpScreen, LinesScreen, LineRouteScreen, StopTimelineElement, MapScreen, BusIcon, CircularStopIcon, OutlinedStopIcon, ShapedStopIcon, SearchScreen, RoundedSearchBar, StopDetailScreen, SettingsScreen, EditFavoritesScreen, App, AppLayoutPlayground - Infrastructure (2): NightModeSelectorBottomSheet, Star icon ## Known Issues - 1 test fails due to layoutlib rendering error (CardsScreen loadedWithTransactionsPreview) Error: Resources_Delegate.initSystem called twice - framework issue, not code ## Statistics - Total preview functions: 125+ - Test wrapper files created: 93 - Reference screenshots: 76 - Success rate: 98% (55/56 attempted renders)
The preview was rendering all 22 cards from Stubs.cards, each with 5 transactions (110 UI elements total), which overwhelmed the layoutlib renderer causing "Resources_Delegate.initSystem called twice" error. Reduced to first 3 cards (15 transaction UI elements) to avoid overloading the preview renderer while still demonstrating the UI.
There was a problem hiding this comment.
Pull request overview
This PR integrates Compose Preview Screenshot Testing into the project, establishing automated visual regression testing for all UI components. The implementation covers 93 screenshot tests across 49 files, with all preview functions refactored to use deterministic test data. The setup uses a wrapper pattern where preview functions remain in main source (visible in IDE) while test wrappers live in the screenshotTest source set.
Key changes:
- Added Compose Screenshot Testing plugin (v0.0.1-alpha12) with 1% image difference threshold
- Migrated all 125+ previews to screenshot testing with deterministic test data
- Increased Gradle heap to 6GB to support the large test suite
- Added comprehensive documentation in CLAUDE.md
Reviewed changes
Copilot reviewed 89 out of 166 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| gradle/libs.versions.toml | Added compose-screenshot plugin and validation library dependencies |
| gradle.properties | Enabled experimental screenshot testing and increased JVM heap to 6GB |
| app/build.gradle.kts | Applied screenshot plugin, configured test options with 1% threshold |
| app/src/screenshotTest/AndroidManifest.xml | Added required empty manifest for screenshotTest source set |
| app/src/screenshotTest/kotlin/**/*ScreenshotTests.kt (93 files) | Created test wrapper classes that reference preview functions with @previewTest |
| app/src/main/java/**/*.kt (49 files) | Changed preview function visibility from private to internal for screenshotTest access |
| app/src/main/java/com/sloy/sevibus/Stubs.kt | Refactored to eliminate all random/non-deterministic patterns for stable screenshots |
| CLAUDE.md | Added comprehensive screenshot testing documentation with setup, usage, and troubleshooting |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| fun noPemissionPreview() { | ||
| NoPemissionPreview() |
There was a problem hiding this comment.
Corrected spelling of 'Pemission' to 'Permission' in function name.
| fun noPemissionPreview() { | |
| NoPemissionPreview() | |
| fun noPermissionPreview() { | |
| NoPermissionPreview() |
Summary
Integrates Compose Preview Screenshot Testing into the project, enabling automated visual regression testing for all Compose previews. This implementation covers 93 screenshot tests across 49 files with deterministic test data.
What's Included
Phase 1: Configuration ✅
Phase 2: Pilot Implementation ✅
Phase 3: Deterministic Test Data ✅
.random(),.shuffled(), andRandom.nextInt()usagePhase 4: Full Migration ✅
Bug Fixes ✅
Test Results
Key Features
File Changes
Remaining Work
Phase 5: CI/CD Integration (Future)
To complete the screenshot testing workflow, the following CI/CD tasks remain:
GitHub Actions Workflow
Automated Screenshot Updates
Memory Optimization
Known Limitations
Testing
Documentation
See CLAUDE.md for: