cashapp / paparazzi

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

`Paparazzi.gif()` throws an un-catchable exception #1325

Closed BraisGabin closed 1 month ago

BraisGabin commented 5 months ago

Description The Paparazzi.gif function fails with an exception when verifying. That's expected. The problem is that when I try to catch that exception to avoid failing I can't do it.

@Test
fun launchComposable() {
    val view = ComposeView(paparazzi.context).apply { setContent { Hello() } }
    try {
        paparazzi.gif(view)
    } catch (e: Throwable) {
        println("exception captured composable!")
    }
}

A test like this always fails at the line paparazzi.git(view) but the println("exception captured composable!") is executed because I can't see that output.

The exception looks like this:

java.lang.AssertionError: File /Users/brais.gabin/Workspace/Paparazzicatchexception/app/src/test/snapshots/images/com.example.paparazzicatchexception_ExampleUnitTest_launchComposable.png does not exist
    at app.cash.paparazzi.SnapshotVerifier$newFrameHandler$1.handle(SnapshotVerifier.kt:46)
    at app.cash.paparazzi.Paparazzi$takeSnapshots$1$3.invoke(Paparazzi.kt:343)
    at app.cash.paparazzi.Paparazzi$takeSnapshots$1$3.invoke(Paparazzi.kt:330)
    at app.cash.paparazzi.Paparazzi.withTime(Paparazzi.kt:378)
    at app.cash.paparazzi.Paparazzi.takeSnapshots(Paparazzi.kt:330)
    at app.cash.paparazzi.Paparazzi.gif(Paparazzi.kt:233)
    at app.cash.paparazzi.Paparazzi.gif$default(Paparazzi.kt:220)
    at com.example.paparazzicatchexception.ExampleUnitTest.launchComposable(ExampleUnitTest.kt:29)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    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 app.cash.paparazzi.Paparazzi$apply$1.evaluate(Paparazzi.kt:147)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    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)

I know that it is expected that paparazzi.gif(view) will throw an exception. But I should be able to catch that exception and prevent the test failure.

This error was present on 1.3.2 but now on 1.3.3 it's easier to reproduce/more consistent.

I imagine that this issue is related with #1309 and this comment: https://github.com/cashapp/paparazzi/pull/1309/files#r1507960495

Steps to Reproduce

  1. Checkout project: https://github.com/BraisGabin/paparazzi-catch-exception
  2. Execute: ./gradlew vPD you will see that one of the two tests in ExempleUnitTest.kt will fail. Which one is not defined, it depends on which one is executed first. You can play changing the name of the tests to see that.
    • You can also see on the junit html report that on the Standard output the output of both catch is there.
  3. Update paparazzi to 1.3.3 at build.gradle.kts
  4. Execute: ./gradlew vPD again and you will see now than both tests fail.

Expected behavior If gif throws an exception and I have a try/catch around it I can capture it and prevent the test to fail.

Context On 1.3.2 I had a workaround like that to mix snapshot and gif in the same project. Even if the gifs didn't verify it is better to have the golden snaphots and at least you will notice changes if that golden snapshots change. It is not ideal but it is better than nothing.

Additional information:

radodado commented 2 months ago

you can also prevent the test from failing by making it pass with my little work around:

BraisGabin commented 1 month ago

@radodado thanks for the workaround. I'm closing this PR as now with 1.3.4 we have support to verify gifs so this is not longer important.