diff --git a/showkase-annotation/src/main/java/com/airbnb/android/showkase/annotation/ShowkaseCodegenMetadata.kt b/showkase-annotation/src/main/java/com/airbnb/android/showkase/annotation/ShowkaseCodegenMetadata.kt index 29fc20ed..5983572d 100644 --- a/showkase-annotation/src/main/java/com/airbnb/android/showkase/annotation/ShowkaseCodegenMetadata.kt +++ b/showkase-annotation/src/main/java/com/airbnb/android/showkase/annotation/ShowkaseCodegenMetadata.kt @@ -41,5 +41,6 @@ annotation class ShowkaseCodegenMetadata( val isDefaultStyle: Boolean = false, val generatedPropertyName: String = "", val tags: Array = [], - val extraMetadata: Array = [] + val extraMetadata: Array = [], + val showkaseGenerateScreenshot: Boolean = false, ) diff --git a/showkase-annotation/src/main/java/com/airbnb/android/showkase/annotation/ShowkaseComposable.kt b/showkase-annotation/src/main/java/com/airbnb/android/showkase/annotation/ShowkaseComposable.kt index 9949248b..0257243b 100644 --- a/showkase-annotation/src/main/java/com/airbnb/android/showkase/annotation/ShowkaseComposable.kt +++ b/showkase-annotation/src/main/java/com/airbnb/android/showkase/annotation/ShowkaseComposable.kt @@ -58,6 +58,8 @@ package com.airbnb.android.showkase.annotation * but are still available in the generated `ShowkaseBrowserComponent` object. This may be useful when * extra data is needed for attributing components during other processes (e.g. static analysis, * displaying attributions in a custom component browser). + * @param generateScreenshot Used for screenshot testing, this will allow Paparazzi to create the + * screenshot */ @MustBeDocumented @Retention(AnnotationRetention.SOURCE) @@ -74,4 +76,5 @@ annotation class ShowkaseComposable( val defaultStyle: Boolean = false, val tags: Array = [], val extraMetadata: Array = [], + val generateScreenshot: Boolean = false, ) diff --git a/showkase-processor/src/main/java/com/airbnb/android/showkase/processor/models/ShowkaseMetadata.kt b/showkase-processor/src/main/java/com/airbnb/android/showkase/processor/models/ShowkaseMetadata.kt index 99d56dd4..eff567a4 100644 --- a/showkase-processor/src/main/java/com/airbnb/android/showkase/processor/models/ShowkaseMetadata.kt +++ b/showkase-processor/src/main/java/com/airbnb/android/showkase/processor/models/ShowkaseMetadata.kt @@ -63,7 +63,8 @@ internal sealed class ShowkaseMetadata { val showkaseStyleName: String? = null, val isDefaultStyle: Boolean = false, val tags: List = emptyList(), - val extraMetadata: List = emptyList() + val extraMetadata: List = emptyList(), + val showkaseGenerateScreenshot: Boolean = false ) : ShowkaseMetadata() data class Color( @@ -135,8 +136,8 @@ internal fun XAnnotationBox.toModel(element: XElement): previewParameterName = props.previewParameterName, isDefaultStyle = props.isDefaultStyle, tags = props.tags.toList(), - extraMetadata = props.tags.toList() - + extraMetadata = props.tags.toList(), + showkaseGenerateScreenshot = props.showkaseGenerateScreenshot ) } ShowkaseMetadataType.COLOR -> { @@ -192,8 +193,8 @@ internal fun getShowkaseMetadata( val previewParameterMetadata = element.getPreviewParameterMetadata() return showkaseAnnotations.mapNotNull { annotation -> - // If this component was configured to be skipped, return early - if (annotation.value.skip) return@mapNotNull null + // If this component was configured to be both skipped and for not recording the screenshot, return early + if (annotation.value.skip && !annotation.value.generateScreenshot) return@mapNotNull null val showkaseName = getShowkaseName(annotation.value.name, element.name) val showkaseGroup = getShowkaseGroup( @@ -224,7 +225,8 @@ internal fun getShowkaseMetadata( isDefaultStyle = isDefaultStyle, componentIndex = showkaseAnnotations.indexOf(annotation), tags = tags, - extraMetadata = extraMetadata + extraMetadata = extraMetadata, + showkaseGenerateScreenshot = annotation.value.generateScreenshot ) } } diff --git a/showkase-processor/src/main/java/com/airbnb/android/showkase/processor/writer/WriterUtils.kt b/showkase-processor/src/main/java/com/airbnb/android/showkase/processor/writer/WriterUtils.kt index efe3eda3..3fb8a37b 100644 --- a/showkase-processor/src/main/java/com/airbnb/android/showkase/processor/writer/WriterUtils.kt +++ b/showkase-processor/src/main/java/com/airbnb/android/showkase/processor/writer/WriterUtils.kt @@ -124,13 +124,15 @@ internal fun CodeBlock.Builder.addShowkaseBrowserComponent( ) doubleIndent() add( - "group = %S,\ncomponentName = %S,\ncomponentKDoc = %S,\ncomponentKey = %P,", + "group = %S,\ncomponentName = %S,\nfunctionName = %S,\ncomponentKDoc = %S,\ncomponentKey = %P,", showkaseMetadata.showkaseGroup, showkaseMetadata.showkaseName, + showkaseMetadata.elementName, showkaseMetadata.showkaseKDoc, componentKey, ) add("\nisDefaultStyle = ${showkaseMetadata.isDefaultStyle},") + add("\ngenerateScreenshot = ${showkaseMetadata.showkaseGenerateScreenshot},") showkaseMetadata.apply { showkaseWidthDp?.let { add("\nwidthDp = %L,", it) } showkaseHeightDp?.let { add("\nheightDp = %L,", it) } diff --git a/showkase-screenshot-testing-paparazzi-sample/src/main/java/com/airbnb/android/showkase/screenshot/testing/paparazzi/sample/BasicChip.kt b/showkase-screenshot-testing-paparazzi-sample/src/main/java/com/airbnb/android/showkase/screenshot/testing/paparazzi/sample/BasicChip.kt index 2ddc43ac..3d47dbce 100644 --- a/showkase-screenshot-testing-paparazzi-sample/src/main/java/com/airbnb/android/showkase/screenshot/testing/paparazzi/sample/BasicChip.kt +++ b/showkase-screenshot-testing-paparazzi-sample/src/main/java/com/airbnb/android/showkase/screenshot/testing/paparazzi/sample/BasicChip.kt @@ -30,13 +30,26 @@ fun BasicChip( } } -@ShowkaseComposable(name = "Basic Chip", group = "Chips", defaultStyle = true) +// This preview will be skipped from component browser +// but will generate the screenshot +@ShowkaseComposable( + name = "Basic Chip", + group = "Chips", + defaultStyle = true, + generateScreenshot = true, + skip = true +) @Composable fun BasicChipPreview() { BasicChip(text = "Chip Component") } -@ShowkaseComposable(name = "Basic Chip", group = "Chips", styleName = "Yellow Background") +@ShowkaseComposable( + name = "Basic Chip", + group = "Chips", + styleName = "Yellow Background", + generateScreenshot = true +) @Composable fun BasicChipYellowPreview() { BasicChip( diff --git a/showkase-screenshot-testing-paparazzi-sample/src/test/java/com/airbnb/android/showkase/screenshot/testing/paparazzi/sample/MyPaparazziShowkaseScreenshotTest.kt b/showkase-screenshot-testing-paparazzi-sample/src/test/java/com/airbnb/android/showkase/screenshot/testing/paparazzi/sample/MyPaparazziShowkaseScreenshotTest.kt index 14f8b2a2..0cd1e373 100644 --- a/showkase-screenshot-testing-paparazzi-sample/src/test/java/com/airbnb/android/showkase/screenshot/testing/paparazzi/sample/MyPaparazziShowkaseScreenshotTest.kt +++ b/showkase-screenshot-testing-paparazzi-sample/src/test/java/com/airbnb/android/showkase/screenshot/testing/paparazzi/sample/MyPaparazziShowkaseScreenshotTest.kt @@ -3,7 +3,7 @@ package com.airbnb.android.showkase.screenshot.testing.paparazzi.sample import com.airbnb.android.showkase.annotation.ShowkaseScreenshot import com.airbnb.android.showkase.screenshot.testing.paparazzi.PaparazziShowkaseScreenshotTest -@ShowkaseScreenshot(rootShowkaseClass = PaparazziSampleRootModule::class) +//@ShowkaseScreenshot(rootShowkaseClass = PaparazziSampleRootModule::class) abstract class MyPaparazziShowkaseScreenshotTest: PaparazziShowkaseScreenshotTest { companion object: PaparazziShowkaseScreenshotTest.CompanionObject } diff --git a/showkase-screenshot-testing-paparazzi-sample/src/test/java/com/airbnb/android/showkase/screenshot/testing/paparazzi/sample/MyPaparazziShowkaseScreenshotTestFiltered.kt b/showkase-screenshot-testing-paparazzi-sample/src/test/java/com/airbnb/android/showkase/screenshot/testing/paparazzi/sample/MyPaparazziShowkaseScreenshotTestFiltered.kt new file mode 100644 index 00000000..7680d02e --- /dev/null +++ b/showkase-screenshot-testing-paparazzi-sample/src/test/java/com/airbnb/android/showkase/screenshot/testing/paparazzi/sample/MyPaparazziShowkaseScreenshotTestFiltered.kt @@ -0,0 +1,79 @@ +package com.airbnb.android.showkase.screenshot.testing.paparazzi.sample + +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.unit.Density +import app.cash.paparazzi.DeviceConfig +import app.cash.paparazzi.Paparazzi +import com.airbnb.android.showkase.models.Showkase +import com.airbnb.android.showkase.models.ShowkaseBrowserComponent +import com.android.ide.common.rendering.api.SessionParams +import com.google.testing.junit.testparameterinjector.TestParameter +import com.google.testing.junit.testparameterinjector.TestParameterInjector +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +class ComponentPreview( + private val showkaseBrowserComponent: ShowkaseBrowserComponent +) { + val content: @Composable () -> Unit = showkaseBrowserComponent.component + override fun toString(): String = + showkaseBrowserComponent.functionName + "-" + showkaseBrowserComponent.group + "_" + showkaseBrowserComponent.componentName +} + +@RunWith(TestParameterInjector::class) +class ComposePaparazziTest { + object PreviewProvider : TestParameter.TestParameterValuesProvider { + override fun provideValues(): List { + return try { + val metadata = Showkase.getMetadata() + val componentList = metadata.componentList + componentList + .filterGenerateScreenshotComponents() + .map(::ComponentPreview) + } catch (error: Throwable) { + emptyList() + } + } + + private fun List.filterGenerateScreenshotComponents(): List { + return filter { + return@filter (it.generateScreenshot) + } + } + } + + @get:Rule + val paparazzi = Paparazzi( + maxPercentDifference = 0.0, + showSystemUi = false, + deviceConfig = DeviceConfig.PIXEL_5.copy( + softButtons = false, + locale = "en"), + renderingMode = SessionParams.RenderingMode.SHRINK + ) + + @Test + fun preview_tests( + @TestParameter(valuesProvider = PreviewProvider::class) componentPreview: ComponentPreview, + @TestParameter(value = ["1.0"]) fontScale: Float + ) { + paparazzi.snapshot() { + CompositionLocalProvider( + LocalInspectionMode provides true, + LocalDensity provides Density( + density = LocalDensity.current.density, + fontScale = fontScale + ) + ) { + Box { + componentPreview.content() + } + } + } + } +} \ No newline at end of file diff --git a/showkase/src/main/java/com/airbnb/android/showkase/models/ShowkaseBrowserComponent.kt b/showkase/src/main/java/com/airbnb/android/showkase/models/ShowkaseBrowserComponent.kt index 9dff093e..d444c5b9 100644 --- a/showkase/src/main/java/com/airbnb/android/showkase/models/ShowkaseBrowserComponent.kt +++ b/showkase/src/main/java/com/airbnb/android/showkase/models/ShowkaseBrowserComponent.kt @@ -15,5 +15,7 @@ data class ShowkaseBrowserComponent( val widthDp: Int? = null, val heightDp: Int? = null, val tags: List = emptyList(), - val extraMetadata: List = emptyList() + val extraMetadata: List = emptyList(), + val functionName: String, + val generateScreenshot: Boolean, )