takahirom / roborazzi

Make JVM Android integration test visible 🤖📸
https://takahirom.github.io/roborazzi/
Apache License 2.0
649 stars 24 forks source link

Hanging test with infinite animation #413

Closed ebicola closed 1 week ago

ebicola commented 1 week ago

Hi, I have some tests which verify a loading state of the UI, which I want to migrate to Roborazzi. This state has a skeleton-like, infinite animation and it seems like the test doesn't complete because of that. Here is some sample code:

import androidx.compose.animation.core.InfiniteTransition
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.LayoutDirection
import com.github.takahirom.roborazzi.captureRoboImage
import org.junit.*
import org.junit.runner.*
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.robolectric.annotation.GraphicsMode

@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(sdk = [33])
class SampleTest {

    @Test
    fun hanging() {
        captureRoboImage {
            Text(
                text = "",
                modifier = Modifier
                    .shimmer(MaterialTheme.colors.onSurface)
                    .clip(MaterialTheme.shapes.medium)
            )
        }
    }
}

fun Modifier.shimmer(color: Color) = composed {
    val transition = rememberInfiniteTransition("shimmerTransition")
    shimmer(color, transition)
}

fun Modifier.shimmer(color: Color, transition: InfiniteTransition) = composed {
    val (initialValue, targetValue) = if (LocalLayoutDirection.current == LayoutDirection.Ltr) 0f to 2f else 2f to 0f
    val translateAnimation = transition.animateFloat(
        label = "shimmerAnimation",
        initialValue = initialValue,
        targetValue = targetValue,
        animationSpec = infiniteRepeatable(
            animation = tween(1200), repeatMode = RepeatMode.Restart
        )
    )

    drawWithContent {
        drawRect(
            Brush.linearGradient(
                colors = listOf(1f, 0.6f, 0.1f, 0.6f, 1f).map { color.copy(alpha = it) },
                start = Offset.Zero,
                end = Offset(x = translateAnimation.value * size.width, y = translateAnimation.value * size.height)
            )
        )
    }
}
takahirom commented 1 week ago

Thanks. I previously suggested setting autoAdvance to false in this comment to address similar issues. Could you try this solution to see if it resolves the problem with the infinite animation in your tests? Additionally, you might consider detecting if the test is running and removing the animated element. https://stackoverflow.com/a/30713876

takahirom commented 1 week ago

I'll close this issue. If you have any other problems, let me know.