Skip to content

Commit

Permalink
Refactor CustomPreviewTester to support JUnit4TestParameter and impro…
Browse files Browse the repository at this point in the history
…ve type safety
  • Loading branch information
takahirom committed Mar 1, 2025
1 parent bf9851a commit ae1b052
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import org.junit.rules.RuleChain
import org.junit.rules.TestWatcher
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo
import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview
import com.github.takahirom.roborazzi.ComposePreviewTester.TestParameter.JUnit4TestParameter.AndroidPreviewJUnit4TestParameter
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.test.ext.junit.rules.ActivityScenarioRule
import com.github.takahirom.roborazzi.*
import androidx.compose.ui.test.onRoot

class CustomPreviewTester : ComposePreviewTester<AndroidPreviewInfo> by AndroidComposePreviewTester() {
val composeTestRule = createAndroidComposeRule<RoborazziActivity>() as AndroidComposeTestRule<ActivityScenarioRule<out androidx.activity.ComponentActivity>, *>
class CustomPreviewTester : ComposePreviewTester<AndroidPreviewJUnit4TestParameter> by AndroidComposePreviewTester() {
override fun options(): ComposePreviewTester.Options = super.options().copy(
testLifecycleOptions = ComposePreviewTester.Options.JUnit4TestLifecycleOptions(
composeRuleFactory = { composeTestRule },
composeRuleFactory = { createAndroidComposeRule<RoborazziActivity>() as AndroidComposeTestRule<ActivityScenarioRule<out androidx.activity.ComponentActivity>, *> },
testRuleFactory = { composeTestRule ->
RuleChain.outerRule(
object : TestWatcher() {
Expand All @@ -40,10 +40,7 @@ class CustomPreviewTester : ComposePreviewTester<AndroidPreviewInfo> by AndroidC
)
)

override fun test(testParameter: ComposePreviewTester.TestParameter<AndroidPreviewInfo>) {
if (testParameter !is ComposePreviewTester.TestParameter.JUnit4TestParameter<*>) {
throw IllegalArgumentException("Currently only JUnit4TestParameter is supported")
}
override fun test(testParameter: AndroidPreviewJUnit4TestParameter) {
val preview = testParameter.preview as ComposablePreview
testParameter.composeTestRule.setContent {
testParameter.preview()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import org.gradle.api.tasks.TaskCollection
import org.gradle.api.tasks.testing.Test
import java.io.File
import java.net.URLEncoder
import java.util.Locale
import java.util.*
import javax.inject.Inject

open class GenerateComposePreviewRobolectricTestsExtension @Inject constructor(objects: ObjectFactory) {
Expand Down Expand Up @@ -205,14 +205,14 @@ abstract class GenerateComposePreviewRobolectricTestsTask : DefaultTask() {
companion object {
// lazy for performance
val testParameters: List<ComposePreviewTester.TestParameter<Any>> by lazy {
val testParameters: List<ComposePreviewTester.TestParameter<*>> by lazy {
setupDefaultOptions()
val tester = getComposePreviewTester("$testerQualifiedClassNameString")
tester.testParameters()
}
@JvmStatic
@ParameterizedRobolectricTestRunner.Parameters(name = "{0}")
fun values(): List<ComposePreviewTester.TestParameter<Any>> = testParameters
fun values(): List<ComposePreviewTester.TestParameter<*>> = testParameters
fun setupDefaultOptions() {
ComposePreviewTester.defaultOptionsFromPlugin = ComposePreviewTester.Options(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import androidx.compose.ui.test.junit4.ComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.rules.ActivityScenarioRule
import com.github.takahirom.roborazzi.ComposePreviewTester.TestParameter
import com.github.takahirom.roborazzi.ComposePreviewTester.TestParameter.JUnit4TestParameter.AndroidPreviewJUnit4TestParameter
import com.github.takahirom.roborazzi.annotations.ManualClockOptions
import com.github.takahirom.roborazzi.annotations.RoboComposePreviewOptions
import org.junit.rules.RuleChain
Expand Down Expand Up @@ -133,7 +135,7 @@ data class RoborazziComposeManualAdvancePreviewOption(
* A new instance of the tester class is created for each test execution and preview generation.
*/
@ExperimentalRoborazziApi
interface ComposePreviewTester<T : Any> {
interface ComposePreviewTester<TESTPARAMETER : TestParameter<*>> {
data class Options(
val testLifecycleOptions: TestLifecycleOptions = JUnit4TestLifecycleOptions(),
val scanOptions: ScanOptions = ScanOptions(emptyList()),
Expand Down Expand Up @@ -189,7 +191,7 @@ interface ComposePreviewTester<T : Any> {
*
* @return A list of ComposablePreview objects of type T.
*/
fun testParameters(): List<TestParameter<T>>
fun testParameters(): List<TESTPARAMETER>

sealed class TestParameter<T> {
open class JUnit4TestParameter<T>(
Expand All @@ -212,9 +214,9 @@ interface ComposePreviewTester<T : Any> {
* Performs a test on a single composable preview.
* Note: This method will not be called as the same instance of previews() method.
*
* @param preview The ComposablePreview object to be tested.
* @param testParameter The TestParameter object.
*/
fun test(testParameter: TestParameter<T>)
fun test(testParameter: TESTPARAMETER)

companion object {
// Should be replaced with the actual default options from the plugin.
Expand All @@ -224,8 +226,8 @@ interface ComposePreviewTester<T : Any> {
}

@ExperimentalRoborazziApi
class AndroidComposePreviewTester : ComposePreviewTester<AndroidPreviewInfo> {
override fun testParameters(): List<ComposePreviewTester.TestParameter<AndroidPreviewInfo>> {
class AndroidComposePreviewTester : ComposePreviewTester<AndroidPreviewJUnit4TestParameter> {
override fun testParameters(): List<AndroidPreviewJUnit4TestParameter> {
val options = options()
val junit4TestLifecycleOptions =
options.testLifecycleOptions as ComposePreviewTester.Options.JUnit4TestLifecycleOptions
Expand All @@ -249,7 +251,7 @@ class AndroidComposePreviewTester : ComposePreviewTester<AndroidPreviewInfo> {
?: RoboComposePreviewOptions()
annotationOptions.variations()
.map { optionVariation ->
ComposePreviewTester.TestParameter.JUnit4TestParameter.AndroidPreviewJUnit4TestParameter(
AndroidPreviewJUnit4TestParameter(
composeTestRule = junit4TestLifecycleOptions.composeRuleFactory(),
preview = preview,
composeRoboComposePreviewOptionVariation = optionVariation
Expand All @@ -258,10 +260,7 @@ class AndroidComposePreviewTester : ComposePreviewTester<AndroidPreviewInfo> {
}
}

override fun test(testParameter: ComposePreviewTester.TestParameter<AndroidPreviewInfo>) {
if (testParameter !is ComposePreviewTester.TestParameter.JUnit4TestParameter.AndroidPreviewJUnit4TestParameter) {
throw IllegalArgumentException("Currently only JUnit4TestParameter is supported")
}
override fun test(testParameter: AndroidPreviewJUnit4TestParameter) {
val junit4TestParameter: ComposePreviewTester.TestParameter.JUnit4TestParameter<*> =
testParameter
val preview = junit4TestParameter.preview
Expand Down Expand Up @@ -322,7 +321,7 @@ internal fun RoboComposePreviewOptions.variations(): List<RoboComposePreviewOpti
}

@InternalRoborazziApi
fun getComposePreviewTester(testerQualifiedClassName: String): ComposePreviewTester<Any> {
fun getComposePreviewTester(testerQualifiedClassName: String): ComposePreviewTester<TestParameter<*>> {
val customTesterClass = try {
Class.forName(testerQualifiedClassName)
} catch (e: ClassNotFoundException) {
Expand All @@ -332,6 +331,6 @@ fun getComposePreviewTester(testerQualifiedClassName: String): ComposePreviewTes
throw IllegalArgumentException("The class $testerQualifiedClassName must implement RobolectricPreviewCapturer")
}
@Suppress("UNCHECKED_CAST") val composePreviewTester =
customTesterClass.getDeclaredConstructor().newInstance() as ComposePreviewTester<Any>
customTesterClass.getDeclaredConstructor().newInstance() as ComposePreviewTester<TestParameter<*>>
return composePreviewTester
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,21 @@ import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onRoot
import androidx.test.ext.junit.rules.ActivityScenarioRule
import com.github.takahirom.roborazzi.ComposePreviewTester
import com.github.takahirom.roborazzi.DEFAULT_ROBORAZZI_OUTPUT_DIR_PATH
import com.github.takahirom.roborazzi.RoborazziActivity
import com.github.takahirom.roborazzi.captureRoboImage
import com.github.takahirom.roborazzi.registerRoborazziActivityToRobolectricIfNeeded
import com.github.takahirom.roborazzi.*
import com.github.takahirom.roborazzi.ComposePreviewTester.TestParameter.JUnit4TestParameter
import org.junit.rules.RuleChain
import org.junit.rules.TestWatcher
import sergio.sastre.composable.preview.scanner.jvm.JvmAnnotationInfo
import sergio.sastre.composable.preview.scanner.jvm.JvmAnnotationScanner

@OptIn(com.github.takahirom.roborazzi.ExperimentalRoborazziApi::class)
class MultiplatformPreviewTester : ComposePreviewTester<JvmAnnotationInfo> {
@Suppress("UNCHECKED_CAST")
val composeTestRule =
createAndroidComposeRule<RoborazziActivity>() as AndroidComposeTestRule<ActivityScenarioRule<out androidx.activity.ComponentActivity>, *>

class MultiplatformPreviewTester : ComposePreviewTester<JUnit4TestParameter<JvmAnnotationInfo>> {
override fun options(): ComposePreviewTester.Options = super.options().copy(
testLifecycleOptions = ComposePreviewTester.Options.JUnit4TestLifecycleOptions(
composeRuleFactory = { composeTestRule },
composeRuleFactory = {
@Suppress("UNCHECKED_CAST")
createAndroidComposeRule<RoborazziActivity>() as AndroidComposeTestRule<ActivityScenarioRule<out androidx.activity.ComponentActivity>, *>
},
testRuleFactory = { composeTestRule ->
RuleChain.outerRule(
object : TestWatcher() {
Expand All @@ -36,22 +32,20 @@ class MultiplatformPreviewTester : ComposePreviewTester<JvmAnnotationInfo> {
)
)

override fun testParameters(): List<ComposePreviewTester.TestParameter<JvmAnnotationInfo>> {
override fun testParameters(): List<JUnit4TestParameter<JvmAnnotationInfo>> {
val options = options()
return JvmAnnotationScanner("org.jetbrains.compose.ui.tooling.preview.Preview")
.scanPackageTrees(*options().scanOptions.packages.toTypedArray())
.scanPackageTrees(*options.scanOptions.packages.toTypedArray())
.getPreviews()
.map {
ComposePreviewTester.TestParameter.JUnit4TestParameter(
composeTestRule,
JUnit4TestParameter(
(options.testLifecycleOptions as ComposePreviewTester.Options.JUnit4TestLifecycleOptions).composeRuleFactory(),
it
)
}
}

override fun test(testParameter: ComposePreviewTester.TestParameter<JvmAnnotationInfo>) {
if (testParameter !is ComposePreviewTester.TestParameter.JUnit4TestParameter<*>) {
throw IllegalArgumentException()
}
override fun test(testParameter: JUnit4TestParameter<JvmAnnotationInfo>) {
val preview = testParameter.preview
testParameter.composeTestRule.setContent {
preview()
Expand Down

0 comments on commit ae1b052

Please sign in to comment.