cashapp/paparazzi

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

elihart opened this issue · 12 comments

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:

  • Paparazzi Version: 1.1.0
  • OS: Linux
  • Compile SDK: 33
  • Gradle Version: 7.5.1
  • Android Gradle Plugin Version: 7.3

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

No, our test class only has the single Paparazzi rule

@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

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
)

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?

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

Closing as fixed

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

Error message is still super confusing and unhelpful.

Yes, it's not fixed.

jrodbx commented

@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.

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.

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:

  • Paparazzi Version: 1.3.1
  • OS: macOS
  • Compile SDK: 34
  • Gradle Version: 8.3
  • Android Gradle Plugin Version: 8.1.1