~ knotless Search/
↑↓ move↵ open⇧↵ all results

grain.social/grain-android

1 collaborator
0
1
main
81 lines · 2.8 KB Raw History
package social.grain

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.v2.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import social.grain.data.model.AspectRatio
import social.grain.data.model.GrainGallery
import social.grain.data.model.GrainPhoto
import social.grain.data.model.GrainProfile
import social.grain.ui.components.GalleryCard
import social.grain.ui.theme.GrainTheme

private const val ALT = "A heron standing in shallow water at dawn"

/** Long enough to clear the platform's double-tap timeout. */
private const val DOUBLE_TAP_WINDOW_MS = 1000L

/**
 * The card carries a photo's description itself.
 *
 * The feed no longer pushes a detail screen, so a tap on the photo has to be
 * what reveals the alt text — if this regresses, the description becomes
 * unreachable to anyone not using a screen reader.
 */
@RunWith(AndroidJUnit4::class)
class GalleryCardAltTextTest {

    @get:Rule
    val composeRule = createComposeRule()

    private fun gallery(alt: String?) = GrainGallery(
        uri = "at://did:plc:test/social.grain.gallery/1",
        creator = GrainProfile(did = "did:plc:test", handle = "heron.example"),
        items = listOf(
            GrainPhoto(
                uri = "at://did:plc:test/social.grain.photo/1",
                alt = alt,
                aspectRatio = AspectRatio(3, 2),
            ),
        ),
        indexedAt = "2026-08-01T00:00:00Z",
    )

    @Test
    fun tappingThePhotoTogglesTheAltText() {
        composeRule.setContent { GrainTheme { GalleryCard(gallery = gallery(ALT)) } }

        composeRule.onNodeWithText(ALT).assertDoesNotExist()

        composeRule.onNodeWithContentDescription(ALT).performClick()
        // The carousel also listens for a double tap, so a single tap is only
        // reported once that window has passed.
        composeRule.mainClock.advanceTimeBy(DOUBLE_TAP_WINDOW_MS)
        composeRule.onNodeWithText(ALT).assertIsDisplayed()

        composeRule.onNodeWithText(ALT).performClick()
        composeRule.waitForIdle()
        composeRule.onNodeWithText(ALT).assertDoesNotExist()
    }

    @Test
    fun theBadgeAlsoOpensTheAltText() {
        composeRule.setContent { GrainTheme { GalleryCard(gallery = gallery(ALT)) } }

        composeRule.onNodeWithContentDescription("Show alt text").performClick()
        composeRule.onNodeWithText(ALT).assertIsDisplayed()
    }

    @Test
    fun aPhotoWithNoAltShowsNoBadge() {
        composeRule.setContent { GrainTheme { GalleryCard(gallery = gallery(null)) } }

        composeRule.onNodeWithText("ALT").assertDoesNotExist()
    }
}