Open hellohj opened 2 weeks ago
Thanks. I'm also not sure why it happens.
However, 0dp
in ConstraintLayout is used as match_constraint. I have some options to try. I think you can try specifying qualifiers like RobolectricDeviceQualifiers.Pixel5
. Additionally, I think you can try adding a wrapper with a fixed width or calling the layout method of the View.
Thanks for taking a look. RoborazziBaseTest
from the above code already has these. I'll try other suggestions.
@RunWith(AndroidJUnit4::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(qualifiers = RobolectricDeviceQualifiers.Pixel5)
abstract class RoborazziBaseTest {...}
Setting title.layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT
in a test shows text so I don't need to touch our complex UI components from the design system, but constraints with surrounding UI elements are slightly off due to wrap_content
. I'm at least unblocked and see if Roborazzi can do something here. Thank you.
I thought that if you adjust the size of the outer View without altering the content, the inner part might change accordingly. Do you know how the layout on the receiving side of the following binding is set up? I suspect it might be set to wrap content.
scenario.onActivity { activity ->
binding =
I'm using a blank activity for the snapshot testing only.
Also, tried ComponentActivity
for ActivityScenario. Still the same issue.
class TestRoborazziActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.snapshot_roborazzi_activity)
}
}
--------
// snapshot_roborazzi_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" />
-------
@RunWith(AndroidJUnit4::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(qualifiers = RobolectricDeviceQualifiers.Pixel5)
abstract class RoborazziBaseTest {
@get:Rule
val roborazziRule =
RoborazziRule(options = RoborazziRule.Options(outputDirectoryPath = OUTPUT_DIRECTORY_PATH))
// For legacy view-based screens.
val scenario = ActivityScenario.launch(TestRoborazziActivity::class.java)
/** Capture snapshot for View-based legacy screen. */
protected fun View.snapshot() {
captureRoboImage()
}
@After
fun tearDown() {
scenario.close()
}
}
Thank you! I understand the situation. That's certainly weird.
I would like to know what happens if we set layout_width="400dp" here. Could you check it out?
// snapshot_roborazzi_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Interesting question. It makes a blank snapshot with a width of 418px. This is wild.
@hellohj
I forgot about this, but could you try using @Config(sdk = [33])
?
https://github.com/takahirom/roborazzi?tab=readme-ov-file#q-the-images-taken-from-roborazzi-seem-broken
And I think you can also try using test.systemProperties["robolectric.pixelCopyRenderMode"] = "hardware"
.
https://github.com/DroidKaigi/conference-app-2024/blob/4c70202b90fc9597e3dc539546caecf1f29f9b96/build-logic/src/main/kotlin/io/github/droidkaigi/confsched/primitive/AndroidRoborazziPlugin.kt#L27
Thanks for suggestions. sdk 33 is already specified from my code example so it didn't help. For the hardware render mode option, it's already defined in my gradle file and it also didn't help. 😢
I'm busy with DroidKaigi and won't be able to work on this for two weeks. If you could provide a sample for reproduction, that would be great.
@takahirom No worries. Sorry, it took long time to provide you a sample. Here is my sample project. With this setup, my test even fails with this error. The layout is shown properly in the design view and the app runs properly. 🤔
width and height must be > 0
java.lang.IllegalArgumentException: width and height must be > 0
at android.graphics.Bitmap.createBitmap(Bitmap.java:1111)
at android.graphics.Bitmap.createBitmap(Bitmap.java:1078)
at android.graphics.Bitmap.createBitmap(Bitmap.java:1028)
at android.graphics.Bitmap.createBitmap(Bitmap.java:989)
at androidx.core.view.ViewKt.drawToBitmap(View.kt:232)
at androidx.core.view.ViewKt.drawToBitmap$default(View.kt:228)
at com.github.takahirom.roborazzi.RoborazziKt.captureRoboImage(Roborazzi.kt:107)
at com.github.takahirom.roborazzi.RoborazziKt.captureRoboImage(Roborazzi.kt:66)
at com.github.takahirom.roborazzi.RoborazziKt.captureRoboImage$default(Roborazzi.kt:61)
at com.example.myapplication.RoborazziMainTest.testBasic$lambda$1(RoborazziMainTest.kt:37)
at androidx.test.core.app.ActivityScenario.lambda$onActivity$2(ActivityScenario.java:794)
at androidx.test.core.app.ActivityScenario.onActivity(ActivityScenario.java:804)
at com.example.myapplication.RoborazziMainTest.testBasic(RoborazziMainTest.kt:32)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at com.github.takahirom.roborazzi.RoborazziRule$runTest$evaluate$1.invoke(RoborazziRule.kt:150)
at com.github.takahirom.roborazzi.RoborazziRule$runTest$evaluate$1.invoke(RoborazziRule.kt:148)
at com.github.takahirom.roborazzi.RoborazziRule.runTest(RoborazziRule.kt:174)
at com.github.takahirom.roborazzi.RoborazziRule.access$runTest(RoborazziRule.kt:27)
at com.github.takahirom.roborazzi.RoborazziRule$apply$1.evaluate(RoborazziRule.kt:132)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
Thank you for creating the reproducing repository. I was able to check it. The reason you are encountering an error is that your view is not attached to the activity you launched.
If we attach the view to MainActivity, it works. However, the view is added to MainActivity, resulting in a duplicated view.
@Test
fun testBasic() {
val scenario = ActivityScenario.launch(MainActivity::class.java)
scenario.onActivity { activity ->
- binding = ActivityMainBinding.inflate(LayoutInflater.from(activity))
- with (binding) {
+ binding = ActivityMainBinding.inflate(
+ LayoutInflater.from(activity),
+ activity.findViewById(android.R.id.content),
+ true
+ )
+ with(binding) {
title.text = "This is a title text"
subtitle.text = "This is a subtitle"
root.captureRoboImage()
In this sample, it seems that the issue with ConstraintLayout is not being reproduced. To better replicate the situation as it occurs in your repository, you might consider adjusting the setup or configurations to match the conditions under which the problem arises. This could involve using the same version of the library, similar layout complexities, or specific configurations that are present in your environment.
I reviewed your code, and it seems that the issue might be that your View is not included in the Activity.
We're migrating Paparazzi snapshot testing to Roborazzi for legacy View-based UI.
During the migration, I encountered an issue where Roborazzi fails to capture anything when the TextView's width is set to 0dp and we set text from a test. Paparazzi doesn't seem to have any issues with the layout, but Roborazzi doesn't show anything (screenshot attached at the bottom). Changing
layout_width=0dp
tolayout_width=wrap_content
resolves the issue, but I don't think that's a desirable solution.Can anyone provide insights into the cause of this issue? Any thoughts or suggestions would be greatly appreciated.
Example of simplified snapshot_test.xml
Example of test