[Deprecated] Android Snapshots (pre-1.0.0)
Deprecated
Emerge has published the 1.0.0 release of snapshots, bringing multiple improvements over the pre-1.0 snapshots. We'd recommend getting started with 1.0 - see the snapshots 1.0.0 documentation for details on how to get started!
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 function 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 provide 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 this explicitly, this is just for example purposes
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 of the module the processor is running on.
Current limitations
- No-arg
@Preview
annotated composable functions are supported.@Preview
annotated functions must be public to be snapshotted. Experimentalinternal
support is available through thesnapshots.experimentalInternalSnapshotsEnabled
Gradle plugin property.- Preview parameters are currently not supported, but long term plans to support are planned. For mocking data, instantiate data directly in the composable preview function.
Variant support
Emerge currently supports a subset of @Preview
annotation parameters for variant generation:
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.
Multipreview support
Emerge has full support for Multipreview annotations and stacked multipreviews.
As an example, the following annotation can be used to generate multiple previews when the custom annotation is used in place of multiple @Preview
annotations.
// src/main/com/myapp/SnapshotTestingPreview.kt
@Preview
@Preview(fontScale = 1.5f)
@Preview(uiMode = UI_MODE_NIGHT_YES)
annotation class SnapshotTestingPreview
Using SnapshotTestingPreview
, the following preview will produce 3 variants, a default (@Preview
annotation), a large font (@Preview(fontScale = 1.5f)
) and a dark mode (@Preview(uiMode = UI_MODE_NIGHT_YES)
).
// src/main/com/myapp/MyComposable.kt
@SnapshotTestingPreview
@Composable
fun MyComposablePreview() {
MyComposable(
text = "Hello, World!"
)
}
Android API levels
Emerge supports specifying the system API level for snapshotting all previews through the snapshots.apiVersion
Gradle plugin property
emerge {
// ...
snapshots {
apiVersion.set(31) // must be 29, 31, 33 or 34
}
}
By default, Emerge snapshots using API level 34 (Android 14). A full list of API levels can be found here. Currently, Emerge only supports API levels 29, 31, 33 and 34. Should you have a use case for other API levels, let us know and we can likely accomodate!
Long term, Emerge plans to support the @Preview
annotation's apiLevel
parameter for more granular API level support.
Generating Preview snapshots from the androidTest
source set
androidTest
source setEmerge 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.
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>")
}
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.
Diffing snapshots
Emerge will automatically diff snapshots based onsha
/baseSha
parameters. These parameters can be specified through the vcs
block of the Emerge Gradle plugin extension, and by default Emerge will attempt to set these automatically through local git information.
emerge {
// ...
vcs {
sha.set("...")
baseSha.set("...")
}
}
When Emerge finds a matching base build whose sha
is equal to the head build's baseSha
, Emerge will automatically diff snapshots with the base build. Diffing is done using a hash of the Preview function's fully qualified name combined with the @Preview
annotation parameters specified.
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.
Updated 6 months ago