Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
3 changes: 3 additions & 0 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ plugins {
alias(libs.plugins.sentry)
alias(libs.plugins.roborazzi)
alias(libs.plugins.androidx.room)
alias(libs.plugins.paparazzi)
}

android {
Expand Down Expand Up @@ -164,6 +165,8 @@ dependencies {
ksp(libs.androidx.room.compiler)

testImplementation(libs.junit)
testImplementation(libs.reflections)
testImplementation(libs.composable.preview.scanner)
testImplementation(libs.robolectric)
testImplementation(libs.roborazzi)
testImplementation(libs.roborazzi.compose)
Expand Down
71 changes: 0 additions & 71 deletions android/app/src/test/kotlin/BookmarksScreenComposeTest.kt

This file was deleted.

37 changes: 0 additions & 37 deletions android/app/src/test/kotlin/StoryRowComposeTest.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.emergetools.hackernews

import app.cash.paparazzi.Paparazzi
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import sergio.sastre.composable.preview.scanner.android.AndroidComposablePreviewScanner
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo
import sergio.sastre.composable.preview.scanner.android.screenshotid.AndroidPreviewScreenshotIdBuilder
import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview


@RunWith(Parameterized::class)
class ComposePreviewScanner(val preview: ComposablePreview<AndroidPreviewInfo>) {

companion object {
// Optimization: This avoids scanning for every test
private val cachedPreviews: List<ComposablePreview<AndroidPreviewInfo>> by lazy {
AndroidComposablePreviewScanner()
.scanPackageTrees("com.emergetools.hackernews")
.getPreviews()
}

@JvmStatic
@Parameterized.Parameters
fun values(): List<ComposablePreview<AndroidPreviewInfo>> = cachedPreviews
}

@get:Rule val paparazzi= Paparazzi()


@Test
fun snapshotTest() {
val screenshotId = AndroidPreviewScreenshotIdBuilder(preview).build()

paparazzi.snapshot(name = screenshotId) {
val previewInfo = preview.previewInfo
preview()
}
Copy link

Choose a reason for hiding this comment

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

Bug: The previewInfo variable is extracted but unused. The preview() object is invoked directly, which likely ignores the intended preview configuration for the snapshot test.
Severity: HIGH | Confidence: High

🔍 Detailed Analysis

In the snapshot test, the previewInfo variable is extracted from the preview object but is never used. Instead, the preview() object is invoked directly. According to the library's documentation, the composable function should be invoked via the previewInfo object (e.g., previewInfo.previewComposable.invoke()). This discrepancy means that important configuration metadata from the @Preview annotation, such as device settings, locale, and theme, is likely being ignored. As a result, the generated snapshots may not reflect the intended configuration, leading to incorrect or failing tests.

💡 Suggested Fix

Replace the direct invocation preview() with the invocation from the previewInfo object, such as previewInfo.previewComposable.invoke(). This will ensure the composable is rendered with the correct configuration specified in its @Preview annotation.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location:
android/app/src/test/kotlin/com/emergetools/hackernews/ComposePreviewScanner.kt#L38-L40

Potential issue: In the snapshot test, the `previewInfo` variable is extracted from the
`preview` object but is never used. Instead, the `preview()` object is invoked directly.
According to the library's documentation, the composable function should be invoked via
the `previewInfo` object (e.g., `previewInfo.previewComposable.invoke()`). This
discrepancy means that important configuration metadata from the `@Preview` annotation,
such as device settings, locale, and theme, is likely being ignored. As a result, the
generated snapshots may not reflect the intended configuration, leading to incorrect or
failing tests.

Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 7526923

}


}
4 changes: 4 additions & 0 deletions android/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ ksp = "2.3.3"
coreKtx = "1.17.0"
junit = "4.13.2"
junitVersion = "1.1.5" # This is to match Compose's version
reflections = "0.10.2"
robolectric = "4.16"
roborazzi = "1.52.0"
espressoCore = "3.5.0" # This is to match Compose's version
Expand All @@ -31,6 +32,7 @@ uiautomator = "2.3.0"
benchmarkMacroJunit4 = "1.4.1"

[libraries]
composable-preview-scanner = { module = "io.github.sergio-sastre.ComposablePreviewScanner:android", version = "0.7.2" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
Expand All @@ -56,6 +58,7 @@ androidx-material3 = { group = "androidx.compose.material3", name = "material3"
extendedspans = { group = "me.saket.extendedspans", name = "extendedspans", version.ref = "extendedspans" }

okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" }
reflections = { module = "org.reflections:reflections", version.ref = "reflections" }
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
retrofit-kotlinx-serialization = { group = "com.squareup.retrofit2", name = "converter-kotlinx-serialization", version.ref = "retrofit" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" }
Expand Down Expand Up @@ -84,6 +87,7 @@ kotlin-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
emerge = { id = "com.emergetools.android", version.ref = "emergePlugin" }
sentry = { id = "io.sentry.android.gradle", version.ref = "sentry" }
roborazzi = { id = "io.github.takahirom.roborazzi", version.ref = "roborazzi" }
paparazzi = { id = "app.cash.paparazzi", version = "2.0.0-alpha02" }
androidx-room = { id = "androidx.room", version.ref = "room" }
android-test = { id = "com.android.test", version.ref = "agp" }

Loading