EmergeTools / emerge-android

Android tooling & gradle plugin for Emerge's size analysis, end-to-end snapshotting, Reaper dead code detection and performance testing
https://docs.emergetools.com/docs/quickstart
Apache License 2.0
24 stars 2 forks source link

[Snapshots] Cannot snapshot two previews in different files with same package #174

Open rbro112 opened 4 months ago

rbro112 commented 4 months ago

We've had a client present an edge case that causes snapshots to fail when two different preview functions live in separate files with the same package/name:

// Snapshot1.kt
package com.example

@Preview
@Composable
fun MyPreview() {...}
// Snapshot2.kt
package com.example

@Preview
@Composable
fun MyPreview() {...}

We use the FQN of the composable function as the primary key (with preview details), meaning in both cases the key is com.example.MyPreview. Depending on which is invoked first, the second will result in a crash as a snapshot with that key has already been saved.

rbro112 commented 2 months ago

The best workaround for this currently is one of three options:

  1. Ensure the fully qualified name (package.method name) is unique for each preview function. This would mean moving one function to a different package.
  2. Renaming one function, resulting in unique FQNs for both methods.
  3. Modifying the @Preview annotation to have different parameters, as Emerge keys off a combination of FQN and preview parameters.

We're looking into use the file as an additional key in the future to solve this, but there's currently no ETA on that change.

rbro112 commented 2 months ago

We've also seen cases where this bug can prevent other snapshot tests from running due to early exits from snapshot runs. We'd encourage the above workaround for any errors where a stacktrace like the following is present:

java.lang.IllegalStateException: File with name {snapshot}.png already exists.
    at com.emergetools.snapshots.SnapshotSaver.saveFile(SnapshotSaver.kt:194)
    at com.emergetools.snapshots.SnapshotSaver.saveImage(SnapshotSaver.kt:113)
    at com.emergetools.snapshots.SnapshotSaver.save(SnapshotSaver.kt:58)
    at com.emergetools.snapshots.EmergeSnapshots.take(EmergeSnapshots.kt:48)
    at com.emergetools.snapshots.compose.ComposeSnapshotterKt.snapshotComposable$lambda$3(ComposeSnapshotter.kt:77)
    at com.emergetools.snapshots.compose.ComposeSnapshotterKt.$r8$lambda$Zxh5rzaAh_iTEohgph_dgwGCc4w(Unknown Source:0)
    at com.emergetools.snapshots.compose.ComposeSnapshotterKt$$ExternalSyntheticLambda0.run(Unknown Source:6)
    at android.os.Handler.handleCallback(Handler.java:958)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8177)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
rbro112 commented 1 month ago

We've added a better error state in Emerge's snapshotting UI to handle this case as an immediate fix. We'll plan to take the file name into account in the snapshot's key in an upcoming update.

Screenshot 2024-09-25 at 4 14 07 PM