### Parameterized Preview Test Setup Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Sets up a parameterized test for Android previews using Paparazzi. It caches scanned previews for optimization and creates a Paparazzi rule for each preview. ```kotlin @RunWith(Parameterized::class) class PreviewTestParameterTests( val preview: ComposablePreview, ) { companion object { // Optimization: This avoids scanning for every test private val cachedPreviews: List> by lazy { AndroidComposablePreviewScanner() .scanPackageTrees("your.package", "your.package2") .includeAnnotationInfoForAllOf(PaparazziConfig::class.java) .getPreviews() } @JvmStatic @Parameterized.Parameters fun values(): List> = cachedPreviews } @get:Rule val paparazzi: Paparazzi = PaparazziPreviewRule.createFor(preview) @Test fun snapshot() { val screenshotId = AndroidPreviewScreenshotIdBuilder(preview).build() paparazzi.snapshot(name = screenshotId) { val previewInfo = preview.previewInfo when (previewInfo.showSystemUi) { false -> PreviewBackground( showBackground = previewInfo.showBackground, backgroundColor = previewInfo.backgroundColor ) { preview() } } } } } ``` -------------------------------- ### Configure JitPack Repository in Root build.gradle Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Add the JitPack repository to your root build.gradle file to enable dependency resolution from JitPack. This is a one-time setup for your project. ```kotlin allprojects { repositories { maven { url = uri('https://jitpack.io') } } } ``` -------------------------------- ### Get Pixel Device Identifiers Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/android/api.txt Retrieve identifiers for various Google Pixel devices. These methods return a unique Identifier object for each specified Pixel model. ```APIDOC ## Get Device Identifiers ### Description Provides methods to retrieve unique identifiers for various Android devices. ### Methods - **getPIXEL()**: Returns the identifier for a standard Pixel device. - **getPIXEL_XL()**: Returns the identifier for the Pixel XL device. - **getPIXEL_2()**: Returns the identifier for the Pixel 2 device. - **getPIXEL_2_XL()**: Returns the identifier for the Pixel 2 XL device. - **getPIXEL_3()**: Returns the identifier for the Pixel 3 device. - **getPIXEL_3_XL()**: Returns the identifier for the Pixel 3 XL device. - **getPIXEL_3A()**: Returns the identifier for the Pixel 3a device. - **getPIXEL_3A_XL()**: Returns the identifier for the Pixel 3a XL device. - **getPIXEL_4()**: Returns the identifier for the Pixel 4 device. - **getPIXEL_4_XL()**: Returns the identifier for the Pixel 4 XL device. - **getPIXEL_4A()**: Returns the identifier for the Pixel 4a device. - **getPIXEL_5()**: Returns the identifier for the Pixel 5 device. - **getPIXEL_6()**: Returns the identifier for the Pixel 6 device. - **getPIXEL_6_PRO()**: Returns the identifier for the Pixel 6 Pro device. - **getPIXEL_6A()**: Returns the identifier for the Pixel 6a device. - **getPIXEL_7()**: Returns the identifier for the Pixel 7 device. - **getPIXEL_7_PRO()**: Returns the identifier for the Pixel 7 Pro device. - **getPIXEL_7A()**: Returns the identifier for the Pixel 7a device. - **getPIXEL_8()**: Returns the identifier for the Pixel 8 device. - **getPIXEL_8_PRO()**: Returns the identifier for the Pixel 8 Pro device. - **getPIXEL_8A()**: Returns the identifier for the Pixel 8a device. - **getPIXEL_9()**: Returns the identifier for the Pixel 9 device. - **getPIXEL_9_PRO()**: Returns the identifier for the Pixel 9 Pro device. - **getPIXEL_9A()**: Returns the identifier for the Pixel 9a device. - **getPIXEL_9_PRO_XL()**: Returns the identifier for the Pixel 9 Pro XL device. - **getPIXEL_9_PRO_FOLD()**: Returns the identifier for the Pixel 9 Pro Fold device. - **getPIXEL_10()**: Returns the identifier for the Pixel 10 device. - **getPIXEL_10_PRO()**: Returns the identifier for the Pixel 10 Pro device. - **getPIXEL_10_PRO_XL()**: Returns the identifier for the Pixel 10 Pro XL device. - **getPIXEL_10_PRO_FOLD()**: Returns the identifier for the Pixel 10 Pro Fold device. - **getPIXEL_C()**: Returns the identifier for the Pixel C tablet. - **getPIXEL_FOLD()**: Returns the identifier for the Pixel Fold device. - **getPIXEL_TABLET()**: Returns the identifier for the Pixel Tablet device. ### Other Device Identifiers - **getQVGA_2_7IN()**: Returns the identifier for a 2.7-inch QVGA screen device. - **getQVGA_2_7IN_SLIDER()**: Returns the identifier for a 2.7-inch QVGA slider device. - **getQVGA_3_2IN_ADP2()**: Returns the identifier for a 3.2-inch QVGA device (ADP2). - **getRESIZABLE_EXPERIMENTAL()**: Returns the identifier for a resizable experimental device configuration. ``` -------------------------------- ### Build Device Configuration from Preview Info Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Build a DeviceConfig object using parsed device information and calculated screen dimensions from AndroidPreviewInfo. Handles cases where device information might be missing. ```kotlin object DeviceConfigBuilder { fun build(preview: AndroidPreviewInfo): DeviceConfig { val parsedDevice = DevicePreviewInfoParser.parse(preview.device)?.inPx() ?: return DeviceConfig() val dimensions = ScreenDimensions.dimensions( parsedDevice = parsedDevice, widthDp = preview.widthDp, heightDp = preview.heightDp ) ``` -------------------------------- ### Run Paparazzi Tests (Record) Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/paparazzi-plugin/README.md Execute the Gradle task to generate and record Paparazzi screenshots for composable previews. ```bash ./gradlew your_module:recordPaparazziDebug ``` -------------------------------- ### Run Paparazzi Tests (Verify) Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/paparazzi-plugin/README.md Execute the Gradle task to generate and verify Paparazzi screenshots against existing recordings. ```bash ./gradlew your_module:verifyPaparazziDebug ``` -------------------------------- ### Mapping PreviewInfo to RoborazziComposeOptions Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Map PreviewInfo details to RoborazziComposeOptions for configuring the composable preview environment. ```kotlin object RoborazziComposeOptionsMapper { @OptIn(ExperimentalRoborazziApi::class) fun createFor(preview: ComposablePreview): RoborazziComposeOptions = RoborazziComposeOptions { val previewInfo = preview.previewInfo previewDevice(previewInfo.device.ifBlank { Devices.NEXUS_5 } ) size( widthDp = previewInfo.widthDp, heightDp = previewInfo.heightDp ) background( showBackground = previewInfo.showBackground, backgroundColor = previewInfo.backgroundColor ) locale(previewInfo.locale) uiMode(previewInfo.uiMode) fontScale(previewInfo.fontScale) } } ``` -------------------------------- ### Mapping PreviewInfo to RoborazziOptions Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Create a mapper to convert PreviewInfo and custom annotations into RoborazziOptions for comparison. ```kotlin object RoborazziOptionsMapper { fun createFor(preview: ComposablePreview): RoborazziOptions = preview.getAnnotation()?.let { RoborazziOptions( compareOptions = CompareOptions(resultValidator = ThresholdValidator(it.comparisonThreshold)) ) } ?: RoborazziOptions() } ``` -------------------------------- ### Run Paparazzi Integration Tests with Gradle Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Execute Paparazzi integration tests for preview generation. This task is part of the automated verification process. ```bash ./gradlew :tests:paparazziPreviews ``` -------------------------------- ### PreviewProvider Interface Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/core/api.txt An interface for providing a list of composable previews. Implement this to define how previews are accessed. ```java public interface PreviewProvider { method public java.util.List> getPreviews(); } ``` -------------------------------- ### Run SourceSet Logic Tests with Gradle Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Execute the SourceSet logic tests for the project. This task is part of the automated verification process. ```bash ./gradlew :tests:testSourceSets ``` -------------------------------- ### Run API Logic Tests with Gradle Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Execute the API logic tests for the project. This task is part of the automated verification process. ```bash ./gradlew :tests:testApi ``` -------------------------------- ### Create Parameter Provider for Desktop Previews Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README_DEPRECATED.md Implement a TestParameterValuesProvider to scan for and provide ComposablePreview instances annotated with your custom desktop screenshot annotation. This uses JvmAnnotationScanner to find previews within specified package trees. ```kotlin class DesktopPreviewProvider : TestParameterValuesProvider() { @OptIn(RequiresShowStandardStreams::class) override fun provideValues(context: Context?): List> = JvmAnnotationScanner("my.package.path.DesktopScreenshot") .enableScanningLogs() .scanPackageTrees("previews") .getPreviews() } ``` -------------------------------- ### Create ActivityScenarioForComposableRule Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Creates an ActivityScenarioForComposableRule with specific configurations for UI mode, orientation, and locale based on preview information. ```kotlin object ActivityScenarioForComposablePreviewRule { fun createFor(preview: ComposablePreview): ActivityScenarioForComposableRule { val uiMode = when (preview.previewInfo.uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES) { true -> UiMode.NIGHT false -> UiMode.DAY } val orientation = when (DevicePreviewInfoParser.parse(preview.previewInfo.device)?.orientation == Orientation.LANDSCAPE) { true -> ComposableConfigOrientation.LANDSCAPE false -> ComposableConfigOrientation.PORTRAIT } val locale = preview.previewInfo.locale.removePrefix("b+").replace("+", "-").ifBlank { "en" } return ActivityScenarioForComposableRule( backgroundColor = Color.TRANSPARENT, config = ComposableConfigItem( uiMode = uiMode, fontSize = FontSizeScale.Value(preview.previewInfo.fontScale), orientation = orientation, locale = locale ) ) } } ``` -------------------------------- ### Annotate Desktop Composables for Testing Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README_DEPRECATED.md Annotate your desktop composable functions with the custom annotation (e.g., @DesktopScreenshot) to indicate they are candidates for screenshot testing. The @Preview annotation is optional but can be included. ```kotlin @DesktopScreenshot @Preview // It'd also work without this annotation @Composable fun MyDesktopComposable() { // Composable code here } ``` -------------------------------- ### Device Configuration Builder Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Builds a DeviceConfig object from parsed device information and preview settings. Used for configuring Paparazzi environments. ```kotlin return DeviceConfig( screenHeight = dimensions.screenHeightInPx, screenWidth = dimensions.screenWidthInPx, density = Density(parsedDevice.densityDpi), xdpi = parsedDevice.densityDpi, // not 100% precise ydpi = parsedDevice.densityDpi, // not 100% precise size = ScreenSize.valueOf(parsedDevice.screenSize.name), ratio = ScreenRatio.valueOf(parsedDevice.screenRatio.name), screenRound = ScreenRound.valueOf(parsedDevice.shape.name), orientation = ScreenOrientation.valueOf(parsedDevice.orientation.name), locale = preview.locale.ifBlank { "en" }, fontScale = preview.fontScale, nightMode = when (preview.uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES) { true -> NightMode.NIGHT false -> NightMode.NOTNIGHT } ) } } ``` -------------------------------- ### Include Build in settings.gradle.kts Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/paparazzi-plugin/README.md Include the local plugin build in your project's settings.gradle.kts file. ```gradle includeBuild("paparazzi-plugin") ``` -------------------------------- ### Apply Paparazzi Plugin in Module Gradle File Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/paparazzi-plugin/README.md Apply the Paparazzi plugin and the composable preview scanner plugin to the desired module's Gradle file. ```gradle plugins { id("app.cash.paparazzi") id("io.github.sergio-sastre.composable-preview-scanner.paparazzi-plugin") } ``` -------------------------------- ### Write Parameterized Desktop Screenshot Test Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README_DEPRECATED.md Write a parameterized test using TestParameterInjector that utilizes the DesktopPreviewProvider. This test will capture screenshots of the annotated composables using Roborazzi. ```kotlin fun screenshotNameFor(preview: ComposablePreview): String = "$DEFAULT_ROBORAZZI_OUTPUT_DIR_PATH/${preview.declaringClass}.${preview.methodName}.png" @RunWith(TestParameterInjector::class) class DesktopPreviewTest( @TestParameter(valuesProvider = DesktopPreviewProvider::class) val preview: ComposablePreview ) { @OptIn(ExperimentalTestApi::class) @Test fun test() { ROBORAZZI_DEBUG = true runDesktopComposeUiTest { setContent { preview() } onRoot().captureRoboImage( filePath = screenshotNameFor(preview), ) } } } ``` -------------------------------- ### Configure Scanner for Platform-Specific and Common Previews Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Configure the scanner to include preview packages from both platform-specific source sets (androidMain or desktopMain) and common source sets (commonMain). ```kotlin AndroidComposablePreviewScanner() .scanPackageTrees( include = listOf( "your.package.android_or_desktop", // platform-specific "your.package.common" // commonMain ) ) .getPreviews() ``` -------------------------------- ### Configure Composable Preview Paparazzi Plugin Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/paparazzi-plugin/README.md Configure the plugin's behavior, including package scanning, preview inclusion, and test class naming. ```gradle composablePreviewPaparazzi { enable = true packages = listOf("com.example.ui.previews") includePrivatePreviews = false testClassName = "MyGeneratedPaparazziTests" testPackageName = "com.example.generated.tests" } ``` -------------------------------- ### Run Roborazzi Integration Tests with Gradle Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Execute Roborazzi integration tests for preview generation. This task is part of the automated verification process. ```bash ./gradlew :tests:roborazziPreviews ``` -------------------------------- ### Add Source Set Dependencies for Testing Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Ensure that dependencies used in the target source set (e.g., screenshotTest) are also available in the test environment (e.g., 'test' or 'androidTest' configuration). ```kotlin screenshotTestImplementation("androidx.compose.ui:ui-tooling-preview:") testImplementation("androidx.compose.ui:ui-tooling-preview:") ``` -------------------------------- ### Calculate Screen Dimensions for Previews Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Calculate the screen dimensions in pixels for a preview based on device density and specified DP dimensions. Falls back to device's full dimensions if DP is not provided. ```kotlin class Dimensions( val screenWidthInPx: Int, val screenHeightInPx: Int ) object ScreenDimensions { fun dimensions( parsedDevice: Device, widthDp: Int, heightDp: Int ): Dimensions { val conversionFactor = parsedDevice.densityDpi / 160f val previewWidthInPx = ceil(widthDp * conversionFactor).toInt() val previewHeightInPx = ceil(heightDp * conversionFactor).toInt() return Dimensions( screenHeightInPx = when (heightDp > 0) { true -> previewHeightInPx false -> parsedDevice.dimensions.height.toInt() }, screenWidthInPx = when (widthDp > 0) { true -> previewWidthInPx false -> parsedDevice.dimensions.width.toInt() } ) } } ``` -------------------------------- ### Verify Paparazzi Integration Tests with Gradle Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Execute Paparazzi integration tests with verification enabled. This task is used to verify snapshot consistency. ```bash ./gradlew :tests:paparazziPreviews -Pverify=true ``` -------------------------------- ### Running Roborazzi Tests Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Execute Roborazzi tests using the Gradle command to record or verify screenshots. ```bash ./gradlew yourModule:recordRoborazziDebug ``` -------------------------------- ### Generate Composable Preview Paparazzi Tests Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/paparazzi-plugin/README.md Execute the Gradle task to only generate the Paparazzi test file without running the tests. ```bash ./gradlew your_module:generateComposablePreviewPaparazziTests ``` -------------------------------- ### Annotating Composable Previews Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Apply custom annotations to Composable Previews to specify configuration parameters for Roborazzi. ```kotlin @RoborazziConfig(comparisonThreshold = 0.1) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable fun MyComposable(){ // Composable code here } ``` -------------------------------- ### ComposablePreviewMapper Abstract Class Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/core/api.txt Abstract base class for mapping Composable preview information. ```APIDOC ## ComposablePreviewMapper ### Description Abstract base class for mapping Composable preview information. ### Constructor `ctor ComposablePreviewMapper(previewMethod: Method, previewInfo: T, annotationsInfo: AnnotationInfoList?)` ### Methods - `getAnnotationsInfo()`: Retrieves the annotation information. - `getPreviewInfo()`: Retrieves the preview information. - `getPreviewMethod()`: Retrieves the preview method. - `mapToComposablePreviews()`: Maps the current state to a sequence of ComposablePreview objects. ``` -------------------------------- ### Scan Previews in screenshotTest Source Set Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Use Classpath(SourceSet.SCREENSHOT_TEST) to target previews within the 'screenshotTest' source set. ```kotlin Classpath(SourceSet.SCREENSHOT_TEST) ``` -------------------------------- ### Configure and Scan Composable Previews Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md This snippet shows how to configure and use the AndroidComposablePreviewScanner or GlanceComposablePreviewScanner to find composable previews. It includes options for logging, targeting source sets, specifying packages, filtering by annotations, and filtering by preview properties. ```kotlin AndroidComposablePreviewScanner() // or GlanceComposablePreviewScanner() // Optional to log scanning info like scanning time or amount of previews found .enableScanningLogs() // Optional to scan previews in compiled classes of other source sets, like "screenshotTest" or "androidTest" // If omitted, it scans previews in 'main' at build time .setTargetSourceSet( Classpath(SourceSet.SCREENSHOT_TEST) // scan previews under "screenshotTest" ) // Required: define where to scan for Previews. // See 'Scanning Source Options (packages, files, inputStreams)' .scanPackageTrees( include = listOf("your.package", "your.package2"), exclude = listOf("your.package.subpackage1", "your.package2.subpackage1") ) // Optional to filter out scanned previews with any of the given annotations // Warning: this and its 'include' counterpart are mutually exclusive by API design .excludeIfAnnotatedWithAnyOf( ExcludeForScreenshot::class.java, ExcludeForScreenshot2::class.java ) // Optional to filter in only scanned previews with any of the given annotations // Warning: this and its 'exclude' counterpart are mutually exclusive by API design .includeIfAnnotatedWithAnyOf( IncludeForScreenshot::class.java, IncludeForScreenshot2::class.java ) // Optional to include configuration info of the screenshot testing library in use // See 'How to use -> Libraries' above for further info .includeAnnotationInfoForAllOf( ScreenshotConfig::class.java, ScreenshotConfig2::class.java ) // Optional to also provide private Previews .includePrivatePreviews() // Optional to filter by any previewInfo: heightDp, widthDp... .filterPreviews { previewInfo -> previewInfo.heightDP >= 800 } // --- .getPreviews() ``` -------------------------------- ### Add JitPack Dependencies for Android Previews Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Include this dependency for Android preview support when using JitPack. Ensure you replace with the appropriate library version. ```kotlin dependencies { // android previews (androidx.compose.ui.tooling.preview.Preview) // supported in jvm targets e.g. android & desktop testImplementation("com.github.sergio-sastre.ComposablePreviewScanner:android:") // glance previews (androidx.glance.preview.Preview) // supported since 0.7.0+ in android target testImplementation("com.github.sergio-sastre.ComposablePreviewScanner:glance:") } ``` -------------------------------- ### Add Necessary Dependencies Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/paparazzi-plugin/README.md Include the ComposablePreviewScanner Android library and JUnit for testing. ```gradle dependencies { testImplementation("io.github.sergio-sastre.ComposablePreviewScanner:android:0.9.0") testImplementation("junit:junit:4.13.2") } ``` -------------------------------- ### Annotate Previews with Custom Configuration Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Annotates Composable previews with the custom DropshotsConfig annotation to apply specific comparison thresholds. ```kotlin @DropshotsConfig(comparisonThreshold = 0.15) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable fun MyComposable() { // Composable code here } ``` -------------------------------- ### GlanceDeviceConfigDimensions Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/glance/api.txt Helper class for calculating width and height based on device configuration. ```APIDOC ## GlanceDeviceConfigDimensions ### Description Provides methods to calculate the width and height of a preview based on original pixel values and device configuration, such as density. ### Class `sergio.sastre.composable.preview.scanner.glance.configuration.GlanceDeviceConfigDimensions` ### Constructor - `ctor public GlanceDeviceConfigDimensions(float densityDpi, int previewWidthDp, int previewHeightDp)`: Creates a new instance with density and preview dimensions in dp. ### Methods - `public int height(int originalDeviceConfigHeightPx)`: Calculates the height in dp given the original height in pixels. - `public int width(int originalDeviceConfigWidthPx)`: Calculates the width in dp given the original width in pixels. ``` -------------------------------- ### Paparazzi Preview Rule Creation Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Factory method to create a Paparazzi instance configured for a specific ComposablePreview. It determines API level, rendering mode, and snapshot handler based on preview info and system properties. ```kotlin const val UNDEFINED_API_LEVEL = -1 const val MAX_API_LEVEL = 36 fun createFor(preview: ComposablePreview): Paparazzi { val previewInfo = preview.previewInfo val previewApiLevel = when(previewInfo.apiLevel == UNDEFINED_API_LEVEL) { true -> MAX_API_LEVEL false -> previewInfo.apiLevel } // other library configurations... val tolerance = preview.getAnnotation()?.maxPercentDifference ?: 0.0 return Paparazzi( environment = detectEnvironment().copy(compileSdkVersion = previewApiLevel), deviceConfig = DeviceConfigBuilder.build(previewInfo), supportsRtl = true, showSystemUi = previewInfo.showSystemUi, renderingMode = when { previewInfo.showSystemUi -> SessionParams.RenderingMode.NORMAL previewInfo.widthDp > 0 && previewInfo.heightDp > 0 -> SessionParams.RenderingMode.FULL_EXPAND else -> SessionParams.RenderingMode.SHRINK }, snapshotHandler = when(System.getProperty("paparazzi.test.verify")?.toBoolean() == true) { true -> PreviewSnapshotVerifier(tolerance) false -> PreviewHtmlReportWriter() }, maxPercentDifference = tolerance ) } } ``` -------------------------------- ### Add Maven Central Dependencies for Android Previews Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Include this dependency for Android preview support when using Maven Central. Ensure you replace with the appropriate library version. ```kotlin dependencies { // android previews (androidx.compose.ui.tooling.preview.Preview) // supported in jvm targets e.g. android & desktop testImplementation("io.github.sergio-sastre.ComposablePreviewScanner:android:") // glance previews (androidx.glance.preview.Preview) // supported since 0.7.0+ in android target testImplementation("io.github.sergio-sastre.ComposablePreviewScanner:glance:") } ``` -------------------------------- ### SystemUiSize Composable Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md A composable that wraps content within a Box, forcing it to occupy a specified size and simulating the screen space when showSystemUi is true. The background is set to white. ```kotlin @Composable fun SystemUiSize( widthInDp: Int, heightInDp: Int, content: @Composable () -> Unit ) { Box(Modifier .size( width = widthInDp.dp, height = heightInDp.dp ) .background(Color.White) ) { content() } } ``` -------------------------------- ### PreviewProvider.getPreviews Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/core/api.txt Retrieves a list of composable previews. This method is part of the PreviewProvider interface. ```APIDOC ## PreviewProvider.getPreviews ### Description Fetches a list of all composable previews available. ### Method N/A (Interface method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Response #### Success Response (200) - **List>** - A list of ComposablePreview objects. ``` -------------------------------- ### DevicePreviewInfoParser Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/android/api.txt Parses device-specific information from a string representation, enabling the interpretation of device configurations. ```APIDOC ## Class: DevicePreviewInfoParser ### Description Parses string representations of device configurations into structured `Device` objects. ### Methods - `public Device? parse(String device)`: Parses the given device string and returns a `Device` object or null if parsing fails. ### Properties - `INSTANCE` (DevicePreviewInfoParser): The singleton instance of the `DevicePreviewInfoParser`. ``` -------------------------------- ### ProvideComposablePreview Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/core/api.txt A class used to provide Composable previews, allowing for custom mapping and preview indexing. ```APIDOC ## ProvideComposablePreview ### Description A class used to provide Composable previews, allowing for custom mapping and preview indexing. ### Constructor `ctor public ProvideComposablePreview()` ### Method `invoke(composablePreviewMapper: ComposablePreviewMapper, previewIndex: Integer? = null, previewParameterDisplayName: String? = null, parameter: Any? = null)`: Creates and returns a ComposablePreview instance. ### Parameters for invoke method - `composablePreviewMapper` (ComposablePreviewMapper): The mapper to convert preview information. - `previewIndex` (Integer?, Optional): The index for the preview. - `previewParameterDisplayName` (String?, Optional): A display name for the preview parameter. - `parameter` (Any?, Optional): Additional parameter for the preview. ``` -------------------------------- ### ClasspathPreviewsFinder Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/core/api.txt A generic finder for discovering composable previews within a classpath, configurable with specific annotations and mappers. ```APIDOC ## ClasspathPreviewsFinder ### Description A generic finder for discovering composable previews within a classpath, configurable with specific annotations and mappers. ### Constructor - `ClasspathPreviewsFinder(annotationToScanClassName: String, previewInfoMapper: ComposablePreviewInfoMapper, previewMapperCreator: ComposablePreviewMapperCreator)` ### Methods - `applyCrossModuleCustomPreviewPackageTrees(packageTrees: List): ClasspathPreviewsFinder` - `applyCustomPreviewsScanResult(customPreviewsScanResult: ScanResult): ClasspathPreviewsFinder` - `applyOverridenClasspath(classPath: Classpath): ClasspathPreviewsFinder` - `findPreviewsFor(classInfo: ClassInfo, scanResultFilterState: ScanResultFilterState): List>` ### Properties - `annotationToScanClassName` (String) ``` -------------------------------- ### RobolectricDeviceQualifierBuilder Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/glance/api.txt Builds device qualifiers for Robolectric tests based on Glance preview info. ```APIDOC ## RobolectricDeviceQualifierBuilder ### Description Builds a string qualifier for Robolectric tests, which can be used to specify device configurations based on `GlancePreviewInfo`. ### Class `sergio.sastre.composable.preview.scanner.glance.configuration.RobolectricDeviceQualifierBuilder` ### Methods - `public String? build(sergio.sastre.composable.preview.scanner.glance.GlancePreviewInfo previewInfo)`: Builds a device qualifier string for Robolectric based on the provided preview information. ### Fields - `public static final RobolectricDeviceQualifierBuilder INSTANCE`: The singleton instance of the builder. ``` -------------------------------- ### Verify Roborazzi Integration Tests with Gradle Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Execute Roborazzi integration tests with verification enabled. This task is used to verify snapshot consistency. ```bash ./gradlew :tests:roborazziPreviews -Pverify=true ``` -------------------------------- ### Parameterized Roborazzi Test Class Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Set up a parameterized test class to run Roborazzi tests for multiple composable previews with specific configurations. ```kotlin @RunWith(ParameterizedRobolectricTestRunner::class) class PreviewParameterizedTests( private val preview: ComposablePreview, ) { companion object { // Optimization: This avoids scanning for every test private val cachedPreviews: List> by lazy { AndroidComposablePreviewScanner() .scanPackageTrees("your.package", "your.package2") .filterPreviews { previewParams -> previewParams.apiLevel == 30 } .includeAnnotationInfoForAllOf(RoborazziConfig::class.java) .getPreviews() } @JvmStatic @ParameterizedRobolectricTestRunner.Parameters fun values(): List> = cachedPreviews } // Recommended for more meaningful screenshot file names. See #Advanced Usage fun screenshotNameFor(preview: ComposablePreview): String = "$DEFAULT_ROBORAZZI_OUTPUT_DIR_PATH/${AndroidPreviewScreenshotIdBuilder(preview).build()}.png" @GraphicsMode(GraphicsMode.Mode.NATIVE) @Config(sdk = [30]) // same as the previews we've filtered @Test fun snapshot() { captureRoboImage( filePath = screenshotNameFor(preview), roborazziOptions = RoborazziOptionsMapper.createFor(preview), roborazziComposeOptions = RoborazziComposeOptionsMapper.createFor(preview) ) { preview() } } } ``` -------------------------------- ### ComposablePreview Interface Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/core/api.txt Represents a Composable preview, providing access to its metadata such as declaring class, method name, and preview index. ```APIDOC ## ComposablePreview Interface ### Description Represents a Composable preview, providing access to its metadata such as declaring class, method name, and preview index. ### Methods - `getDeclaringClass()`: Returns the name of the class declaring the Composable. - `getMethodName()`: Returns the name of the method that is a Composable preview. - `getMethodParametersType()`: Returns the type information for the parameters of the Composable method. - `getOtherAnnotationsInfo()`: Retrieves information about other annotations present on the Composable. - `getPreviewIndex()`: Gets the index of the preview if multiple previews exist in a method. - `getPreviewIndexDisplayName()`: Gets a display-friendly name for the preview index. - `getPreviewInfo()`: Retrieves the specific preview information. - `invoke()`: Invokes the Composable preview. ### Properties - `declaringClass` (String): The name of the class declaring the Composable. - `methodName` (String): The name of the method that is a Composable preview. - `methodParametersType` (String): The type information for the parameters of the Composable method. - `otherAnnotationsInfo` (AnnotationInfoList?): Information about other annotations present on the Composable. - `previewIndex` (Integer?): The index of the preview if multiple previews exist in a method. - `previewIndexDisplayName` (String?): A display-friendly name for the preview index. - `previewInfo` (T): The specific preview information. ``` -------------------------------- ### ComposablePreviewInfoMapper Interface Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/core/api.txt Interface for mapping parameter values to Composable preview information. ```APIDOC ## ComposablePreviewInfoMapper ### Description Interface for mapping parameter values to Composable preview information. ### Method `mapToComposablePreviewInfo(parameters: AnnotationParameterValueList)`: Maps the provided annotation parameter values to the specific preview info type T. ``` -------------------------------- ### Annotate Previews with Custom Paparazzi Configuration Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Annotate Composable Previews with the custom PaparazziConfig annotation to apply specific settings, such as night mode and maxPercentDifference. ```kotlin @PaparazziConfig(maxPercentDifference = 0.1) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable fun MyComposable(){ // Composable code here } ``` -------------------------------- ### Parse Preview Device String Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Use DevicePreviewInfoParser.parse(device: String) to extract device information for Roborazzi and Paparazzi screenshot tests. This supports various device string formats, including standard and custom configurations. ```kotlin // The over 80 devices supported either by id and/or name, for instance: @Preview(device = "id:pixel_10_pro") @Preview(device = "name:Pixel 10 Pro") @Preview(device = "spec:parent=pixel_10_pro, orientation=landscape, navigation=buttons") // And custom devices @Preview(device = "spec:width = 411dp, height = 891dp, orientation = landscape, dpi = 420, isRound = false, chinSize = 0dp, cutout = corner") @Preview(device = "spec:id=reference_desktop,shape=Normal,width=1920,height=1080,unit=px,dpi=160") // in pixels @Preview(device = "spec:id=reference_desktop,shape=Normal,width=1920,height=1080,unit=dp,dpi=160") // in dp ``` -------------------------------- ### ClassGraphSourceScanner Implementation Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/core/api.txt A concrete implementation of SourceScanner using ClassGraph. It provides methods for scanning packages and files, similar to the abstract class. ```java public final class ClassGraphSourceScanner implements sergio.sastre.composable.preview.scanner.core.scanner.config.SourceScanner { ctor public ClassGraphSourceScanner(io.github.classgraph.ClassGraph classGraph, sergio.sastre.composable.preview.scanner.core.scanner.config.classpath.previewfinder.ClasspathPreviewsFinder findComposableWithPreviewsInClass, sergio.sastre.composable.preview.scanner.core.scanner.config.classpath.Classpath? classpath, boolean isLoggingEnabled); method @sergio.sastre.composable.preview.scanner.core.scanresult.RequiresLargeHeap public sergio.sastre.composable.preview.scanner.core.scanresult.filter.ScanResultFilter scanAllPackages(); method public sergio.sastre.composable.preview.scanner.core.scanresult.filter.ScanResultFilter scanFile(File jsonFile); method public sergio.sastre.composable.preview.scanner.core.scanresult.filter.ScanResultFilter scanFile(InputStream targetInputStream, InputStream customPreviewsInfoInputStream); method public sergio.sastre.composable.preview.scanner.core.scanresult.filter.ScanResultFilter scanPackageTrees(java.lang.String... packageTrees); method public sergio.sastre.composable.preview.scanner.core.scanresult.filter.ScanResultFilter scanPackageTrees(java.util.List include, java.util.List exclude); } ``` -------------------------------- ### GlanceSnapshotConfigurator Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/glance/api.txt Configures snapshots for Glance composables. ```APIDOC ## GlanceSnapshotConfigurator ### Description Configures the environment for taking snapshots of Glance composables. It allows setting size and state for the composable preview. ### Class `sergio.sastre.composable.preview.scanner.glance.configuration.GlanceSnapshotConfigurator` ### Constructor - `ctor public GlanceSnapshotConfigurator(android.content.Context context)`: Creates a new configurator with the provided Android context. ### Methods - `public android.view.View composableToView(kotlin.jvm.functions.Function0 composable)`: Converts a composable lambda into an Android View. - `@InaccessibleFromKotlin public android.content.Context getContext()`: Gets the Android context (inaccessible from Kotlin). - `public GlanceSnapshotConfigurator setSizeDp(int widthDp, int heightDp)`: Sets the desired width and height for the preview in dp. - `public GlanceSnapshotConfigurator setState(T state)`: Sets the state for the composable preview. ### Properties - `public android.content.Context context`: The Android context. ``` -------------------------------- ### Add ComposablePreviewScanner JVM Dependency Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README_DEPRECATED.md Add the ComposablePreviewScanner JVM dependency to your project for desktop previews. Specify the version according to your needs. ```kotlin // Maven Central testImplementation("io.github.sergio-sastre.ComposablePreviewScanner:jvm:") // JitPack testImplementation("com.github.sergio-sastre.ComposablePreviewScanner:jvm:") ``` -------------------------------- ### Classpath Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/core/api.txt Represents a classpath entry for scanning. It can be defined by a package path and an optional root directory, or by using legacy or standard SourceSet configurations. ```APIDOC ## Classpath ### Description Represents a classpath entry for scanning. It can be defined by a package path and an optional root directory, or by using legacy or standard SourceSet configurations. ### Constructors - `Classpath(packagePath: String, rootDir: String?)` - `Classpath(legacySourceSetClasspath: LegacySourceSetClasspath, variantName: String?)` - `Classpath(sourceSet: SourceSet, variantName: String?)` ### Properties - `packagePath` (String) - `rootDir` (String) ### Methods - `component1(): String` - `component2(): String` - `copy(packagePath: String?, rootDir: String?): Classpath` - `equals(other: Any?): Boolean` - `getPackagePath(): String` - `getRootDir(): String` - `hashCode(): Int` - `toString(): String` ``` -------------------------------- ### Custom SnapshotHandler for Stable File Naming Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Implement custom SnapshotHandler classes to control screenshot file naming, ensuring stability by using a fixed prefix instead of test indices. ```kotlin // Define the prefix = __ private val paparazziTestName = TestName(packageName = "Paparazzi", className = "Preview", methodName = "Test") private class PreviewSnapshotVerifier( maxPercentDifference: Double ): SnapshotHandler { private val snapshotHandler = SnapshotVerifier( maxPercentDifference = maxPercentDifference ) override fun newFrameHandler( snapshot: Snapshot, frameCount: Int, fps: Int ): SnapshotHandler.FrameHandler { val newSnapshot = Snapshot( name = snapshot.name, testName = paparazziTestName, timestamp = snapshot.timestamp, tags = snapshot.tags, file = snapshot.file, ) return snapshotHandler.newFrameHandler( snapshot = newSnapshot, frameCount = frameCount, fps = fps ) } override fun close() { snapshotHandler.close() } } private class PreviewHtmlReportWriter: SnapshotHandler { private val snapshotHandler = HtmlReportWriter() override fun newFrameHandler( snapshot: Snapshot, frameCount: Int, fps: Int ): SnapshotHandler.FrameHandler { val newSnapshot = Snapshot( name = snapshot.name, testName = paparazziTestName, timestamp = snapshot.timestamp, tags = snapshot.tags, file = snapshot.file, ) return snapshotHandler.newFrameHandler( snapshot = newSnapshot, frameCount = frameCount, fps = fps ) } override fun close() { snapshotHandler.close() } } ``` -------------------------------- ### Scan Previews in androidTest Source Set Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Use Classpath(SourceSet.ANDROID_TEST) to target previews within the 'androidTest' source set. ```kotlin Classpath(SourceSet.ANDROID_TEST) ``` -------------------------------- ### Define Custom Paparazzi Configuration Annotation Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Define a custom annotation to specify Paparazzi configuration values like maxPercentDifference for specific Previews. ```kotlin annotation class PaparazziConfig(val maxPercentDifference: Double) ``` -------------------------------- ### Composable Preview Instrumentation Test Class Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md This class defines parameterized instrumentation tests for composable previews. It uses lazy initialization to cache scanned previews and integrates with Dropshots for screenshot assertions. Ensure the 'scan_result.json' file is available in the assets. ```kotlin @RunWith(ParameterizedTestRunner::class) class PreviewParameterizedTests( private val preview: ComposablePreview, ) { companion object { private val cachedPreviews: List> by lazy { AndroidComposablePreviewScanner() .scanFile(getInstrumentation().context.assets.open("scan_result.json")) .includeAnnotationInfoForAllOf(DropshotsConfig::class.java) .getPreviews() } @JvmStatic @ParameterizedTestRunner.Parameters fun values(): List> = cachedPreviews } @get:Rule val dropshots: Dropshots = DropshotsPreviewRule.createFor(preview) @get:Rule val activityScenarioForComposableRule: ActivityScenarioForComposableRule = ActivityScenarioForComposablePreviewRule.createFor(preview) @Test fun snapshot() { activityScenarioForComposableRule.onActivity { it.setContent { preview() } } dropshots.assertSnapshot( view = activityScenarioForComposableRule.activity.waitForComposeView() ) } } ``` -------------------------------- ### Increase JVM RAM for Slow Screenshot Tests Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README.md Allocate more RAM to unit tests to improve performance during large scans. Configure your Gradle file to set the maximum heap size. ```kotlin testOptions.unitTests { all { test -> // allocate 4GB RAM test.jvmArgs("-Xmx4g") } } ``` -------------------------------- ### Define Custom Annotation for Desktop Screenshots Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/README_DEPRECATED.md Define a custom annotation for marking composables that should be included in desktop screenshot tests. Ensure it does not use AnnotationRetention.SOURCE. ```kotlin package my.package.path @Target(AnnotationTarget.FUNCTION) annotation class DesktopScreenshot ``` -------------------------------- ### ComposablePreviewMapperCreator Interface Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/core/api.txt Interface for creating ComposablePreviewMapper instances. ```APIDOC ## ComposablePreviewMapperCreator ### Description Interface for creating ComposablePreviewMapper instances. ### Method `createComposablePreviewMapper(previewMethod: Method, previewInfo: T, annotationsInfo: AnnotationInfoList?)`: Creates and returns a ComposablePreviewMapper instance. ``` -------------------------------- ### ScanResultDumper Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/core/api.txt The ScanResultDumper class provides methods to configure and initiate the scanning process, including specifying packages to scan and setting target source sets. It also allows for enabling scanning logs. ```APIDOC ## ScanResultDumper ### Description Provides methods to configure and initiate the scanning process, including specifying packages to scan and setting target source sets. It also allows for enabling scanning logs. ### Methods - **enableScanningLogs()**: Enables the logging of scanning information. - **scanAllPackages()**: Initiates a scan across all packages. - **scanPackageTrees(packages: String...)**: Initiates a scan for specified package trees. - **setTargetSourceSet(sourceSetClasspath: Classpath)**: Sets the target source set for the scan. ``` -------------------------------- ### SourceScanner Interface Source: https://github.com/sergio-sastre/composablepreviewscanner/blob/master/core/api.txt The interface defining the contract for scanning composable previews. It specifies methods for scanning all packages, specific files, and package trees. ```java public interface SourceScanner { method @sergio.sastre.composable.preview.scanner.core.scanresult.RequiresLargeHeap public sergio.sastre.composable.preview.scanner.core.scanresult.filter.ScanResultFilter scanAllPackages(); method public sergio.sastre.composable.preview.scanner.core.scanresult.filter.ScanResultFilter scanFile(File jsonFile); method public sergio.sastre.composable.preview.scanner.core.scanresult.filter.ScanResultFilter scanFile(InputStream targetInputStream, InputStream customPreviewsInfoInputStream); method public sergio.sastre.composable.preview.scanner.core.scanresult.filter.ScanResultFilter scanPackageTrees(java.lang.String... packageTrees); method public sergio.sastre.composable.preview.scanner.core.scanresult.filter.ScanResultFilter scanPackageTrees(java.util.List include, java.util.List exclude); } ```