Skip to content

Commit

Permalink
[Paywalls V2] Adds image background tests (#1967)
Browse files Browse the repository at this point in the history
  • Loading branch information
JayShortway authored Dec 10, 2024
1 parent eda371a commit b793940
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 3 deletions.
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ window-core = { module = "androidx.window:window-core", version.ref = "window" }

coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" }
coil-svg = { module = "io.coil-kt:coil-svg", version.ref = "coil" }
coil-test = { module = "io.coil-kt:coil-test", version.ref = "coil" }

commonmark = { module = "org.commonmark:commonmark", version.ref = "commonmark" }
commonmark-strikethrough = { module = "org.commonmark:commonmark-ext-gfm-strikethrough", version.ref = "commonmark" }
Expand Down
1 change: 1 addition & 0 deletions ui/revenuecatui/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ dependencies {
debugImplementation libs.androidx.test.compose.manifest

testImplementation libs.bundles.test
testImplementation libs.coil.test
testImplementation libs.coroutines.test
testImplementation libs.kotlinx.serialization.json
testImplementation libs.androidx.test.compose
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ internal fun Background.toBackgroundStyle(): BackgroundStyle =
val imageUrls = value.urlsForCurrentTheme
BackgroundStyle.Image(
painter = rememberAsyncImagePainter(
model = imageUrls.webp,
model = imageUrls.webp.toString(),
placeholder = rememberAsyncImagePainter(
model = imageUrls.webpLowRes,
model = imageUrls.webpLowRes.toString(),
error = null,
fallback = null,
contentScale = ContentScale.Crop,
Expand Down Expand Up @@ -136,4 +136,5 @@ private fun Background_Preview_ColorGradientRadial() {
)
}

// We cannot use a network image in Compose previews, so we don't have a preview for Background.Image.
// We cannot use a network image in Compose previews, so we don't have a preview for Background.Image. Instead, we have
// some tests in BackgroundTests.
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package com.revenuecat.purchases.ui.revenuecatui.components.modifier

import android.graphics.drawable.ColorDrawable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTag
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import coil.Coil
import coil.ImageLoader
import coil.annotation.ExperimentalCoilApi
import coil.test.FakeImageLoaderEngine
import com.revenuecat.purchases.paywalls.components.common.Background
import com.revenuecat.purchases.paywalls.components.properties.ImageUrls
import com.revenuecat.purchases.paywalls.components.properties.ThemeImageUrls
import com.revenuecat.purchases.ui.revenuecatui.assertions.assertPixelColorEquals
import com.revenuecat.purchases.ui.revenuecatui.assertions.assertPixelColorPercentage
import com.revenuecat.purchases.ui.revenuecatui.components.properties.toBackgroundStyle
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
import org.robolectric.annotation.GraphicsMode
import org.robolectric.shadows.ShadowPixelCopy
import java.net.URL

@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(shadows = [ShadowPixelCopy::class], sdk = [26])
@OptIn(ExperimentalCoilApi::class)
@RunWith(AndroidJUnit4::class)
class BackgroundTests {

private enum class TestUrl(val urlString: String, val color: Color) {
Blue(urlString = "https://blue", color = Color.Blue),
;
}

@get:Rule
val composeTestRule = createComposeRule()

@Before
fun setup() {
val engine = FakeImageLoaderEngine.Builder()
.interceptAllTestUrls()
.build()
val imageLoader = ImageLoader.Builder(InstrumentationRegistry.getInstrumentation().targetContext)
.components { add(engine) }
.build()

Coil.setImageLoader(imageLoader)
}

@After
fun teardown() {
Coil.reset()
}

@Test
fun `Should properly set an image background`(): Unit = with(composeTestRule) {
// Arrange
val sizePx = 100
val testUrl = TestUrl.Blue
val expectedColor = testUrl.color
val background = Background.Image(ThemeImageUrls(light = testUrl.toImageUrls(size = sizePx)))
setContent {
val backgroundStyle = background.toBackgroundStyle()
val sizeDp = with(LocalDensity.current) { sizePx.toDp() }

// Act
Box(
modifier = Modifier
.requiredSize(sizeDp)
.background(backgroundStyle)
.semantics { testTag = "box" }
)
}

// Assert
onNodeWithTag("box")
.assertIsDisplayed()
.assertPixelColorEquals(startX = 0, startY = 0, width = sizePx, height = sizePx, color = expectedColor)
}

@Test
fun `Should draw image background behind content`(): Unit = with(composeTestRule) {
// Arrange
val sizePx = 100
val testUrl = TestUrl.Blue
val expectedColor = testUrl.color
val background = Background.Image(ThemeImageUrls(light = testUrl.toImageUrls(size = sizePx)))
setContent {
val backgroundStyle = background.toBackgroundStyle()
val sizeDp = with(LocalDensity.current) { sizePx.toDp() }

// Act
Text(
text = "Hello",
modifier = Modifier
.requiredSize(sizeDp)
.background(backgroundStyle)
.semantics { testTag = "box" }
)
}

// Assert
onNodeWithTag("box")
.assertIsDisplayed()
.assertPixelColorPercentage(
startX = 0,
startY = 0,
width = sizePx,
height = sizePx,
color = expectedColor,
// Text rendering might not be fully deterministic (e.g. due to anti aliasing, font settings, etc.) so
// we're just verifying that the majority of the Composable shows the background, but not all of it.
predicate = { percentage -> percentage in 0.6f..0.99f }
)
}

private fun FakeImageLoaderEngine.Builder.interceptAllTestUrls(): FakeImageLoaderEngine.Builder = apply {
TestUrl.values().forEach { testUrl ->
intercept(testUrl.urlString, ColorDrawable(testUrl.color.toArgb()))
}
}

private fun TestUrl.toImageUrls(size: Int): ImageUrls =
ImageUrls(
original = URL(urlString),
webp = URL(urlString),
webpLowRes = URL(urlString),
width = size.toUInt(),
height = size.toUInt(),
)
}

0 comments on commit b793940

Please sign in to comment.