-
Notifications
You must be signed in to change notification settings - Fork 42
Fix preview size retention bug #721
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Use RuntimeEnvironment.getQualifiers() to save current state - Restore original qualifiers after capture completes - Fixes issue where Preview annotation size persists between captures
WalkthroughIncreased GitHub Actions compare-screenshot-test job timeout. Updated RoborazziCompose captureRoboImage(File, ...) to save and restore Robolectric runtime qualifiers around capture. Added a new Robolectric test class to reproduce preview size retention behavior across sequential captures. Changes
Sequence Diagram(s)sequenceDiagram
participant Test as Test (Robolectric)
participant RC as captureRoboImage(File,...)
participant RE as RuntimeEnvironment
participant Cap as Image Capture
Test->>RC: captureRoboImage(file, options)
RC->>RE: getQualifiers()
RC->>RC: save savedQualifiers
RC->>Cap: perform capture (may change qualifiers)
Cap-->>RC: result
RC->>RE: setQualifiers(savedQualifiers) (finally)
RC-->>Test: return
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Nitpick comments (2)
roborazzi-compose/src/main/java/com/github/takahirom/roborazzi/RoborazziCompose.kt (1)
65-83
: Guard against parallel test interference when mutating global qualifiers.
RuntimeEnvironment.setQualifiers
affects global state. If Robolectric tests run in parallel forks/threads, interleaving could cause flaky dimensions. Consider serializing the critical section that mutates qualifiers.Minimal approach:
- Add a process-wide lock.
- Wrap the save/launch/capture/restore sequence in
synchronized
.Add this at top-level (outside any function):
private val qualifiersLock = Any()Then wrap the refactored body:
synchronized(qualifiersLock) { // save -> launch -> capture -> afterCapture -> restore }
This is defensive but prevents rare race conditions when multiple captures with different qualifiers run concurrently.
sample-android/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt (1)
35-36
: Update test docstring to reflect current intent (regression, not expected failure).Now that the fix is in place, this test validates the regression and should pass. Consider renaming the method or updating the comment to avoid confusion.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
.github/workflows/CompareScreenshot.yml
(1 hunks).github/workflows/StoreScreenshot.yml
(1 hunks)roborazzi-compose/src/main/java/com/github/takahirom/roborazzi/RoborazziCompose.kt
(3 hunks)sample-android/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
sample-android/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt (4)
include-build/roborazzi-core/src/commonJvmMain/kotlin/com/github/takahirom/roborazzi/RoborazziOptions.kt (1)
File
(225-247)sample-android/src/test/java/com/github/takahirom/roborazzi/sample/boxed/boxedEnvironment.kt (1)
boxedEnvironment
(9-21)include-build/roborazzi-core/src/commonMain/kotlin/com/github/takahirom/roborazzi/RoborazziProperties.kt (1)
roborazziSystemPropertyOutputDirectory
(6-9)roborazzi-compose/src/main/java/com/github/takahirom/roborazzi/RoborazziComposeOptions.kt (1)
size
(166-172)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: ollama-test
🔇 Additional comments (3)
.github/workflows/StoreScreenshot.yml (1)
14-14
: Timeout increase looks good and aligns with the compare workflow.Raising to 30 minutes is reasonable for heavier screenshot tasks. Keep both workflows in sync (as done here) to avoid false waits and flaky pipeline behavior.
.github/workflows/CompareScreenshot.yml (1)
11-11
: Timeout increase acknowledged.Matches the StoreScreenshot workflow. This should reduce CI flakiness on longer Roborazzi runs.
roborazzi-compose/src/main/java/com/github/takahirom/roborazzi/RoborazziCompose.kt (1)
65-83
: Not required — createScenario does not mutate Robolectric qualifiersI searched the codebase: RuntimeEnvironment.setQualifiers is only called from RoborazziComposeOptions.ConfigBuilder.applyToRobolectric() (invoked by configured()), not from createScenario or any activity-scenario creator implementations. Therefore the current save/restore already captures qualifier changes made by configured(), and moving save/restore to wrap launchRoborazziActivity is unnecessary.
Key locations:
- roborazzi-compose/src/main/java/com/github/takahirom/roborazzi/RoborazziComposeOptions.kt — ConfigBuilder.applyToRobolectric() calls setQualifiers(...)
- roborazzi-compose/src/main/java/com/github/takahirom/roborazzi/RoborazziCompose.kt — RuntimeEnvironment.getQualifiers() (saved) and RuntimeEnvironment.setQualifiers(...) (restore) (current placement)
- ActivityScenario creators: RoborazziComposeActivityThemeOption (RoborazziComposeOptions.kt) and RoborazziPreviewScannerSupport.createScenario — neither call setQualifiers
Resulting action: ignore the proposed refactor — the original concern is not supported by the codebase.
Likely an incorrect or invalid review comment.
...oid/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt
Outdated
Show resolved
Hide resolved
...oid/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt
Outdated
Show resolved
Hide resolved
...oid/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt
Outdated
Show resolved
Hide resolved
...oid/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt
Outdated
Show resolved
Hide resolved
...oid/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt
Outdated
Show resolved
Hide resolved
...oid/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt
Outdated
Show resolved
Hide resolved
- Replace Kotlin assert with JUnit Assert for reliability - Add null check for BitmapFactory.decodeFile() - Add try-finally blocks for proper cleanup
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
sample-android/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt (1)
103-111
: Nice: migrated to JUnit assertions and ensured cleanup with try/finally.
- Replacing Kotlin assert with JUnit assertions makes the tests reliable regardless of JVM -ea flags.
- try/finally cleanup guarantees artifact deletion even when assertions fail.
Also applies to: 133-136, 168-171, 231-238, 172-175, 239-242
🧹 Nitpick comments (3)
sample-android/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt (3)
64-67
: Optional: avoid decoding full bitmap; read dimensions only (memory-friendly).To reduce memory overhead and avoid retaining a Bitmap, decode bounds only.
- val bitmap = BitmapFactory.decodeFile(filePath) - ?: throw AssertionError("Failed to decode bitmap: $filePath") - return bitmap.width to bitmap.height + val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } + BitmapFactory.decodeFile(filePath, options) + val width = options.outWidth + val height = options.outHeight + if (width <= 0 || height <= 0) { + throw AssertionError("Failed to decode image dimensions: $filePath") + } + return width to height
70-70
: Nit: rename tests to reflect current intent (regression tests that pass post-fix).Names like “shouldFailBeforeFix” can confuse future readers when the test passes in main. Consider framing as a regression test.
- fun testPreviewSizeRetentionBug_shouldFailBeforeFix() { + fun regression_previewSizeDoesNotLeakBetweenCaptures() {- fun testMultiplePreviewsWithSameCode_simulatesComposablePreviewScanner() { + fun regression_sizeIsolation_simulatesComposablePreviewScanner() {Also applies to: 180-180
224-238
: Stronger invariant: compare “default” sizes to a baseline default capture.Asserting “not equal” verifies the leak is gone, but a more robust check is:
- Capture a baseline “default” (no size) before any sized preview,
- After each sized capture, capture again with default and assert it equals the baseline size.
This guards against coincidental equality/inequality and asserts the intended behavior precisely.
If you’d like, I can draft a variant that records a baseline default size and asserts equality against it for previews 2 and 4.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
sample-android/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
sample-android/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt (4)
include-build/roborazzi-core/src/commonJvmMain/kotlin/com/github/takahirom/roborazzi/RoborazziOptions.kt (1)
File
(225-247)sample-android/src/test/java/com/github/takahirom/roborazzi/sample/boxed/boxedEnvironment.kt (1)
boxedEnvironment
(9-21)include-build/roborazzi-core/src/commonMain/kotlin/com/github/takahirom/roborazzi/RoborazziProperties.kt (1)
roborazziSystemPropertyOutputDirectory
(6-9)roborazzi-compose/src/main/java/com/github/takahirom/roborazzi/RoborazziComposeOptions.kt (1)
size
(166-172)
🔇 Additional comments (1)
sample-android/src/test/java/com/github/takahirom/roborazzi/sample/boxed/PreviewSizeRetentionBugTest.kt (1)
59-67
: Good fix: handle decodeFile null to avoid NPEs.The explicit null check with a clear AssertionError makes failures actionable and prevents NPEs when decoding bitmaps.
Summary
Fixes a bug where Preview annotation size attributes (heightDp/widthDp) incorrectly persist between captures when using ComposablePreviewScanner.
Problem
heightDp=600
, subsequent previews without explicit size specifications also get rendered at 600dp height instead of default sizeRuntimeEnvironment.setQualifiers()
modifies Robolectric's global display configuration which persists between capturesSolution
Save and restore Robolectric qualifiers around each capture operation:
RoborazziComposeOptions
immutable (no mutable fields)Test
Added
PreviewSizeRetentionBugTest
that reproduces the bug and verifies the fix works by checking actual image dimensions.Fixes #719
Summary by CodeRabbit
Bug Fixes
Tests
Chores