Test previews with a11y details and add a first example with HomeViewA11yPreview.

This commit is contained in:
Benoit Marty 2025-08-23 16:43:50 +02:00 committed by Benoit Marty
parent a625c109b8
commit 1d7e7e19d9
5 changed files with 105 additions and 2 deletions

View file

@ -31,6 +31,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import dev.chrisbanes.haze.hazeEffect
@ -313,3 +314,22 @@ internal fun HomeViewPreview(@PreviewParameter(HomeStateProvider::class) state:
leaveRoomView = {}
)
}
@Preview
@Composable
internal fun HomeViewA11yPreview() = ElementPreview {
HomeView(
homeState = aHomeState(),
onRoomClick = {},
onSettingsClick = {},
onSetUpRecoveryClick = {},
onConfirmRecoveryKeyClick = {},
onStartChatClick = {},
onRoomSettingsClick = {},
onReportRoomClick = {},
onMenuActionClick = {},
onDeclineInviteAndBlockUser = {},
acceptDeclineInviteView = {},
leaveRoomView = {}
)
}

View file

@ -12,6 +12,7 @@ import com.google.common.truth.Truth.assertThat
import com.lemonappdev.konsist.api.Konsist
import com.lemonappdev.konsist.api.ext.list.withAllAnnotationsOf
import com.lemonappdev.konsist.api.ext.list.withName
import com.lemonappdev.konsist.api.ext.list.withNameEndingWith
import com.lemonappdev.konsist.api.ext.list.withoutName
import com.lemonappdev.konsist.api.verify.assertEmpty
import com.lemonappdev.konsist.api.verify.assertTrue
@ -32,6 +33,26 @@ class KonsistPreviewTest {
}
}
@Test
fun `Check functions with 'A11yPreview'`() {
Konsist
.scopeFromProject()
.functions()
.withNameEndingWith("A11yPreview")
.assertTrue(
additionalMessage = "Functions with 'A11yPreview' suffix should have '@Previews' annotation and not '@PreviewsDayNight'," +
" should contain 'ElementPreview' composable," +
" should contain the tested view" +
" and should be internal"
) {
val testedView = it.name.removeSuffix("A11yPreview")
it.text.contains("$testedView(") &&
it.hasAllAnnotationsOf(PreviewsDayNight::class).not() &&
it.text.contains("ElementPreview") &&
it.hasInternalModifier
}
}
@Test
fun `Functions with '@PreviewsDayNight' annotation should contain 'ElementPreview' composable`() {
Konsist

View file

@ -29,6 +29,7 @@ object ComposablePreviewProvider : TestParameter.TestParameterValuesProvider {
AndroidComposablePreviewScanner()
.scanPackageTrees(*PACKAGE_TREES)
.getPreviews()
.filter { composablePreview -> composablePreview.methodName.endsWith("A11yPreview").not() }
.withIndex()
.toList()
}
@ -36,6 +37,18 @@ object ComposablePreviewProvider : TestParameter.TestParameterValuesProvider {
override fun provideValues(): List<IndexedValue<ComposablePreview<AndroidPreviewInfo>>> = values
}
object ComposableA11yPreviewProvider : TestParameter.TestParameterValuesProvider {
private val values: List<ComposablePreview<AndroidPreviewInfo>> by lazy {
AndroidComposablePreviewScanner()
.scanPackageTrees(*PACKAGE_TREES)
.getPreviews()
.filter { composablePreview -> composablePreview.methodName.endsWith("A11yPreview") }
.toList()
}
override fun provideValues(): List<ComposablePreview<AndroidPreviewInfo>> = values
}
object Shard1ComposablePreviewProvider : TestParameter.TestParameterValuesProvider {
override fun provideValues(): List<ComposablePreview<AndroidPreviewInfo>> =
ComposablePreviewProvider.provideValues().filter { it.index % 4 == 0 }.map { it.value }

View file

@ -19,6 +19,7 @@ import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.unit.Density
import app.cash.paparazzi.DeviceConfig
import app.cash.paparazzi.Paparazzi
import app.cash.paparazzi.RenderExtension
import app.cash.paparazzi.TestName
import com.android.resources.NightMode
import io.element.android.compound.theme.ElementTheme
@ -112,7 +113,12 @@ fun createScreenshotIdFor(preview: ComposablePreview<AndroidPreviewInfo>) = buil
}.joinToString("_")
object PaparazziPreviewRule {
fun createFor(preview: ComposablePreview<AndroidPreviewInfo>, locale: String, deviceConfig: DeviceConfig = ScreenshotTest.defaultDeviceConfig): Paparazzi {
fun createFor(
preview: ComposablePreview<AndroidPreviewInfo>,
locale: String,
deviceConfig: DeviceConfig = ScreenshotTest.defaultDeviceConfig,
renderExtensions: Set<RenderExtension> = setOf(),
): Paparazzi {
val densityScale = deviceConfig.density.dpiValue / 160f
val customScreenHeight = preview.previewInfo.heightDp.takeIf { it >= 0 }?.let { it * densityScale }?.toInt()
return Paparazzi(
@ -125,7 +131,8 @@ object PaparazziPreviewRule {
softButtons = false,
screenHeight = customScreenHeight ?: deviceConfig.screenHeight,
),
maxPercentDifference = 0.01
maxPercentDifference = 0.01,
renderExtensions = renderExtensions,
)
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package ui
import app.cash.paparazzi.accessibility.AccessibilityRenderExtension
import base.ComposableA11yPreviewProvider
import base.PaparazziPreviewRule
import base.ScreenshotTest
import com.google.testing.junit.testparameterinjector.TestParameter
import com.google.testing.junit.testparameterinjector.TestParameterInjector
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import sergio.sastre.composable.preview.scanner.android.AndroidPreviewInfo
import sergio.sastre.composable.preview.scanner.core.preview.ComposablePreview
/**
* Test that takes a preview and runs a screenshot test on it.
* It uses [ComposableA11yPreviewProvider] to test only previews that ends with "A11yPreview".
*/
@RunWith(TestParameterInjector::class)
class PreviewA11yTest(
@TestParameter(valuesProvider = ComposableA11yPreviewProvider::class)
val preview: ComposablePreview<AndroidPreviewInfo>,
) {
@get:Rule
val paparazziRule = PaparazziPreviewRule.createFor(
preview = preview,
locale = "en",
renderExtensions = setOf(AccessibilityRenderExtension()),
)
@Test
fun snapshot() {
ScreenshotTest.runTest(paparazzi = paparazziRule, preview = preview, localeStr = "en")
}
}