Skip to content

Commit

Permalink
Add RoborazziComposeActivityScenarioCreationOption to handle theme
Browse files Browse the repository at this point in the history
  • Loading branch information
takahirom committed Dec 18, 2024
1 parent f4aa5be commit 48423d8
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ internal fun registerActivityToRobolectricIfNeeded() {
val appContext: Application = ApplicationProvider.getApplicationContext()
Shadows.shadowOf(appContext.packageManager).addActivityIfNotPresent(
ComponentName(
appContext.packageName,
RoborazziTransparentActivity::class.java.name,
appContext,
RoborazziActivity::class.java,
)
)
} catch (e: ClassNotFoundException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewRootForTest
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import java.io.File


Expand Down Expand Up @@ -59,7 +60,7 @@ fun captureRoboImage(
content: @Composable () -> Unit,
) {
if (!roborazziOptions.taskType.isEnabled()) return
launchRoborazziTransparentActivity { activityScenario ->
launchRoborazziActivity(roborazziComposeOptions) { activityScenario ->
val configuredContent = roborazziComposeOptions
.configured(activityScenario) {
content()
Expand All @@ -70,19 +71,27 @@ fun captureRoboImage(
}
}

private fun launchRoborazziTransparentActivity(block: (ActivityScenario<RoborazziTransparentActivity>) -> Unit = {}) {
registerActivityToRobolectricIfNeeded()

val activityScenario = ActivityScenario.launch(RoborazziTransparentActivity::class.java)
private fun launchRoborazziActivity(roborazziComposeOptions: RoborazziComposeOptions,block: (ActivityScenario<out ComponentActivity>) -> Unit = {}) {
val activityScenario = roborazziComposeOptions.createScenario {
createActivityScenario(theme = android.R.style.Theme_Translucent_NoTitleBar_Fullscreen)
}

// Closing the activity is necessary to prevent memory leaks.
// If multiple captureRoboImage calls occur in a single test,
// they can lead to an activity leak.
return activityScenario.use { block(activityScenario) }
}

internal fun createActivityScenario(theme: Int): ActivityScenario<out ComponentActivity> {
registerActivityToRobolectricIfNeeded()
return ActivityScenario.launch(RoborazziActivity.createIntent(
context = ApplicationProvider.getApplicationContext(),
theme = theme
))
}

private fun ActivityScenario<out ComponentActivity>.captureRoboImage(

private fun ActivityScenario<out androidx.activity.ComponentActivity>.captureRoboImage(
filePath: String,
roborazziOptions: RoborazziOptions = provideRoborazziContext().options,
content: @Composable () -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.github.takahirom.roborazzi
import android.app.Activity
import android.content.res.Configuration
import android.graphics.Color
import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
Expand Down Expand Up @@ -32,24 +33,35 @@ interface RoborazziComposeActivityScenarioOption : RoborazziComposeOption {
fun configureWithActivityScenario(scenario: ActivityScenario<out Activity>)
}

@ExperimentalRoborazziApi
interface RoborazziComposeActivityScenarioCreationOption : RoborazziComposeOption {
fun createScenario(chain: () -> ActivityScenario<out androidx.activity.ComponentActivity>): ActivityScenario<out androidx.activity.ComponentActivity>
}

@ExperimentalRoborazziApi
interface RoborazziComposeComposableOption : RoborazziComposeOption {
fun configureWithComposable(content: @Composable () -> Unit): @Composable () -> Unit
}

@ExperimentalRoborazziApi
class RoborazziComposeOptions private constructor(
private val createActivityScenarioOptions: List<RoborazziComposeActivityScenarioCreationOption>,
private val activityScenarioOptions: List<RoborazziComposeActivityScenarioOption>,
private val composableOptions: List<RoborazziComposeComposableOption>,
private val setupOptions: List<RoborazziComposeSetupOption>
) {
class Builder {
private val activityScenarioOptions =
mutableListOf<RoborazziComposeActivityScenarioOption>()
private val createActivityScenarioOptions =
mutableListOf<RoborazziComposeActivityScenarioCreationOption>()
private val composableOptions = mutableListOf<RoborazziComposeComposableOption>()
private val setupOptions = mutableListOf<RoborazziComposeSetupOption>()

fun addOption(option: RoborazziComposeOption): Builder {
if (option is RoborazziComposeActivityScenarioCreationOption) {
createActivityScenarioOptions.add(option)
}
if (option is RoborazziComposeActivityScenarioOption) {
activityScenarioOptions.add(option)
}
Expand All @@ -64,6 +76,7 @@ class RoborazziComposeOptions private constructor(

fun build(): RoborazziComposeOptions {
return RoborazziComposeOptions(
createActivityScenarioOptions = createActivityScenarioOptions,
activityScenarioOptions = activityScenarioOptions,
composableOptions = composableOptions,
setupOptions = setupOptions
Expand All @@ -80,6 +93,13 @@ class RoborazziComposeOptions private constructor(
}
}

@ExperimentalRoborazziApi
fun createScenario(chain: () -> ActivityScenario<out androidx.activity.ComponentActivity>): ActivityScenario<out androidx.activity.ComponentActivity> {
return createActivityScenarioOptions.fold(chain) { acc, option ->
{ option.createScenario(acc) }
}()
}

@ExperimentalRoborazziApi
fun configured(
activityScenario: ActivityScenario<out Activity>,
Expand Down Expand Up @@ -269,10 +289,8 @@ fun RoborazziComposeOptions.Builder.theme(themeResId: Int): RoborazziComposeOpti

@ExperimentalRoborazziApi
data class RoborazziComposeActivityThemeOption(private val themeResId: Int) :
RoborazziComposeActivityScenarioOption {
override fun configureWithActivityScenario(scenario: ActivityScenario<out Activity>) {
scenario.onActivity { activity ->
activity.setTheme(themeResId)
}
RoborazziComposeActivityScenarioCreationOption {
override fun createScenario(chain: () -> ActivityScenario<out ComponentActivity>): ActivityScenario<out ComponentActivity> {
return createActivityScenario(themeResId)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
package com.github.takahirom.roborazzi

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity

class RoborazziTransparentActivity: ComponentActivity() {
@Deprecated("Use RoborazziActivity instead", ReplaceWith("RoborazziActivity"), level = DeprecationLevel.ERROR)
class RoborazziTransparentActivity: RoborazziActivity()

open class RoborazziActivity: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(android.R.style.Theme_Translucent_NoTitleBar_Fullscreen)
setTheme(intent.getIntExtra(EXTRA_THEME, android.R.style.Theme_Translucent_NoTitleBar_Fullscreen))
super.onCreate(savedInstanceState)
}
companion object {
const val EXTRA_THEME = "EXTRA_THEME"
fun createIntent(context: Context, theme: Int = android.R.style.Theme_Translucent_NoTitleBar_Fullscreen): Intent {
return Intent(context, RoborazziActivity::class.java).apply {
putExtra(EXTRA_THEME, theme)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class ComposeLambdaTest {
theme(android.R.style.Theme_Material_Light)
}
) {
Text("This composable function should not have transparent background!")
Text("This composable function should NOT have transparent background!")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ import androidx.compose.ui.test.performClick
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.github.takahirom.roborazzi.Dump
import com.github.takahirom.roborazzi.RoborazziActivity
import com.github.takahirom.roborazzi.RoborazziOptions
import com.github.takahirom.roborazzi.RoborazziRule
import com.github.takahirom.roborazzi.RoborazziTransparentActivity
import com.github.takahirom.roborazzi.captureRoboImage
import org.junit.Rule
import org.junit.Test
Expand All @@ -48,7 +48,7 @@ import org.robolectric.annotation.GraphicsMode
@GraphicsMode(GraphicsMode.Mode.NATIVE)
class ComposeTest {
@get:Rule
val composeTestRule = createAndroidComposeRule<RoborazziTransparentActivity>()
val composeTestRule = createAndroidComposeRule<RoborazziActivity>()

@get:Rule
val roborazziRule = RoborazziRule(
Expand Down

0 comments on commit 48423d8

Please sign in to comment.