cashapp / paparazzi

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

Cannot invoke "com.android.layoutlib.bridge.android.BridgeContext.isAppCompatTheme()" because "this.mContext" is null #630

Closed elihart closed 1 year ago

elihart commented 1 year ago

Description We are seeing on CI that paparazzi occasionally fails with the error:

NullPointerException: Cannot invoke "com.android.layoutlib.bridge.android.BridgeContext.isAppCompatTheme()" because "this.mContext" is null

Steps to Reproduce We are using Paparazzi with compose. The test class is in android unit test sources with junit 4.


class OurTestClass {
    @get:Rule
    val paparazzi = Paparazzi(
        deviceConfig = PIXEL_5.copy(
            softButtons = false,
            locale = "en-rUS"
        ),
        theme = "BaseUiPrimitivesTheme.TabNav",
        renderingMode = SessionParams.RenderingMode.NORMAL,
    )

 @Test
 fun ourTestFunction() {
   paparazzi.snapshot {
     // Compose UI
   }
 }
}

Sorry, I don't have any better repro steps and can't tell why it only sometimes happens.

Expected behavior Test should run consistently without crashing

Additional information:

jrodbx commented 1 year ago

By chance, does your test contain other Junit Rules outside of a RuleChain?

elihart commented 1 year ago

No, our test class only has the single Paparazzi rule

vinaygaba commented 1 year ago

@jrodbx I'm seeing the same error as part of the work I'm doing around Showkase + Paparazzi integration. I'm now integrating that artifact to airbnb's app and seeing errors of this nature in about 33% of the tests. The test itself uses TestParameterInjector for creating a parameterized Paparazzi test

Error


java.lang.NullPointerException: Cannot invoke "com.android.layoutlib.bridge.android.BridgeContext.setBridgeInflater(android.view.BridgeInflater)" because "context" is null 

at com.android.layoutlib.bridge.impl.RenderSessionImpl.init(RenderSessionImpl.java:205) |  
-- | --
  |   | at app.cash.paparazzi.Paparazzi.prepare(Paparazzi.kt:168) |  
  |   | at app.cash.paparazzi.Paparazzi$apply$statement$1.evaluate(Paparazzi.kt:116) |  
  |   | at com.google.testing.junit.testparameterinjector.PluggableTestRunner$ContextMethodRule$1.evaluate(PluggableTestRunner.java:420) |  
  |   | at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) |  
  |   | at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) |  
  |   | at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) |  
  |   | at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) |  
  |   | at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) |  
  |   | at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) |  
  |   | at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) |  
  |   | at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) |  
  |   | at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) |  
  |   | at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) |  
  |   | at org.junit.runners.ParentRunner.run(ParentRunner.java:413)

Sample Test

https://github.com/airbnb/Showkase/blob/d26dca339e4ed361acbb9f1fa2cbea2a007a7d56/showkase-processor-testing/src/test/resources/ShowkaseProcessorTest/class_with_@ScreenshotTest_generates_paparazzi_screenshot_test_for_all_UI_elements/output/MyScreenshotTest_PaparazziShowkaseTest.kt

vinaygaba commented 1 year ago

I spent way too long on this, but was eventually able to figure out the line that's causing this issue. Removing this from the setup gets rid of this error. Sounds like a bug somewhere in Paparazzi

Paparazzi(
    maxPercentDifference = 0.0,
    showSystemUi = false,
-  renderingMode = SessionParams.RenderingMode.SHRINK
)
vinaygaba commented 1 year ago

One more update: I was able to reduce the odds of the error happening with my previous comment, however it still happens often enough that I cannot possibly use it without causing disruption. Any chance I could get some advice?

vinaygaba commented 1 year ago

Just to close the loop on this issue, this happens when a component uses Lottie Compose in its implementation. Thanks to this tip on a separate issue.

To get around this, add this to your test class.

@Before
fun setup() {
    LottieTask.EXECUTOR = Executor(Runnable::run)
}
jrodbx commented 1 year ago

Closing as fixed

matejdro commented 1 year ago

I wouldn't really count this as fixed, as this is only a workaround.

Error message is still super confusing and unhelpful.

vassilisimon commented 1 year ago

Yes, it's not fixed.

jrodbx commented 1 year ago

@matejdro can you file a new issue with a repro project?

It's not a workaround since the issue is ultimately not a Paparazzi issue but rather a Lottie issue, due to how it exposes its threading implementation.

matejdro commented 1 year ago

It only happens on our CI system, I cannot reproduce it on my machine to make a reliable repro project.

Maybe "Lottie" section could be added to README to explain this? I am prepared to offer a Pull Request for that.

jamesrapadmi commented 1 year ago

I'm seeing this issue on all my paparazzi tests, even without SessionParams.RenderingMode.SHRINK and with the following setup block.

@Before
fun setup() {
    LottieTask.EXECUTOR = Executor(Runnable::run)
}

Is there anything else I can do to avoid this?

java.lang.NullPointerException: Cannot invoke "com.android.layoutlib.bridge.android.BridgeContext.setBridgeInflater(android.view.BridgeInflater)" because "context" is null
    at com.android.layoutlib.bridge.impl.RenderSessionImpl.init(RenderSessionImpl.java:198)
    at app.cash.paparazzi.Paparazzi.prepare(Paparazzi.kt:175)
    at app.cash.paparazzi.Paparazzi$apply$statement$1.evaluate(Paparazzi.kt:124)
...

For reference, I'm on:

mrea1 commented 4 months ago

I'm seeing this on a project, but not using Lottie