|
| 1 | +# Testify — Android Screenshot Testing — Paparazzi Extensions |
| 2 | + |
| 3 | +<a href="https://search.maven.org/artifact/dev.testify/testify-paparazzi"><img alt="Maven Central" src="https://img.shields.io/maven-central/v/dev.testify/testify-paparazzi?color=%236e40ed&label=dev.testify%3Atestify-paparazzi"/></a> |
| 4 | + |
| 5 | +**Utility library for [Paparazzi](https://github.com/cashapp/paparazzi) snapshot testing, providing factory functions, theme helpers, and multi-variant testing support for Compose UIs.** |
| 6 | + |
| 7 | +Paparazzi snapshot tests often repeat identical boilerplate: rule construction, theme wrapping, and manual light/dark duplication. The Testify Paparazzi extension eliminates this repetition by providing: |
| 8 | + |
| 9 | +- **Device presets** — Curated set of common device configurations (phone, tablet, foldable). |
| 10 | +- **Theme helpers** — A `ThemeProvider` interface and extension functions for automatic light/dark snapshot coverage. |
| 11 | +- **Factory functions** — `TestifyPaparazzi.component()` and `TestifyPaparazzi.screen()` replace repetitive `Paparazzi(...)` constructors. |
| 12 | +- **Font scale testing** — Presets and helpers for verifying accessibility font sizes. |
| 13 | +- **Locale/RTL testing** — Presets for internationalization and pseudolocalization testing. |
| 14 | +- **Accessibility snapshots** — Pre-configured `AccessibilityRenderExtension` factory. |
| 15 | +- **State matrix testing** — Snapshot multiple component states from a single test method. |
| 16 | +- **ComposableSnapshotRule** — A high-level JUnit rule combining all features into one declaration. |
| 17 | + |
| 18 | +# Set up testify-paparazzi |
| 19 | + |
| 20 | +**settings.gradle** |
| 21 | + |
| 22 | +Ensure that `mavenCentral()` is available in `dependencyResolutionManagement`. |
| 23 | + |
| 24 | +**Application build.gradle** |
| 25 | +```groovy |
| 26 | +dependencies { |
| 27 | + testImplementation "dev.testify:testify-paparazzi:5.0.1" |
| 28 | + testImplementation "app.cash.paparazzi:paparazzi:2.0.0-alpha04" |
| 29 | +} |
| 30 | +``` |
| 31 | + |
| 32 | +# Write a test |
| 33 | + |
| 34 | +### Basic snapshot with theme |
| 35 | + |
| 36 | +Define a `ThemeProvider` for your app's theme: |
| 37 | + |
| 38 | +```kotlin |
| 39 | +val myThemeProvider = ThemeProvider { darkTheme, content -> |
| 40 | + MyAppTheme(darkTheme = darkTheme) { content() } |
| 41 | +} |
| 42 | +``` |
| 43 | + |
| 44 | +### Using ComposableSnapshotRule |
| 45 | + |
| 46 | +The highest-level API. A single rule declaration provides themed snapshots with no boilerplate: |
| 47 | + |
| 48 | +```kotlin |
| 49 | +class MyComponentTest { |
| 50 | + |
| 51 | + @get:Rule val snapshot = ComposableSnapshotRule(themeProvider = myThemeProvider) |
| 52 | + |
| 53 | + @Test fun default() = snapshot.snapshot { MyComponent() } |
| 54 | + |
| 55 | + @Test fun darkTheme() = snapshot.snapshot(variant = ThemeVariant.DARK) { MyComponent() } |
| 56 | + |
| 57 | + @Test fun allThemes() = snapshot.snapshotAllThemes { MyComponent() } |
| 58 | +} |
| 59 | +``` |
| 60 | + |
| 61 | +### Using factory functions directly |
| 62 | + |
| 63 | +For more control, use `TestifyPaparazzi` factory functions with the snapshot extension functions: |
| 64 | + |
| 65 | +```kotlin |
| 66 | +class MyComponentTest { |
| 67 | + |
| 68 | + @get:Rule val paparazzi = TestifyPaparazzi.component() |
| 69 | + |
| 70 | + @Test fun default() { |
| 71 | + paparazzi.themedSnapshot(myThemeProvider) { MyComponent() } |
| 72 | + } |
| 73 | + |
| 74 | + @Test fun allThemes() { |
| 75 | + paparazzi.snapshotAllThemes(myThemeProvider) { MyComponent() } |
| 76 | + } |
| 77 | +} |
| 78 | +``` |
| 79 | + |
| 80 | +### State matrix testing |
| 81 | + |
| 82 | +Snapshot multiple component states from a single test method: |
| 83 | + |
| 84 | +```kotlin |
| 85 | +@Test fun ratingStates() { |
| 86 | + paparazzi.snapshotStates( |
| 87 | + variants = listOf( |
| 88 | + StateVariant("zero_stars", 0), |
| 89 | + StateVariant("three_stars", 3), |
| 90 | + StateVariant("five_stars", 5), |
| 91 | + ), |
| 92 | + themeProvider = myThemeProvider, |
| 93 | + ) { rating -> |
| 94 | + RatingBar(rating = rating) |
| 95 | + } |
| 96 | +} |
| 97 | +``` |
| 98 | + |
| 99 | +### Font scale testing |
| 100 | + |
| 101 | +Verify your UI at different accessibility font sizes: |
| 102 | + |
| 103 | +```kotlin |
| 104 | +@Test fun largeFonts() { |
| 105 | + paparazzi.snapshotAllFontScales { MyComponent() } |
| 106 | +} |
| 107 | +``` |
| 108 | + |
| 109 | +--- |
| 110 | + |
| 111 | +# License |
| 112 | + |
| 113 | + MIT License |
| 114 | + |
| 115 | + Copyright (c) 2026 ndtp |
| 116 | + |
| 117 | + Permission is hereby granted, free of charge, to any person obtaining a copy |
| 118 | + of this software and associated documentation files (the "Software"), to deal |
| 119 | + in the Software without restriction, including without limitation the rights |
| 120 | + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 121 | + copies of the Software, and to permit persons to whom the Software is |
| 122 | + furnished to do so, subject to the following conditions: |
| 123 | + |
| 124 | + The above copyright notice and this permission notice shall be included in all |
| 125 | + copies or substantial portions of the Software. |
| 126 | + |
| 127 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 128 | + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 129 | + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 130 | + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 131 | + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 132 | + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 133 | + SOFTWARE. |
0 commit comments