Android Snapshots

Emerge offers a full-suite snapshotting solution on Android, allowing for snapshotting of Composables, Activities and Views. Emerge handles the complicated aspects, like emulator coordination, file storage, image comparisons & diffs, allowing you to focus on writing tests.

Concepts

Automatic Compose snapshot tests

Emerge automatically generates snapshot tests for any Compose view annotated with @Preview. There is no extra test code to maintain.

Management & diffing

When snapshot builds are uploaded to Emerge using the Emerge Gradle Plugin, Emerge automatically handles storing the resulting snapshot images and diffing between them.

For details on how Emerge manages and diffs snapshots, see Snapshot management & diffing.

Explicit or automatic composable snapshot tests

Emerge generates Composable snapshot tests from @Preview annotated functions from any source set of your choosing using a custom KSP processor and gradle plugin. This allows full flexibility of keeping snapshot tests explicitly separate as test code, or automatically generated for all main source set previews.

Support for legacy (XML/Custom) views & Activities

Emerge snapshots provides full support for manual snapshot testing of legacy XML/custom views as well as full activities.

Quickstart (~10 min)

Emerge snapshotting requires the usage of Emerge's Gradle plugin and the com.emergetools.snapshots:snapshots library.

Additionally, Emerge offers a custom KSP processor, com.emergetools.snapshots:snapshots-processor for automatic generation of Composable @Preview snapshots.

Setup Emerge Gradle Plugin

See Gradle Plugin (Android) for full setup instructions, but for a quick setup, add the Emerge plugin to your app's build.gradle.kts file:

plugins {
  id("com.emergetools.android")
}

emerge {
  // Emerge uses the EMERGE_API_TOKEN env variable by default, so no need to set env explicitly
  apiToken.set(System.getenv("EMERGE_API_TOKEN"))
}

The above setup assumes you've created an API token and set as the EMERGE_API_TOKEN env variable. Full instructions can be found at obtain an API key.

Add Snapshot SDKs

Emerge snapshot SDKs are published to Maven Central and should be added as dependencies to your app's build.gradle.kts file.

Compose @Preview snapshot generation relies on a KSP Processor to automatically generate snapshot tests for Compose Previews, which requires the KSP plugin to be added to your project. For more details, see Add the KSP plugin to your project from the Android developer documentation.

plugins {
  // ...
  
  // For Compose @Preview snapshot generation:
  id("com.google.devtools.ksp")
}

// ...

dependencies {
  androidTestImplementation("com.emergetools.snapshots:snapshots:<latest_version>")
  
  // For Compose @Preview snapshot generation from the main source set:
  ksp("com.emergetools.snapshots:snapshots-processor:<latest_version>")
}

See the emerge-android repo for the latest snapshots SDK versions.

Create your first snapshot test

Composables

Emerge's KSP snapshot-processor automatically generates snapshot tests for compose previews in the
source set the KSP processor is applied to. No additional setup work needs to be done!

// /src/main/com/myapp/MyComposable.kt

@Preview  
@Composable  
fun MyComposablePreview() {  
  MyComposable(  
    text = "Hello, World!"  
  )  
}

That's it! Using KSP, Emerge's snapshot-processor will automatically generate snapshot tests for all @Preview annotated functions in the main source set.

⚠️ Currently only no-arg @Preview annotated composables with a default configuration are supported.

Variant support

Emerge currently supports variants through a subset of @Preview annotation parameters:

  • fontScale
  • locale
  • uiMode (dark/light mode)

Emerge will automatically generate a snapshot test for each Preview annotation present. For example,
for the following composable:

// src/main/com/myapp/MyComposable.kt

@Preview
@Preview(fontScale = 1.5f)
@Composable
fun MyComposablePreview() {
  MyComposable(
    text = "Hello, World!"
  )
}

Emerge will generate two snapshots, one default, and one with 1.5f font scale.

Generating Preview snapshots from the androidTest source set

Emerge can automatically generate snapshot tests for all composable previews in the main source
set, but sometimes creating explicit previews for snapshot testing is more desired.

Simply apply the Emerge KSP processor as a kspAndroidTest dependency instead of ksp to generate
snapshot tests from the androidTest source set.

plugins {
  id("com.emergetools.android")
  id("com.google.devtools.ksp")
}

emerge {
  // ..
}

dependencies {
  androidTestImplementation("com.emergetools.snapshots:snapshots:<latest_version>")
  // For Compose @Preview snapshot generation from androidTest source set:
  kspAndroidTest("com.emergetools.snapshots:snapshots-processor:<latest_version>")
}

And as an example, assuming the following preview lives in the androidTest source set:

// /src/androidTest/com/myapp/MyComposablePreviewTest.kt

@Preview
@Composable
fun MyComposablePreviewTest() {
  MyComposable(
    text = "Hello, World!"
  )
}

Emerge will automatically generate a preview snapshot test for MyComposablePreviewTest().

Activities and views

Create a basic test class that uses the EmergeSnapshot rule to generate snapshots.

@RunWith(AndroidJUnit4::class)  
class EmergeSnapshotTests {

  @get:Rule  
  val activityScenarioRule = ActivityScenarioRule(MainActivity::class.java)

  @get:Rule  
  val snapshots = EmergeSnapshot()

  @Test  
  fun mainActivitySnapshot() {  
    val scenario = activityScenarioRule.scenario  
    scenario.onActivity {  
      snapshots.take(name = "MainActivity", activity = it)  
    }  
  }

  @Test  
  fun customViewSnapshot() {  
    val view = CustomView(InstrumentationRegistry.getInstrumentation().targetContext)  
    snapshots.take(name = "CustomView", view = view)  
  }
}

Each name parameter must be unique as it's used as the primary key for saving & diffing.

Upload snapshots to Emerge

The Emerge gradle plugin offers a single command to build & upload screenshot tests packages to Emerge. Emerge will handle generating, storing, and diffing the snapshots against a base build for you.

./gradlew :app:emergeUploadSnapshotBundleDebug

Once uploaded, snapshots and diffs are viewable directly in the Emerge UI.

Generate snapshots locally

Emerge also offers a command to generate snapshots locally for debugging or saving locally.

./gradlew :app:emergeLocalSnapshotsDebug

Additionally, you can specify where to save the snapshots to using the snapshots extension of the Emerge Gradle plugin. By default, snapshots are saved to the /build/emerge/snapshots/outputs directory.

emerge {
  ..
  
  snapshots {
    snapshotsStorageDirectory.set("/app/src/main/snapshots") // Storage of locally generated snapshots
  }
}

Additional resources

For details on how Emerge manages and diffs snapshots, see Snapshot management & diffing.

Full source code and SDK documentation is available in the emerge-android repository.