cashapp / paparazzi

Render your Android screens without a physical device or emulator
https://cashapp.github.io/paparazzi/
Apache License 2.0
2.25k stars 213 forks source link

"Width (0) and height (0) cannot be <= 0" error or font resource loading error or empty screenshot issue #1288

Open alashow opened 6 months ago

alashow commented 6 months ago

Description Note: re-opening https://github.com/cashapp/paparazzi/issues/1054 because it was closed and now it's failing with upgrading composeBom to latest stable vs alpha version of constraintLayout.

When upgrading from composeBom 2023.10.01 to 2024.02.00, screenshot tests start failing with empty screens or these errors:

Variant 1:
ava.lang.IllegalArgumentException: Width (0) and height (0) cannot be <= 0
    at java.desktop/java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1016)
    at java.desktop/java.awt.image.BufferedImage.<init>(BufferedImage.java:333)
    at com.android.layoutlib.bridge.impl.RenderSessionImpl.renderAndBuildResult(RenderSessionImpl.java:543)
    at com.android.layoutlib.bridge.impl.RenderSessionImpl.render(RenderSessionImpl.java:468)
    at app.cash.paparazzi.Paparazzi$takeSnapshots$1$3.invoke(Paparazzi.kt:329)
    at app.cash.paparazzi.Paparazzi$takeSnapshots$1$3.invoke(Paparazzi.kt:328)
    at app.cash.paparazzi.Paparazzi.withTime(Paparazzi.kt:376)
    at app.cash.paparazzi.Paparazzi.takeSnapshots(Paparazzi.kt:328)
    at app.cash.paparazzi.Paparazzi.snapshot(Paparazzi.kt:214)
    at app.cash.paparazzi.Paparazzi.snapshot$default(Paparazzi.kt:213)
    at app.cash.paparazzi.Paparazzi.snapshot(Paparazzi.kt:209)

Variant 2
java.lang.IllegalStateException: Could not load font
    at androidx.compose.ui.text.font.TypefaceRequestCache.runCached(FontFamilyResolver.kt:207)
    at androidx.compose.ui.text.font.FontFamilyResolverImpl.resolve(FontFamilyResolver.kt:92)
    at androidx.compose.ui.text.font.FontFamilyResolverImpl.resolve-DPcqOEQ(FontFamilyResolver.kt:79)
    at androidx.compose.foundation.text.HeightInLinesModifierKt$heightInLines$2.invoke(HeightInLinesModifier.kt:73)
    at androidx.compose.foundation.text.HeightInLinesModifierKt$heightInLines$2.invoke(HeightInLinesModifier.kt:52)
    at androidx.compose.ui.ComposedModifierKt$materialize$result$1.invoke(ComposedModifier.kt:270)
    at androidx.compose.ui.ComposedModifierKt$materialize$result$1.invoke(ComposedModifier.kt:265)
    at androidx.compose.ui.Modifier$Element.foldIn(Modifier.kt:136)
.....
android.content.res.Resources$NotFoundException: Font resource ID #0x7f09000f could not be retrieved.

Steps to Reproduce Not able to cleanly reproduce this yet. Before it was happening with constraintLayout alpha versions, now not sure what library is causing this exactly.

Project sample fails with different error when adding all composeBom library dependencies (PlatformTextInputPluginRegistryImpl classnotfound error)

Additional information:

Screenshots See screenshots in https://github.com/cashapp/paparazzi/issues/1054

JeremiahStephenson commented 6 months ago

I started getting this after specifically updating Material3 to 1.2.0. Any previews that display text with custom font will fail and the snapshot comes out blank.

jrodbx commented 6 months ago

@alashow thanks for reopening. without a repro, this remains a challenge to solve. Also, how certain are you that the two variants are related, i.e., the same bug?

@JeremiahStephenson re: "any previews that display text will fail" so this might be an layoutlib issue?

One thing I just noticed is that compileSdk = 34 is specified, but Paparazzi currently only supports up to API 33, due to its dependency on layoutlib being pinned (at the moment) to Giraffe (link)

Have you updated the environment accordingly, i.e.,

Paparazzi(
  environment = detectEnvironment().run {
    copy(compileSdkVersion = 33, platformDir = platformDir.replace("34", "33"))
  },
)

?

JeremiahStephenson commented 6 months ago

@jrodbx No, that doesn't fix my issue. The issue for me only came up after updating material3 to the latest stable version 1.2.0.

alashow commented 6 months ago

Also, how certain are you that the two variants are related, i.e., the same bug?

Both errors show up after updating composeBom to latest, so that's the only reason I think they're related.

Have you updated the environment accordingly, i.e.,

Yes, I did apply the fix from https://github.com/cashapp/paparazzi/issues/1025, compileSdk = 34 doesn't work otherwise.

alashow commented 6 months ago

Indeed, only tests using Text component fail. So I tested more with it and it seems like it's related to fontFamily..

After debugging I found out that it only fails when using custom fontFamily. I changed our default fontFamily from custom one to FontFamily.Default, and re-recorded tests - all tests got recorded / didn't fail with above errors.

Then I tried specifying loadingStrategy when initializing our custom fontFamily, i.e:

