### Groovy DSL Configuration for Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/preview_support.md Example of how to configure Roborazzi using Groovy DSL, using the set method for assignments. ```groovy generateComposePreviewRobolectricTests.enable.set(true) generateComposePreviewRobolectricTests.packages.set(["com.example"]) ``` -------------------------------- ### Configure Roborazzi Recording Options in gradle.properties Source: https://github.com/takahirom/roborazzi/blob/main/README.md Set Roborazzi recording options directly in your `gradle.properties` file or via command-line arguments. This example shows how to enable recording and set a resize scale. ```properties roborazzi.test.record=true # roborazzi.test.compare=true # roborazzi.test.verify=true ``` ```properties roborazzi.record.resizeScale=0.5 ``` -------------------------------- ### Write a Roborazzi Test for Compose Desktop Source: https://github.com/takahirom/roborazzi/blob/main/README.md Implement a test class using Roborazzi's testing utilities for Compose Desktop. This example captures an image of the root UI, performs a click action, and captures another image. ```kotlin class MainKmpTest { @OptIn(ExperimentalTestApi::class) @Test fun test() = runDesktopComposeUiTest { setContent { App() } val roborazziOptions = RoborazziOptions( recordOptions = RoborazziOptions.RecordOptions( resizeScale = 0.5 ), compareOptions = RoborazziOptions.CompareOptions( changeThreshold = 0F ) ) onRoot().captureRoboImage(roborazziOptions = roborazziOptions) onNodeWithTag("button").performClick() onRoot().captureRoboImage(roborazziOptions = roborazziOptions) } } ``` -------------------------------- ### Define a Composable UI for Testing Source: https://github.com/takahirom/roborazzi/blob/main/README.md Create a Composable function that represents the UI you want to test. This example shows a simple button that changes text when clicked. ```kotlin @Composable fun App() { var text by remember { mutableStateOf("Hello, World!") } MaterialTheme { Button( modifier = Modifier.testTag("button"), onClick = { text = "Hello, Desktop!" }) { Text( style = MaterialTheme.typography.h2, text = text ) } } } ``` -------------------------------- ### Accessibility Check Log Output Examples Source: https://github.com/takahirom/roborazzi/blob/main/roborazzi-accessibility-check/README.md Examples of log output for accessibility checks, showing different issue types (Error, Warning) and the details provided for each. ```text Error: [AccessibilityViewCheckResult check=AccessibilityHierarchyCheckResult ERROR SpeakableTextPresentCheck 4 [ViewHierarchyElement class=android.view.View bounds=Rect(474, 1074 - 606, 1206)] null num_answers:0 view=null] Warning: [AccessibilityViewCheckResult check=AccessibilityHierarchyCheckResult WARNING TextContrastCheck 11 [ViewHierarchyElement class=android.widget.TextView text=Something hard to read bounds=Rect(403, 1002 - 678, 1092)] {KEY_BACKGROUND_COLOR=-12303292, KEY_CONTRAST_RATIO=1.02, KEY_FOREGROUND_COLOR=-12369085, KEY_REQUIRED_CONTRAST_RATIO=3.0} num_answers:0 view=null] ``` -------------------------------- ### Implement Manual AI Assertion with Custom LLM Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/ai_powered_image_assertion.md Provide a custom `AiAssertionModel` implementation within `RoborazziOptions` to use your own LLM for image assertion. This example demonstrates how to structure the results. ```kotlin compareOptions = RoborazziOptions.CompareOptions( aiAssertionOptions = AiAssertionOptions( aiAssertionModel = object : AiAssertionOptions.AiAssertionModel { override fun assert( comparisonImageFilePath: String, aiAssertionOptions: AiAssertionOptions ): AiAssertionResults { // You can use any LLMs here to create AiAssertionResults return AiAssertionResults( aiAssertionResults = aiAssertionOptions.aiAssertions.map { assertion -> AiAssertionResult( assertionPrompt = assertion.assertionPrompt, fulfillmentPercent = fulfillmentPercent, requiredFulfillmentPercent = assertion.requiredFulfillmentPercent, failIfNotFulfilled = assertion.failIfNotFulfilled, explanation = "This is a manual test.", ) } ) } }, aiAssertions = listOf( AiAssertionOptions.AiAssertion( assertionPrompt = "it should have PREVIOUS button", requiredFulfillmentPercent = 90, ), ), ) ) ... ``` -------------------------------- ### Write Compose Multiplatform iOS Test with Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/README.md Example of an iOS test using Roborazzi with Compose Multiplatform. This test sets up a basic UI and captures screenshots using `captureRoboImage`. ```kotlin class IosTest { @OptIn(ExperimentalTestApi::class) @Test fun test() { runComposeUiTest { setContent { MaterialTheme { Column { Button( modifier = Modifier.alpha(alpha), onClick = { }) { Text("Hello World") } Box( modifier = Modifier .background(Color.Red.copy(alpha = alpha), MaterialTheme.shapes.small) .size(100.dp), ) } } } onRoot().captureRoboImage(this, filePath = "ios.png") onNodeWithText("Hello World").captureRoboImage( this, filePath = "ios_button.png" ) } } } ``` -------------------------------- ### Generate Jetpack Compose GIF with Test Rule Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/how_to_use.md Integrate RoborazziRule into a Jetpack Compose test to capture GIFs of your composable functions. This example demonstrates capturing a GIF of a composable that changes based on user interaction. ```kotlin @RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) class ComposeTest { @get:Rule val composeTestRule = createAndroidComposeRule() @get:Rule val roborazziRule = RoborazziRule( composeRule = composeTestRule, captureRoot = composeTestRule.onRoot(), options = RoborazziRule.Options( RoborazziRule.CaptureType.Gif() ) ) @Test fun composable() { composeTestRule.setContent { SampleComposableFunction() } (0 until 3).forEach { _ -> composeTestRule .onNodeWithTag("AddBoxButton") .performClick() } } } ``` -------------------------------- ### Configure Roborazzi for AI Image Assertion (Gemini) Source: https://github.com/takahirom/roborazzi/blob/main/README.md Set up Roborazzi with AI-powered image assertion using the Gemini model. This feature is experimental and runs only when images differ. Ensure your API key is securely managed, for example, via environment variables. ```kotlin ... @get:Rule val composeTestRule = createAndroidComposeRule() @get:Rule val roborazziRule = RoborazziRule( options = RoborazziRule.Options( roborazziOptions = RoborazziOptions( compareOptions = RoborazziOptions.CompareOptions( aiAssertionOptions = AiAssertionOptions( aiAssertionModel = GeminiAiAssertionModel( // DO NOT HARDCODE your API key in your code. // This is an example passing API Key through unitTests.all{ environment(key, value) } apiKey = System.getenv("gemini_api_key") ?: "" ), ) ) ) ) ) @Test fun captureWithAi() { ROBORAZZI_DEBUG = true onView(ViewMatchers.isRoot()) .captureRoboImage( roborazziOptions = provideRoborazziContext().options.addedAiAssertions( AiAssertionOptions.AiAssertion( assertionPrompt = "it should have PREVIOUS button", requiredFulfillmentPercent = 90, ), AiAssertionOptions.AiAssertion( assertionPrompt = "it should show First Fragment", requiredFulfillmentPercent = 90, ) ) ) } ``` -------------------------------- ### Enable Experimental WebP Support Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/how_to_use.md Configure your project to generate WebP images by setting `roborazzi.record.image.extension` in `gradle.properties`. Add the `webp-imageio` dependency for lossless WebP support. ```properties roborazzi.record.image.extension=webp ``` ```kotlin onView(ViewMatchers.withId(R.id.textview_first)) .captureRoboImage( roborazziOptions = RoborazziOptions( recordOptions = RoborazziOptions.RecordOptions( imageIoFormat = LosslessWebPImageIoFormat(), ), ) ) ``` -------------------------------- ### Write UI Tests for Compose Desktop with Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/compose_multiplatform.md Use `runDesktopComposeUiTest` to set up your Composable UI and capture screenshots with custom Roborazzi options. ```kotlin class MainKmpTest { @OptIn(ExperimentalTestApi::class) @Test fun test() = runDesktopComposeUiTest { setContent { App() } val roborazziOptions = RoborazziOptions( recordOptions = RoborazziOptions.RecordOptions( resizeScale = 0.5 ), compareOptions = RoborazziOptions.CompareOptions( changeThreshold = 0F ) ) onRoot().captureRoboImage(roborazziOptions = roborazziOptions) onNodeWithTag("button").performClick() onRoot().captureRoboImage(roborazziOptions = roborazziOptions) } } ``` -------------------------------- ### Configure Roborazzi Output Directories Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md Customize the directories for reference and comparison images in your `build.gradle` file. This allows you to organize your screenshot assets. ```kotlin roborazzi { // Directory for reference images outputDir.set(file("src/screenshots")) // Directory for comparison images (Experimental option) compare { outputDir.set(file("build/outputs/screenshots_comparison")) } } ``` -------------------------------- ### Write UI Tests for Compose Multiplatform iOS with Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/compose_multiplatform.md Utilize `runComposeUiTest` to set up your Composable UI and capture screenshots for testing. ```kotlin class IosTest { @OptIn(ExperimentalTestApi::class) @Test fun test() { runComposeUiTest { setContent { MaterialTheme { Column { Button( modifier = Modifier.alpha(alpha), onClick = { }) { Text("Hello World") } Box( modifier = Modifier .background(Color.Red.copy(alpha = alpha), MaterialTheme.shapes.small) .size(100.dp), ) } } } onRoot().captureRoboImage(this, filePath = "ios.png") onNodeWithText("Hello World").captureRoboImage( this, filePath = "ios_button.png" ) } } } ``` -------------------------------- ### Configure Gemini AI Assertion in Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/ai_powered_image_assertion.md Set up Roborazzi to use the Gemini AI model for image assertions. Ensure your API key is securely managed, for example, through environment variables. ```kotlin import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.onView import androidx.compose.ui.test.performClick import androidx.test.espresso.matcher.ViewMatchers import io.github.takahirom.roborazzi.* import io.github.takahirom.roborazzi.compare.AiAssertionOptions import io.github.takahirom.roborazzi.compare.AiAssertionOptions.AiAssertion import io.github.takahirom.roborazzi.compare.AiAssertionOptions.AiAssertionModel import io.github.takahirom.roborazzi.compare.AiAssertionResults import io.github.takahirom.roborazzi.compare.GeminiAiAssertionModel import org.junit.Rule import org.junit.Test class ExampleActivityTest { @get:Rule val composeTestRule = createAndroidComposeRule() @get:Rule val roborazziRule = RoborazziRule( options = RoborazziRule.Options( roborazziOptions = RoborazziOptions( compareOptions = RoborazziOptions.CompareOptions( aiAssertionOptions = AiAssertionOptions( aiAssertionModel = GeminiAiAssertionModel( // DO NOT HARDCODE your API key in your code. // This is an example passing API Key through unitTests.all{ environment(key, value) } apiKey = System.getenv("gemini_api_key") ?: "" ) ) ) ) ) ) @Test fun captureWithAi() { ROBORAZZI_DEBUG = true onView(ViewMatchers.isRoot()) .captureRoboImage( roborazziOptions = provideRoborazziContext().options.addedAiAssertions( AiAssertionOptions.AiAssertion( assertionPrompt = "it should have PREVIOUS button", requiredFulfillmentPercent = 90, ), AiAssertionOptions.AiAssertion( assertionPrompt = "it should show First Fragment", requiredFulfillmentPercent = 90, ) ) ) } } ``` -------------------------------- ### Run Unit Tests for Verify and Record Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md Run unit tests with both 'roborazzi.test.verify=true' and 'roborazzi.test.record=true' enabled to verify and potentially re-record screenshots. ```bash ./gradlew testDebugUnitTest ``` ```bash ./gradlew testDebugUnitTest -Proborazzi.test.verify=true -Proborazzi.test.record=true ``` -------------------------------- ### Run Roborazzi Gradle Tasks for Desktop Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/compose_multiplatform.md Execute Gradle tasks to record, compare, or verify UI snapshots on Desktop. ```bash ./gradlew recordRoborazzi[SourceSet] ``` ```bash ./gradlew recordRoborazziDesktop ./gradlew compareRoborazziDesktop ./gradlew verifyRoborazziDesktop ... ``` -------------------------------- ### Filter Screenshot Tests with Gradle Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/faq.md Configure your Gradle build to filter screenshot tests using JUnit categories and a custom project property. This setup allows running only screenshot tests when the -Pscreenshot flag is provided. ```groovy android { testOptions { unitTests { all { // -Pscreenshot to filter screenshot tests it.useJUnit { if (project.hasProperty("screenshot")) { includeCategories("io.github.takahirom.roborazzi.testing.category.ScreenshotTests") } } } } } } ``` -------------------------------- ### Implement Custom Image Format Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/how_to_use.md Create a custom image format by implementing `ImageIoFormat` with your own `AwtImageWriter` and `AwtImageLoader`. ```kotlin data class JvmImageIoFormat( val awtImageWriter: AwtImageWriter, val awtImageLoader: AwtImageLoader ) : ImageIoFormat ``` -------------------------------- ### Class-based Reusable Capturer for AndroidComposePreviewTester Source: https://github.com/takahirom/roborazzi/blob/main/proposals/01-make-AndroidComposePreviewTester-customizable.md Shows how to create a reusable class that implements the Capturer interface to customize capture behavior, specifically setting a change threshold for image comparison. ```kotlin import com.github.takahirom.roborazzi.core.compareOptions import com.github.takahirom.roborazzi.core.copy import com.github.takahirom.roborazzi.core.imageComparator import com.github.takahirom.roborazzi.core.SimpleImageComparator class ChangeThresholdCapturer(private val threshold: Float) : Capturer { override fun capture(parameter: CaptureParameter) { val customOptions = parameter.roborazziOptions.copy( compareOptions = parameter.roborazziOptions.compareOptions.copy( imageComparator = SimpleImageComparator(maxDistance = threshold) ) ) parameter.preview.captureRoboImage( filePath = parameter.filePath, roborazziOptions = customOptions, roborazziComposeOptions = parameter.roborazziComposeOptions ) } } class CustomTester : AndroidComposePreviewTester( capturer = ChangeThresholdCapturer(0.01f) ) ``` -------------------------------- ### Run Screenshot Tests with Gradle Source: https://github.com/takahirom/roborazzi/blob/main/CONTRIBUTING.md Execute screenshot tests for Roborazzi. Use 'record' to create baseline images, 'verify' to check against baselines, and 'compare' to generate diffs. Ensure your changes are tested against sample modules. ```bash # First, record baseline screenshots ./gradlew recordRoborazziDebug ``` ```bash # Then, verify screenshots match the baseline ./gradlew verifyRoborazziDebug ``` ```bash # Or, compare and generate diff images ./gradlew compareRoborazziDebug ``` -------------------------------- ### Run Unit Tests for Recording Screenshots Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md Run unit tests with the 'roborazzi.test.record=true' property set in gradle.properties or via the command line to record screenshots. ```bash ./gradlew testDebugUnitTest ``` ```bash ./gradlew testDebugUnitTest -Proborazzi.test.record=true ``` -------------------------------- ### Initialize Materialize Components and Handle Image Modals Source: https://github.com/takahirom/roborazzi/blob/main/include-build/roborazzi-gradle-plugin/src/main/resources/META-INF/index.html Initializes Materialize CSS components like tabs and modals. It also sets up event listeners to open image modals when clicking on report images, displaying the selected image and its alt text. ```javascript M.AutoInit(); document.addEventListener('DOMContentLoaded', function() { M.Tabs.getInstance(document.getElementsByClassName("tabs")[0]).select('results'); var modalInstance = M.Modal.init(document.getElementById('imageBottomSheet'), {}); var modal = document.getElementById('imageBottomSheet'); var modalImage = document.getElementById('modalImage'); var modalTriggers = document.querySelectorAll('.modal-trigger'); modalTriggers.forEach(function(trigger) { trigger.addEventListener('click', function() { var src = this.getAttribute('src'); var alt = this.getAttribute('data-alt'); modalImage.setAttribute('src', src); modalImage.setAttribute('alt', alt); var instance = M.Modal.getInstance(modal); instance.open(); }); }); }); ``` -------------------------------- ### Configure Roborazzi Naming Strategy Source: https://github.com/takahirom/roborazzi/blob/main/README.md Choose a naming convention for your recorded screenshots. Options include `testPackageAndClassAndMethod`, `escapedTestPackageAndClassAndMethod`, and `testClassAndMethod`. ```properties roborazzi.record.namingStrategy=testClassAndMethod ``` -------------------------------- ### Composing Default Behavior in Custom Capturer Source: https://github.com/takahirom/roborazzi/blob/main/proposals/01-make-AndroidComposePreviewTester-customizable.md Demonstrates the recommended approach for custom capturers that need to utilize the default capture behavior by explicitly composing the DefaultCapturer. ```kotlin class CustomCapturer( private val defaultCapturer: Capturer = AndroidComposePreviewTester.DefaultCapturer() ) : Capturer { override fun capture(parameter: CaptureParameter) { // Use defaultCapturer as needed } } ``` -------------------------------- ### Verify and Record Screenshots with Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md Use verifyAndRecordRoborazziDebug to first verify images and then record new baselines if differences are found. ```bash ./gradlew verifyAndRecordRoborazziDebug ``` -------------------------------- ### Review Image Changes using Unit Test Task Source: https://github.com/takahirom/roborazzi/blob/main/README.md Review image changes by running the unit test task with `roborazzi.test.compare=true` set in `gradle.properties` or via command line. ```bash ./gradlew testDebugUnitTest ``` ```properties roborazzi.test.compare=true ``` ```bash ./gradlew testDebugUnitTest -Proborazzi.test.compare=true ``` -------------------------------- ### Verify and Record Screenshots using Unit Test Task Source: https://github.com/takahirom/roborazzi/blob/main/README.md Perform verification and recording by running the unit test task with both `roborazzi.test.verify=true` and `roborazzi.test.record=true` properties set. ```bash ./gradlew testDebugUnitTest ``` ```properties roborazzi.test.verify=true roborazzi.test.record=true ``` ```bash ./gradlew testDebugUnitTest -Proborazzi.test.verify=true -Proborazzi.test.record=true ``` -------------------------------- ### Custom Capturer Implementation for AndroidComposePreviewTester Source: https://github.com/takahirom/roborazzi/blob/main/proposals/01-make-AndroidComposePreviewTester-customizable.md Illustrates how users can create a custom `AndroidComposePreviewTester` by providing a custom `capturer` lambda for specific logic. ```kotlin class MyTester : AndroidComposePreviewTester( capturer = { parameter -> /* custom logic */ } ) ``` -------------------------------- ### Run Unit Tests for Verifying Screenshots Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md To verify screenshots, run unit tests with 'roborazzi.test.verify=true' enabled, either in gradle.properties or via the command line. ```bash ./gradlew testDebugUnitTest ``` ```bash ./gradlew testDebugUnitTest -Proborazzi.test.verify=true ``` -------------------------------- ### Configure Device with @Config Annotation Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/how_to_use.md Configure the device environment for tests using the `@Config` annotation. This allows you to specify qualifiers like predefined device types, night mode, locale, and screen size. ```kotlin @RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) @Config(qualifiers = RobolectricDeviceQualifiers.Pixel5) class RoborazziTest { ``` ```kotlin @Test @Config(qualifiers = RobolectricDeviceQualifiers.Pixel5) fun test() { ``` ```kotlin @Config(qualifiers = "+night") ``` ```kotlin @Config(qualifiers = "+ja") ``` ```kotlin @Config(qualifiers = RobolectricDeviceQualifiers.MediumTablet) ``` -------------------------------- ### Configure WebP Image Extension Source: https://github.com/takahirom/roborazzi/blob/main/README.md Sets the image file extension to 'webp' in gradle.properties for generating WebP images. This is a project-level configuration. ```properties roborazzi.record.image.extension=webp ``` -------------------------------- ### Enable Compose Preview Screenshot Test Generation Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/preview_support.md Enable the feature to generate Compose Preview screenshot tests by adding this configuration to your build.gradle.kts file. ```kotlin roborazzi { generateComposePreviewRobolectricTests { enable = true } } ``` -------------------------------- ### Capture Espresso View Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/how_to_use.md Capture screenshots using Espresso's `onView()` with `ViewMatchers.isRoot()` to capture the entire screen or `withId()` to target a specific view. ```kotlin onView(ViewMatchers.isRoot()) .captureRoboImage() ``` ```kotlin onView(withId(R.id.button_first)) .captureRoboImage() ``` -------------------------------- ### Run Boxed Tests for Runtime APIs Source: https://github.com/takahirom/roborazzi/blob/main/CONTRIBUTING.md Execute tests that ensure a clean environment for Roborazzi's runtime APIs, such as 'compare'. These tests manage screenshot files to create a predictable state. ```bash ./gradlew :sample-android:test ``` -------------------------------- ### Record Screenshots with Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md Execute the recordRoborazzi task to capture screenshots. The default output directory is 'build/outputs/roborazzi', and reports are available at 'build/reports/roborazzi/index.html'. ```bash ./gradlew recordRoborazziDebug ``` -------------------------------- ### Sample Composable Function for Testing Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/how_to_use.md A sample Jetpack Compose function that can be used for UI testing with Roborazzi. It includes a clickable element that modifies the UI. ```kotlin @Composable fun SampleComposableFunction() { var count by remember { mutableStateOf(0) } Column( Modifier .size(300.dp) ) { Box( Modifier .testTag("AddBoxButton") .size(50.dp) .clickable { count++ } ) (0..count).forEach { Box( Modifier .size(30.dp) ) } } } ``` -------------------------------- ### Run Unit Tests for Comparing Screenshots Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md Execute unit tests with 'roborazzi.test.compare=true' enabled to compare screenshots. This can be set in gradle.properties or passed as a command-line argument. ```bash ./gradlew testDebugUnitTest ``` ```bash ./gradlew testDebugUnitTest -Proborazzi.test.compare=true ``` -------------------------------- ### Capture Image with Lossless WebP Format Source: https://github.com/takahirom/roborazzi/blob/main/README.md Captures a Robo image using RoborazziOptions to specify a lossless WebP image format. This requires adding the 'webp-imageio' dependency to your build.gradle.kts file. ```kotlin onView(ViewMatchers.withId(R.id.textview_first)) .captureRoboImage( roborazziOptions = RoborazziOptions( recordOptions = RoborazziOptions.RecordOptions( imageIoFormat = LosslessWebPImageIoFormat(), ), ) ) ``` -------------------------------- ### Custom Output Path and File Provider with RoborazziRule Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/how_to_use.md This Kotlin code demonstrates how to use RoborazziRule to customize the output directory path and file naming convention for captured screenshots. It's useful for organizing test outputs. ```kotlin @RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) class RuleTestWithPath { @get:Rule val roborazziRule = RoborazziRule( options = Options( outputDirectoryPath = "$DEFAULT_ROBORAZZI_OUTPUT_DIR_PATH/custom_outputDirectoryPath", outputFileProvider = { description, outputDirectory, fileExtension -> File( outputDirectory, "custom_outputFileProvider-${description.testClass.name}.${description.methodName}.$fileExtension" ) } ), ) @Test fun captureRoboImage() { launch(MainActivity::class.java) // The file will be saved using the rule's outputDirectoryPath and outputFileProvider onView(isRoot()).captureRoboImage() } } ``` -------------------------------- ### Run Roborazzi Gradle Tasks for Desktop Source: https://github.com/takahirom/roborazzi/blob/main/README.md Execute Gradle tasks to record or compare screenshots for your Compose Desktop application. The task names typically follow the pattern `recordRoborazzi[SourceSet]`. ```bash ./gradlew recordRoborazziDesktop ./gradlew compareRoborazziDesktop ./gradlew verifyRoborazziDesktop ... ``` -------------------------------- ### Record Screenshots using Unit Test Task Source: https://github.com/takahirom/roborazzi/blob/main/README.md Capture screenshots by running the unit test task with the `roborazzi.test.record=true` property set in `gradle.properties` or via command line. ```bash ./gradlew testDebugUnitTest ``` ```properties roborazzi.test.record=true ``` ```bash ./gradlew testDebugUnitTest -Proborazzi.test.record=true ``` -------------------------------- ### Run Roborazzi Gradle Tasks for iOS Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/compose_multiplatform.md Execute Gradle tasks to record, compare, or verify UI snapshots on iOS simulators. ```bash ./gradlew recordRoborazzi[SourceSet] ``` ```bash ./gradlew recordRoborazziIosSimulatorArm64 ./gradlew compareRoborazziIosSimulatorArm64 ./gradlew verifyRoborazziIosSimulatorArm64 ... ``` -------------------------------- ### Existing User Migration for AndroidComposePreviewTester Source: https://github.com/takahirom/roborazzi/blob/main/proposals/01-make-AndroidComposePreviewTester-customizable.md Shows that existing users do not need to change their code and can continue to use `AndroidComposePreviewTester` as before. ```kotlin // This continues to work class MyTester : AndroidComposePreviewTester() ``` -------------------------------- ### Filter Previews by Annotation (Include Mode) Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/preview_support.md Configure Roborazzi to capture only previews annotated with @RoboPreviewInclude by setting the annotationFilter. ```kotlin roborazzi { @OptIn(ExperimentalRoborazziApi::class) generateComposePreviewRobolectricTests { enable = true packages = listOf("com.example") annotationFilter = AnnotationFilter.Filter.RoboPreviewInclude } } ``` -------------------------------- ### GitHub Actions Job to Verify Screenshots Source: https://github.com/takahirom/roborazzi/blob/main/README.md This YAML configuration defines a GitHub Actions job to download previously stored screenshots and verify them against current test runs. It includes steps for checking out code, setting up Java, caching Gradle, downloading artifacts, running the verification task, and uploading any differences or test results. ```yaml name: verify test on: push env: GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx6g -Dorg.gradle.daemon=false -Dkotlin.incremental=false" jobs: test: runs-on: macos-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3.9.0 with: distribution: 'zulu' java-version: 19 - name: Gradle cache uses: gradle/gradle-build-action@v2 # Download screenshots from main branch - uses: dawidd6/action-download-artifact@v2 with: name: screenshots path: app/build/outputs/roborazzi workflow: test.yaml branch: main - name: verify test id: verify-test run: | # If there is a difference between the screenshots, the test will fail. ./gradlew app:verifyRoborazziDebug --stacktrace - uses: actions/upload-artifact@v3 if: ${{ always() }} with: name: screenshot-diff path: app/build/outputs/roborazzi retention-days: 30 - uses: actions/upload-artifact@v3 if: ${{ always() }} with: name: screenshot-diff-reports path: app/build/reports retention-days: 30 - uses: actions/upload-artifact@v3 if: ${{ always() }} with: name: screenshot-diff-test-results path: app/build/test-results retention-days: 30 ``` -------------------------------- ### Define Composable for Desktop Testing Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/compose_multiplatform.md Create a Composable function that will be used as the target for UI testing on Desktop. ```kotlin @Composable fun App() { var text by remember { mutableStateOf("Hello, World!") } MaterialTheme { Button( modifier = Modifier.testTag("button"), onClick = { text = "Hello, Desktop!" }) { Text( style = MaterialTheme.typography.h2, text = text ) } } } ``` -------------------------------- ### Configure Roborazzi Output Directory for Caching Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/faq.md Specify a custom `outputDir` in your `build.gradle` file to manage screenshot caching. This is useful for improving test stability, especially when dealing with inconsistent test results. ```gradle roborazzi { outputDir = "src/your/screenshot/folder" } ``` -------------------------------- ### Configure Screen Size for Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/README.md Utilize RobolectricDeviceQualifiers.MediumTablet within the @Config annotation to set the screen size for testing. ```kotlin @Config(qualifiers = RobolectricDeviceQualifiers.MediumTablet) ``` -------------------------------- ### Configure Image Comparator Custom Settings Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/how_to_use.md Adjust comparison options to mitigate differences caused by antialiasing. Set a change threshold and customize the image comparator with maximum distance and shift values. ```kotlin val roborazziRule = RoborazziRule( options = RoborazziRule.Options( roborazziOptions = RoborazziOptions( compareOptions = RoborazziOptions.CompareOptions( changeThreshold = 0.01, // For 1% accepted difference imageComparator = SimpleImageComparator( maxDistance = 0.007F, // 0.001F is default value from Differ vShift = 2, // Increasing the shift can help resolve antialiasing issues hShift = 2 // Increasing the shift can help resolve antialiasing issues ) ) ) ) ) ``` -------------------------------- ### Configure Roborazzi Test Behavior Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/gradle_properties_options.md Set `roborazzi.test.record` to true to enable recording. Other options like `compare` and `verify` can also be configured. ```properties roborazzi.test.record=true # roborazzi.test.compare=true # roborazzi.test.verify=true ``` -------------------------------- ### Configure Roborazzi File Path Strategy Source: https://github.com/takahirom/roborazzi/blob/main/README.md Specify how recorded image files should be named and where they should be saved. The `relativePathFromRoborazziContextOutputDirectory` strategy saves files to a configured output directory. ```properties roborazzi.record.filePathStrategy=relativePathFromRoborazziContextOutputDirectory ``` -------------------------------- ### Decorating Default Capturer Behavior in AndroidComposePreviewTester Source: https://github.com/takahirom/roborazzi/blob/main/proposals/01-make-AndroidComposePreviewTester-customizable.md Illustrates how to decorate the default capture behavior by creating a custom capturer that wraps the default implementation, allowing for pre- and post-processing steps. ```kotlin class CustomCapturer( private val defaultCapturer: Capturer = AndroidComposePreviewTester.DefaultCapturer() ) : Capturer { override fun capture(parameter: CaptureParameter) { // Pre-processing println("Capturing: ${parameter.filePath}") // Call default implementation defaultCapturer.capture(parameter) // Post-processing println("Captured: ${parameter.filePath}") } } class CustomTester : AndroidComposePreviewTester( capturer = CustomCapturer() ) ``` -------------------------------- ### Configure Roborazzi for Compose Desktop Multiplatform Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/compose_multiplatform.md Include the Roborazzi Compose Desktop dependency in your Gradle build for multiplatform desktop testing. ```kotlin plugins { kotlin("multiplatform") id("org.jetbrains.compose") id("io.github.takahirom.roborazzi") } kotlin { // You can use your source set name jvm("desktop") sourceSets { ... val desktopTest by getting { dependencies { implementation(project("io.github.takahirom.roborazzi:roborazzi-compose-desktop:[1.6.0-alpha-2 or higher]")) implementation(kotlin("test")) } } ... ``` -------------------------------- ### RoborazziRule Options Configuration Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/how_to_use.md This code defines the `RoborazziRule` class and its associated `Options` and `CaptureType` interfaces. It outlines the available configurations for screenshot capture, including output paths and types. ```kotlin /** * This rule is a JUnit rule for roborazzi. * This rule is optional. You can use [captureRoboImage] without this rule. * * This rule have two features. * 1. Provide context such as `RoborazziOptions` and `outputDirectoryPath` etc for [captureRoboImage]. * 2. Capture screenshots for each test when specifying RoborazziRule.options.captureType. */ class RoborazziRule private constructor( private val captureRoot: CaptureRoot, private val options: Options = Options() ) : TestWatcher() { /** * If you add this annotation to the test, the test will be ignored by * roborazzi's CaptureType.LastImage, CaptureType.AllImage and CaptureType.Gif. */ annotation class Ignore data class Options( val captureType: CaptureType = CaptureType.None, /** * output directory path */ val outputDirectoryPath: String = provideRoborazziContext().outputDirectory, val outputFileProvider: FileProvider = provideRoborazziContext().fileProvider ?: defaultFileProvider, val roborazziOptions: RoborazziOptions = provideRoborazziContext().options, ) sealed interface CaptureType { /** * Do not generate images. Just provide the image path to [captureRoboImage]. */ object None : CaptureType /** * Generate last images for each test */ data class LastImage( /** * capture only when the test fail */ val onlyFail: Boolean = false, ) : CaptureType /** * Generate images for Each layout change like TestClass_method_0.png for each test */ data class AllImage( /** * capture only when the test fail */ val onlyFail: Boolean = false, ) : CaptureType /** * Generate gif images for each test */ data class Gif( /** * capture only when the test fail */ val onlyFail: Boolean = false, ) : CaptureType } } ``` -------------------------------- ### Apply Roborazzi Plugin using apply plugin in Module build.gradle Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md An alternative way to apply the Roborazzi plugin in a module's build.gradle file using the apply plugin syntax. ```groovy apply plugin: "io.github.takahirom.roborazzi" ``` -------------------------------- ### Lambda-based Customization of AndroidComposePreviewTester Source: https://github.com/takahirom/roborazzi/blob/main/proposals/01-make-AndroidComposePreviewTester-customizable.md Demonstrates how to customize the capture behavior by providing a lambda function to the AndroidComposePreviewTester constructor, allowing modification of comparison options. ```kotlin import com.github.takahirom.roborazzi.core.compareOptions import com.github.takahirom.roborazzi.core.copy import com.github.takahirom.roborazzi.core.imageComparator import com.github.takahirom.roborazzi.core.SimpleImageComparator class CustomTester : AndroidComposePreviewTester( capturer = { parameter -> val customOptions = parameter.roborazziOptions.copy( compareOptions = parameter.roborazziOptions.compareOptions.copy( imageComparator = SimpleImageComparator(maxDistance = 0.01f) ) ) parameter.preview.captureRoboImage( filePath = parameter.filePath, roborazziOptions = customOptions, roborazziComposeOptions = parameter.roborazziComposeOptions ) } ) ``` -------------------------------- ### Configure Roborazzi Plugin Dependency in Root build.gradle.kts Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md Add the Roborazzi Gradle plugin as a classpath dependency in the root build.gradle.kts file. Replace '[version]' with the correct version. ```kotlin buildscript { dependencies { ... classpath("io.github.takahirom.roborazzi:roborazzi-gradle-plugin:[version]") } } ``` -------------------------------- ### Gradle Task for JVM Plugin Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/compose_multiplatform.md If using the Kotlin JVM plugin, the Gradle task name for recording Roborazzi snapshots will be suffixed with 'Jvm'. ```bash recordRoborazzi**Jvm** ``` -------------------------------- ### Custom ComposePreviewTester Implementation Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/preview_support.md Implement a custom ComposePreviewTester to control screenshot capture behavior, such as setting a custom image comparison threshold. ```kotlin import com.dropbox.differ.SimpleImageComparator import com.github.takahirom.roborazzi.* @ExperimentalRoborazziApi class MyCustomComposePreviewTester( private val defaultCapturer: AndroidComposePreviewTester.Capturer = AndroidComposePreviewTester.DefaultCapturer() ) : AndroidComposePreviewTester( capturer = { parameter -> val customOptions = parameter.roborazziOptions.copy( compareOptions = parameter.roborazziOptions.compareOptions.copy( // Set custom comparison threshold (0.0 = exact match, 1.0 = ignore differences) imageComparator = SimpleImageComparator(maxDistance = 0.01f) ) ) defaultCapturer.capture( parameter.copy(roborazziOptions = customOptions) ) } ) ``` -------------------------------- ### Capture Entire Screen with Dialogs Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/how_to_use.md The experimental `captureScreenRoboImage()` function captures the entire screen, including any displayed dialogs or overlays. Use this for comprehensive screen captures. ```kotlin captureScreenRoboImage() ``` -------------------------------- ### Customize Compose Preview Screenshot Test Generation Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/preview_support.md Customize the generated Compose Preview screenshot tests by configuring package scanning, Robolectric settings, inclusion of private previews, custom tester class, generated test class count, and annotation filtering. ```kotlin roborazzi { @OptIn(ExperimentalRoborazziApi::class) generateComposePreviewRobolectricTests { enable = true // The package names to scan for Composable Previews. packages = listOf("com.example") // robolectricConfig will be passed to Robolectric's @Config annotation in the generated test class. // See https://robolectric.org/configuring/ for more information. robolectricConfig = mapOf( "sdk" to "[32]", "qualifiers" to "RobolectricDeviceQualifiers.Pixel5", ) // If true, the private previews will be included in the test. includePrivatePreviews = true // The fully qualified class name of the custom test class that implements [com.github.takahirom.roborazzi.ComposePreviewTester]. testerQualifiedClassName = "com.example.MyCustomComposePreviewTester" // The number of test classes to generate. Set this to match maxParallelForks for parallel test execution. generatedTestClassCount = 4 // Filter previews by annotation. Defaults to AnnotationFilter.Filter.RoboPreviewExclude // (previews annotated with @RoboPreviewExclude are skipped). Override to switch to opt-in mode // where only previews annotated with @RoboPreviewInclude are captured. annotationFilter = AnnotationFilter.Filter.RoboPreviewInclude } } ``` -------------------------------- ### Configure Locale for Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/README.md Use '+ja' in the @Config qualifiers to set the locale to Japanese for screenshot testing. ```kotlin @Config(qualifiers = "+ja") ``` -------------------------------- ### Capture Composable Preview with Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/preview_support.md Use the captureRoboImage() extension function on ComposablePreview to capture Composable Previews using settings from Preview annotations. ```kotlin fun ComposablePreview.captureRoboImage( filePath: String, roborazziOptions: RoborazziOptions ) ``` -------------------------------- ### Define Roborazzi Plugin in Root build.gradle Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md Use this to define the Roborazzi plugin in the root build.gradle file. Replace '[version]' with the actual plugin version. ```groovy plugins { ... id "io.github.takahirom.roborazzi" version "[version]" apply false } ``` -------------------------------- ### Configure Time-Based Captures with @RoboComposePreviewOptions Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/preview_support.md Use @RoboComposePreviewOptions to configure manual clock options for time-based captures in Compose Previews. This is useful for testing animations or delayed state changes. ```kotlin @RoboComposePreviewOptions( manualClockOptions = [ManualClockOptions(advanceTimeMillis = 516L)] ) @Preview @Composable fun DelayedPreview() { var visible by remember { mutableStateOf(false) } LaunchedEffect(Unit) { delay(500) visible = true } if (visible) { Text("Content appears after 500ms") } } ``` -------------------------------- ### Configure RoborazziRule with Custom Output Path and File Provider Source: https://github.com/takahirom/roborazzi/blob/main/README.md Use RoborazziRule to specify custom output directory paths and file naming conventions for captured images. This allows for more organized and descriptive file storage. ```kotlin @RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) class RuleTestWithPath { @get:Rule val roborazziRule = RoborazziRule( options = Options( outputDirectoryPath = "$DEFAULT_ROBORAZZI_OUTPUT_DIR_PATH/custom_outputDirectoryPath", outputFileProvider = { description, outputDirectory, fileExtension -> File( outputDirectory, "custom_outputFileProvider-${description.testClass.name}.${description.methodName}.$fileExtension" ) } ), ) @Test fun captureRoboImage() { launch(MainActivity::class.java) // The file will be saved using the rule's outputDirectoryPath and outputFileProvider onView(isRoot()).captureRoboImage() } } ``` -------------------------------- ### Configure Night Mode for Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/README.md Add '+night' to the qualifiers in the @Config annotation to enable night mode for screenshot testing. ```kotlin @Config(qualifiers = "+night") ``` -------------------------------- ### Define Roborazzi Plugin in Root build.gradle.kts Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md Use this to define the Roborazzi plugin in the root build.gradle.kts file. Ensure you replace '[version]' with the actual plugin version. ```kotlin plugins { ... id("io.github.takahirom.roborazzi") version "[version]" apply false } ``` -------------------------------- ### Update Gradle Wrapper for Optimization Warning Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/faq.md Resolve Java lambda optimization warnings by upgrading your Gradle version. Modify the `distributionUrl` in `gradle-wrapper.properties` to point to Gradle 7.6.2 or later. ```properties distributionUrl=https://services.gradle.org/distributions/gradle-7.6.2-bin.zip ``` -------------------------------- ### Compare Screenshots with Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md Use the compareRoborazzi task to review changes by comparing current screenshots with saved ones. A comparison image and a diff JSON file will be generated. ```bash ./gradlew compareRoborazziDebug ``` -------------------------------- ### Set Roborazzi Record Naming Strategy Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/gradle_properties_options.md Customize `roborazzi.record.namingStrategy` to control the naming convention of recorded screenshots. Options include `testPackageAndClassAndMethod`, `escapedTestPackageAndClassAndMethod`, and `testClassAndMethod`. ```properties roborazzi.record.namingStrategy=testClassAndMethod ``` -------------------------------- ### Run Integration Tests for Gradle Plugin Source: https://github.com/takahirom/roborazzi/blob/main/CONTRIBUTING.md Execute integration tests for the Roborazzi Gradle plugin functionality. These tests verify the plugin's behavior with real Gradle projects. You can run all tests or filter by specific test cases. ```bash # Run from project root cd include-build && ./gradlew roborazzi-gradle-plugin:integrationTest && cd .. # Or run specific tests cd include-build && ./gradlew roborazzi-gradle-plugin:integrationTest --tests "*RoborazziGradleProjectTest.record" && cd .. ``` -------------------------------- ### Resolve Gradle Optimization Warning Source: https://github.com/takahirom/roborazzi/blob/main/README.md Upgrade to Gradle 7.6.2 by changing the distribution URL in gradle-wrapper.properties to resolve optimization warnings related to Java lambdas. ```properties distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip ``` -------------------------------- ### Extensible CaptureParameter Data Class Source: https://github.com/takahirom/roborazzi/blob/main/proposals/01-make-AndroidComposePreviewTester-customizable.md Demonstrates how to extend the `CaptureParameter` data class with new fields while maintaining backward compatibility by providing default values. ```kotlin data class CaptureParameter( val preview: ComposablePreview, val filePath: String, val roborazziComposeOptions: RoborazziComposeOptions, val roborazziOptions: RoborazziOptions = provideRoborazziContext().options, // Future fields can be added with default values val newField: String = "default" ) ``` -------------------------------- ### Add Roborazzi Core Dependencies Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/build_setup.md Include the core Roborazzi library for essential screenshot testing functionalities. ```gradle testImplementation("io.github.takahirom.roborazzi:roborazzi:[version]") ``` -------------------------------- ### Specify Roborazzi Record File Path Strategy Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/gradle_properties_options.md Configure `roborazzi.record.filePathStrategy` to define how recorded image files are named and located. The default is `relativePathFromCurrentDirectory`. ```properties roborazzi.record.filePathStrategy=relativePathFromRoborazziContextOutputDirectory ``` -------------------------------- ### Add Compose Preview Scanner Support Dependency Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/preview_support.md Add this dependency to use the ComposablePreviewScanner helper function for capturing Composable Previews. ```gradle testImplementation("io.github.takahirom.roborazzi:roborazzi-compose-preview-scanner-support:[version]") ``` -------------------------------- ### Validate Screenshots using Unit Test Task Source: https://github.com/takahirom/roborazzi/blob/main/README.md Validate screenshots by running the unit test task with `roborazzi.test.verify=true` set in `gradle.properties` or via command line. ```bash ./gradlew testDebugUnitTest ``` ```properties roborazzi.test.verify=true ``` ```bash ./gradlew testDebugUnitTest -Proborazzi.test.verify=true ``` -------------------------------- ### Configure Robolectric Pixel Copy Render Mode Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/gradle_properties_options.md Enhance screenshot accuracy by setting `robolectric.pixelCopyRenderMode` to `hardware` within your `build.gradle` file's `testOptions`. ```gradle android { testOptions { ... unitTests { isIncludeAndroidResources = true isReturnDefaultValues = true all { it.systemProperties["robolectric.pixelCopyRenderMode"] = "hardware" } ``` -------------------------------- ### Generate GIF Animation with Roborazzi Source: https://github.com/takahirom/roborazzi/blob/main/docs/topics/how_to_use.md This Kotlin code snippet shows how to capture a GIF animation of UI interactions. It uses `captureRoboGif` to record a sequence of UI states after launching an activity and performing actions. ```kotlin @Test fun captureRoboGifSample() { onView(ViewMatchers.isRoot()) .captureRoboGif("build/test.gif") { // launch ActivityScenario.launch(MainActivity::class.java) // move to next page onView(withId(R.id.button_first)) .perform(click()) // back pressBack() // move to next page onView(withId(R.id.button_first)) .perform(click()) } } ```