Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support includePrivatePreviews of ComposablePreviewScanner #445

Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,7 @@ If you are having trouble debugging your test, try Dump mode as follows.
# Experimental Compose Preview Support

Roborazzi provides support for generating screenshot tests and easy setup for Jetpack Compose Preview.
This support uses [ComposePreviewScanner](https://github.com/sergio-sastre/ComposablePreviewScanner) to scan the Composable Previews in your project.
This support uses [ComposablePreviewScanner](https://github.com/sergio-sastre/ComposablePreviewScanner) to scan the Composable Previews in your project.

## Generate Compose Preview screenshot tests

Expand Down Expand Up @@ -994,13 +994,13 @@ roborazzi {

## Manually adding Compose Preview screenshot tests

Roborazzi provides a helper function for ComposePreviewScanner.
Roborazzi provides a helper function for ComposablePreviewScanner.
You can add the following dependency to your project to use the helper function:

`testImplementation("io.github.takahirom.roborazzi:roborazzi-compose-preview-scanner-support:[version]")`

Then you can use the `ComposablePreview<AndroidPreviewInfo>.captureRoboImage()` function to capture the Composable Preview using the settings in Preview annotations.
To obtain the `ComposablePreview` object, please refer to [ComposePreviewScanner](https://github.com/sergio-sastre/ComposablePreviewScanner).
To obtain the `ComposablePreview` object, please refer to [ComposablePreviewScanner](https://github.com/sergio-sastre/ComposablePreviewScanner).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I named it like that and I had my own doubts.
Google is also inconsistent on whether to call them "Compose Previews", like in "Compose Preview Screenshot Testing tool" or "Composable Previews" like here

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I know it should not be Compose Composable Preview. 😊

"A good name is long enough to fully communicate what the item is or does, without being so long that it becomes hard to read." https://google.github.io/eng-practices/review/reviewer/looking-for.html

I personally think we can use ComposePreview in an Android context, and also I think we can use ComposablePreview in a Jetpack Compose context. This is because Composable is an annotation name, so it's a minor distinction, while Compose is the framework name.


```kotlin
fun ComposablePreview<AndroidPreviewInfo>.captureRoboImage(
Expand Down
6 changes: 3 additions & 3 deletions docs/topics/preview_support.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Experimental Compose Preview Support

Roborazzi provides support for generating screenshot tests and easy setup for Jetpack Compose Preview.
This support uses [ComposePreviewScanner](https://github.com/sergio-sastre/ComposablePreviewScanner) to scan the Composable Previews in your project.
This support uses [ComposablePreviewScanner](https://github.com/sergio-sastre/ComposablePreviewScanner) to scan the Composable Previews in your project.

## Generate Compose Preview screenshot tests

Expand Down Expand Up @@ -44,13 +44,13 @@ roborazzi {

## Manually adding Compose Preview screenshot tests

Roborazzi provides a helper function for ComposePreviewScanner.
Roborazzi provides a helper function for ComposablePreviewScanner.
You can add the following dependency to your project to use the helper function:

`testImplementation("io.github.takahirom.roborazzi:roborazzi-compose-preview-scanner-support:[version]")`

Then you can use the `ComposablePreview<AndroidPreviewInfo>.captureRoboImage()` function to capture the Composable Preview using the settings in Preview annotations.
To obtain the `ComposablePreview` object, please refer to [ComposePreviewScanner](https://github.com/sergio-sastre/ComposablePreviewScanner).
To obtain the `ComposablePreview` object, please refer to [ComposablePreviewScanner](https://github.com/sergio-sastre/ComposablePreviewScanner).

```kotlin
fun ComposablePreview<AndroidPreviewInfo>.captureRoboImage(
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ webjar-material-design-icons = "4.0.0"
webjar-materialize = "1.0.0"
webjars-locator-lite = "0.0.4"

composable-preview-scanner = "0.1.2"
composable-preview-scanner = "0.1.3"

[libraries]
roborazzi = { module = "io.github.takahirom.roborazzi:roborazzi", version.ref = "roborazzi-for-replacing-by-include-build" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class GeneratePreviewTestTest {
checkHasImages()
}
}

@Test
fun whenKmpModuleAndRecordRunImagesShouldBeRecorded() {
RoborazziGradleRootProject(testProjectDir).previewModule.apply {
Expand All @@ -26,6 +27,40 @@ class GeneratePreviewTestTest {
checkHasImages()
}
}

@Test
fun whenDisablePreviewAndRecordRunImagesShouldNotBeRecorded() {
RoborazziGradleRootProject(testProjectDir).previewModule.apply {
buildGradle.enable = false

record()

checkNoImages()
}
}

@Test
fun whenCustomTesterAndRecordRunImagesShouldBeRecordedAndCanSeeJUnitLog() {
RoborazziGradleRootProject(testProjectDir).previewModule.apply {
buildGradle.useCustomTester = true

record {
itShouldHaveJUnitRuleLog()
}

checkHasImages()
}
}

@Test
fun whenIncludePrivatePreviewsAndRecordRunImagesShouldBeRecorded() {
RoborazziGradleRootProject(testProjectDir).previewModule.apply {
buildGradle.isIncludePrivatePreviews = true
record()

checkHasPrivatePreviewImages()
}
}
}

class PreviewModule(
Expand All @@ -35,6 +70,7 @@ class PreviewModule(
companion object {
val moduleName = "sample-generate-preview-tests"
}

val buildGradle = BuildGradle(testProjectDir)

class BuildGradle(private val projectFolder: TemporaryFolder) {
Expand All @@ -44,14 +80,8 @@ class PreviewModule(
val file =
projectFolder.root.resolve(PATH)
file.parentFile.mkdirs()
val roborazziExtension = """
roborazzi {
generateComposePreviewRobolectricTests {
enable = true
packages = listOf("com.github.takahirom.preview.tests")
}
}
""".trimIndent()

val roborazziExtension = createRoborazziExtension()
val androidBlock = """
android {
namespace = "com.github.takahirom.preview.tests"
Expand Down Expand Up @@ -89,7 +119,7 @@ class PreviewModule(
}

""".trimIndent()
val buildGradleText = if(isKmp)
val buildGradleText = if (isKmp)
"""
plugins {
kotlin("multiplatform")
Expand Down Expand Up @@ -144,7 +174,7 @@ class PreviewModule(
maven { url = uri("https://jitpack.io") }
}
""".trimIndent()
else """
else """
plugins {
id("com.android.application")
// id("com.android.library")
Expand Down Expand Up @@ -180,10 +210,44 @@ class PreviewModule(
buildGradleText.trimIndent()
)
}

var enable = true
var isIncludePrivatePreviews = false
var useCustomTester = false

private fun createRoborazziExtension(): String {
val includePrivatePreviewsExpr = if (isIncludePrivatePreviews) {
"""includePrivatePreviews = $isIncludePrivatePreviews"""
} else {
""
}
val customTesterExpr = if (useCustomTester) {
"""testerQualifiedClassName = "com.github.takahirom.sample.CustomPreviewTester""""
} else {
""
}
val roborazziExtension = """
roborazzi {
generateComposePreviewRobolectricTests {
enable = $enable
packages = listOf("com.github.takahirom.preview.tests")
$includePrivatePreviewsExpr
$customTesterExpr
}
}
""".trimIndent()
return roborazziExtension
}
}

fun record(checks: BuildResult.() -> Unit = {}) {
val result = runTask("recordRoborazziDebug")
result.checks()
}

fun record() {
runTask("recordRoborazziDebug")
fun BuildResult.itShouldHaveJUnitRuleLog() {
assert(output.contains("JUnit4TestLifecycleOptions starting"))
assert(output.contains("JUnit4TestLifecycleOptions finished"))
}

private fun runTask(
Expand All @@ -205,4 +269,24 @@ class PreviewModule(
println("images:" + images?.toList())
assert(images?.isNotEmpty() == true)
}

fun checkNoImages() {
val images = testProjectDir.root.resolve("$moduleName/build/outputs/roborazzi/").listFiles()
println("images:" + images?.toList())
checkResultCount(
testProjectDir.root.resolve("$moduleName/build/test-results/roborazzi/results-summary.json")
// All zero
)

assert(images?.isEmpty() == true)
}

fun checkHasPrivatePreviewImages() {
val privateImages =
testProjectDir.root.resolve("$moduleName/build/outputs/roborazzi/").listFiles()
.orEmpty()
.filter { it.name.contains("PreviewWithPrivate") }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not to name it "WithPrivatePreviews" instead?

println("images:" + privateImages.toList())
assert(privateImages.isNotEmpty() == true)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -337,19 +337,7 @@ dependencies {
) {
val recordedFile =
testProjectDir.root.resolve("app/$buildDirName/test-results/roborazzi/results-summary.json")
val results = CaptureResults.fromJsonFile(recordedFile.absolutePath)
assert(results.resultSummary.recorded == recorded) {
"Expected count: $recorded, actual count: ${results.resultSummary.recorded} summary:${results.resultSummary}"
}
assert(results.resultSummary.added == added) {
"Expected count: $added, actual count: ${results.resultSummary.added} summary:${results.resultSummary}"
}
assert(results.resultSummary.changed == changed) {
"Expected count: $changed, actual count: ${results.resultSummary.changed} summary:${results.resultSummary}"
}
assert(results.resultSummary.unchanged == unchanged) {
"Expected count: $unchanged, actual count: ${results.resultSummary.unchanged} summary:${results.resultSummary}"
}
checkResultCount(recordedFile, recorded, added, changed, unchanged)
}

fun checkRecordedFileExists(path: String) {
Expand Down Expand Up @@ -646,3 +634,25 @@ class RoborazziTest {

val buildGradle = BuildGradle(testProjectDir)
}

fun checkResultCount(
recordedFile: File,
recorded: Int = 0,
added: Int = 0,
changed: Int = 0,
unchanged: Int = 0
) {
val results = CaptureResults.fromJsonFile(recordedFile.absolutePath)
assert(results.resultSummary.recorded == recorded) {
"Expected count: $recorded, actual count: ${results.resultSummary.recorded} summary:${results.resultSummary}"
}
assert(results.resultSummary.added == added) {
"Expected count: $added, actual count: ${results.resultSummary.added} summary:${results.resultSummary}"
}
assert(results.resultSummary.changed == changed) {
"Expected count: $changed, actual count: ${results.resultSummary.changed} summary:${results.resultSummary}"
}
assert(results.resultSummary.unchanged == unchanged) {
"Expected count: $unchanged, actual count: ${results.resultSummary.unchanged} summary:${results.resultSummary}"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,23 @@ fun PreviewDarkMode() {
}
}

@Preview
@Composable
private fun PreviewWithPrivate() {
val isSystemInDarkTheme = isSystemInDarkTheme()
MaterialTheme {
Card(
Modifier
.width(180.dp)
) {
Text(
modifier = Modifier.padding(8.dp),
text = "This is private preview"
)
}
}
}

@Preview(
name = "Preview Name",
// These properties are not supported by Roborazzi yet.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.github.takahirom.sample

import org.junit.Assert.*
import com.github.takahirom.roborazzi.*
import org.junit.rules.TestWatcher
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo

class CustomPreviewTester : ComposePreviewTester<AndroidPreviewInfo> by AndroidComposePreviewTester() {
override fun options(): ComposePreviewTester.Options = super.options().copy(
testLifecycleOptions = ComposePreviewTester.Options.JUnit4TestLifecycleOptions(
testRuleFactory = {
object : TestWatcher() {
override fun starting(description: org.junit.runner.Description?) {
println("JUnit4TestLifecycleOptions starting")
super.starting(description)
}

override fun finished(description: org.junit.runner.Description?) {
println("JUnit4TestLifecycleOptions finished")
super.finished(description)
}
}
}
)
)
}

This file was deleted.

Loading
Loading