FontFamily(
    fonts = listOf(
        Font(
            resId = R.font.customFont,
            weight = FontWeight.Thin,
            style = FontStyle.Normal,
            loadingStrategy= FontLoadingStrategy.Async,
        )
        ...,
)

and again screenshot test didn't fail when running. Changing loadingStrategy from default FontLoadingStrategy.Blocking to FontLoadingStrategy.Async or even FontLoadingStrategy.OptionalLocal makes the tests work again. The actual font specified isn't rendered of course, I assume because they're rendered a bit after / they're still being loaded in background / async(?)

So if this is a layoutlib issue, does it mean the same components using Text with custom font shouldn't be rendered in preview mode when the same layoutlib version of paparazzi is used by Android Studio?

renovater8 commented 6 months ago

Description Note: re-opening #1054 because it was closed and now it's failing with upgrading composeBom to latest stable vs alpha version of constraintLayout.

When upgrading from composeBom 2023.10.01 to 2024.02.00, screenshot tests start failing with empty screens or these errors:

Variant 1:
ava.lang.IllegalArgumentException: Width (0) and height (0) cannot be <= 0
  at java.desktop/java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1016)
  at java.desktop/java.awt.image.BufferedImage.<init>(BufferedImage.java:333)
  at com.android.layoutlib.bridge.impl.RenderSessionImpl.renderAndBuildResult(RenderSessionImpl.java:543)
  at com.android.layoutlib.bridge.impl.RenderSessionImpl.render(RenderSessionImpl.java:468)
  at app.cash.paparazzi.Paparazzi$takeSnapshots$1$3.invoke(Paparazzi.kt:329)
  at app.cash.paparazzi.Paparazzi$takeSnapshots$1$3.invoke(Paparazzi.kt:328)
  at app.cash.paparazzi.Paparazzi.withTime(Paparazzi.kt:376)
  at app.cash.paparazzi.Paparazzi.takeSnapshots(Paparazzi.kt:328)
  at app.cash.paparazzi.Paparazzi.snapshot(Paparazzi.kt:214)
  at app.cash.paparazzi.Paparazzi.snapshot$default(Paparazzi.kt:213)
  at app.cash.paparazzi.Paparazzi.snapshot(Paparazzi.kt:209)

Variant 2
java.lang.IllegalStateException: Could not load font
  at androidx.compose.ui.text.font.TypefaceRequestCache.runCached(FontFamilyResolver.kt:207)
  at androidx.compose.ui.text.font.FontFamilyResolverImpl.resolve(FontFamilyResolver.kt:92)
  at androidx.compose.ui.text.font.FontFamilyResolverImpl.resolve-DPcqOEQ(FontFamilyResolver.kt:79)
  at androidx.compose.foundation.text.HeightInLinesModifierKt$heightInLines$2.invoke(HeightInLinesModifier.kt:73)
  at androidx.compose.foundation.text.HeightInLinesModifierKt$heightInLines$2.invoke(HeightInLinesModifier.kt:52)
  at androidx.compose.ui.ComposedModifierKt$materialize$result$1.invoke(ComposedModifier.kt:270)
  at androidx.compose.ui.ComposedModifierKt$materialize$result$1.invoke(ComposedModifier.kt:265)
  at androidx.compose.ui.Modifier$Element.foldIn(Modifier.kt:136)
.....
android.content.res.Resources$NotFoundException: Font resource ID #0x7f09000f could not be retrieved.

Steps to Reproduce Not able to cleanly reproduce this yet. Before it was happening with constraintLayout alpha versions, now not sure what library is causing this exactly.

Project sample fails with different error when adding all composeBom library dependencies (PlatformTextInputPluginRegistryImpl classnotfound error)

Additional information:

  • Paparazzi Version: 1.3.1, 1.3.2, 1.3.3-SNAPSHOT
  • OS: osx sonoma
  • Compile SDK: 34
  • Gradle Version: 8.2.1
  • Android Gradle Plugin Version: 8.2.2

Screenshots See screenshots in #1054

I think it also was reading sent under note and day and date was only saying today or yesterday also but I did notice if you reset your camera in settings for just the camera it works like new only once in settings u have to adjust it then like right away.

renovater8 commented 6 months ago

I think just a simple reset would change it all unless u have a cheap phone

alashow commented 6 months ago

@renovater8 what are you going on about?

rafsanjani commented 6 months ago

@alashow loadingStrategy is not available on Compose Multiplatform.

alashow commented 4 months ago

@jrodbx any updates on this?

artemyto commented 3 months ago

We had this issue on our project when we ran Paparazzi tests with JUnit 5 enabled. When we rewrote our tests to use JUnit 4 and completely disabled JUnit 5, the issue has gone.

I don't know why JUnit version matters, but this our case.

alashow commented 3 months ago

We had this issue on our project when we ran Paparazzi tests with JUnit 5 enabled. When we rewrote our tests to use JUnit 4 and completely disabled JUnit 5, the issue has gone.

I don't know why JUnit version matters, but this our case.

We're using JUnit 4 (4.13.2 specifically)

xatok commented 2 months ago

It fails for me when using a custom font in Compose Multiplatform.

I've got a workaround which is far from perfect but at least it lets me run the screenshot tests:

It consists in mocking the FontFamily and returning a list of Font using the Android font implementation (so androidx.compose.ui.text.font.Font instead of org.jetbrains.compose.resources.Font).

That of course means the fonts needs to get copied over to the Android test font resource folder. I'm using Mockposable along with Mockk for mocking the composable function.

Something like this:

mockkStatic("my.package.FontFamilyKt")
everyComposable { fontFamily() } answersComposable { androidFontFamily() }