diff --git a/.github/workflows/reusable-check.yml b/.github/workflows/reusable-check.yml index 85b9d46ba..0078af20c 100644 --- a/.github/workflows/reusable-check.yml +++ b/.github/workflows/reusable-check.yml @@ -12,6 +12,9 @@ on: run_instrumented_tests: type: boolean default: true + run_screenshot_tests: + type: boolean + default: true flavors: type: string default: '["google"]' @@ -110,6 +113,15 @@ jobs: fi fi + # Screenshot Test Tasks + if [ "${{ inputs.run_screenshot_tests }}" = "true" ] && [ "$IS_FIRST_API" = "true" ]; then + if [ "$FLAVOR" = "google" ]; then + TASKS="$TASKS validateGoogleDebugScreenshotTest " + elif [ "$FLAVOR" = "fdroid" ]; then + TASKS="$TASKS validateFdroidDebugScreenshotTest " + fi + fi + # Instrumented Test Tasks if [ "${{ inputs.run_instrumented_tests }}" = "true" ]; then [ "$IS_FIRST_FLAVOR" = "true" ] && TASKS="$TASKS connectedDebugAndroidTest " diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 1dfdc27b8..1f5ef3cd9 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -21,9 +21,13 @@ plugins { alias(libs.plugins.meshtastic.android.library.compose) alias(libs.plugins.meshtastic.android.library.flavors) alias(libs.plugins.meshtastic.hilt) + alias(libs.plugins.screenshot) } -configure { namespace = "org.meshtastic.core.ui" } +configure { + namespace = "org.meshtastic.core.ui" + experimentalProperties["android.experimental.enableScreenshotTest"] = true +} dependencies { implementation(projects.core.common) @@ -55,4 +59,7 @@ dependencies { androidTestImplementation(libs.androidx.test.runner) testImplementation(libs.junit) + + screenshotTestImplementation(libs.screenshot.validation.api) + screenshotTestImplementation(libs.androidx.compose.ui.tooling) } diff --git a/core/ui/src/screenshotTest/kotlin/org/meshtastic/core/ui/AlertScreenshotTest.kt b/core/ui/src/screenshotTest/kotlin/org/meshtastic/core/ui/AlertScreenshotTest.kt new file mode 100644 index 000000000..9a1c7ae6a --- /dev/null +++ b/core/ui/src/screenshotTest/kotlin/org/meshtastic/core/ui/AlertScreenshotTest.kt @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025-2026 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.meshtastic.core.ui + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import com.android.tools.screenshot.PreviewTest +import org.meshtastic.core.ui.util.PreviewTextAlert +import org.meshtastic.core.ui.util.PreviewIconAlert +import org.meshtastic.core.ui.util.PreviewHtmlAlert +import org.meshtastic.core.ui.util.PreviewMultipleChoiceAlert +import org.meshtastic.core.ui.util.PreviewComposableAlert + +class AlertScreenshotTest { + + @PreviewTest + @Preview(showBackground = true) + @Composable + fun TextAlert() { + PreviewTextAlert() + } + + @PreviewTest + @Preview(showBackground = true) + @Composable + fun IconAlert() { + PreviewIconAlert() + } + + @PreviewTest + @Preview(showBackground = true) + @Composable + fun HtmlAlert() { + PreviewHtmlAlert() + } + + @PreviewTest + @Preview(showBackground = true) + @Composable + fun MultipleChoiceAlert() { + PreviewMultipleChoiceAlert() + } + + @PreviewTest + @Preview(showBackground = true) + @Composable + fun ComposableAlert() { + PreviewComposableAlert() + } +} diff --git a/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/ComposableAlert_748aa731_0.png b/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/ComposableAlert_748aa731_0.png new file mode 100644 index 000000000..dfbcea318 Binary files /dev/null and b/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/ComposableAlert_748aa731_0.png differ diff --git a/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/HtmlAlert_748aa731_0.png b/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/HtmlAlert_748aa731_0.png new file mode 100644 index 000000000..e10f03b4b Binary files /dev/null and b/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/HtmlAlert_748aa731_0.png differ diff --git a/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/IconAlert_748aa731_0.png b/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/IconAlert_748aa731_0.png new file mode 100644 index 000000000..29a4c3004 Binary files /dev/null and b/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/IconAlert_748aa731_0.png differ diff --git a/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/MultipleChoiceAlert_748aa731_0.png b/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/MultipleChoiceAlert_748aa731_0.png new file mode 100644 index 000000000..7e54d473d Binary files /dev/null and b/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/MultipleChoiceAlert_748aa731_0.png differ diff --git a/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/TextAlert_748aa731_0.png b/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/TextAlert_748aa731_0.png new file mode 100644 index 000000000..0fd4fa050 Binary files /dev/null and b/core/ui/src/screenshotTestFdroidDebug/reference/org/meshtastic/core/ui/AlertScreenshotTest/TextAlert_748aa731_0.png differ diff --git a/gradle.properties b/gradle.properties index b0a71dbe3..34a83af3e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,6 +20,9 @@ android.useAndroidX=true dependency.analysis.print.build.health=true enableComposeCompilerMetrics=false enableComposeCompilerReports=false +android.experimental.enableScreenshotTest=true + +# Housekeeping kotlin.code.style=official kotlin.daemon.jvm.options=-Xmx4g -XX\:+UseParallelGC kotlin.parallel.tasks.in.project=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 48fe82c7c..67f952194 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -54,6 +54,7 @@ devtools-ksp = "2.3.6" markdownRenderer = "0.39.2" okio = "3.16.4" osmdroid-android = "6.1.20" +screenshot = "0.0.1-alpha13" spotless = "8.2.1" wire = "6.0.0-alpha02" vico = "3.0.2" @@ -180,6 +181,7 @@ androidx-test-espresso-core = { module = "androidx.test.espresso:espresso-core", junit = { module = "junit:junit", version = "4.13.2" } mockk = { module = "io.mockk:mockk", version.ref = "mockk" } robolectric = { module = "org.robolectric:robolectric", version = "4.16.1" } +screenshot-validation-api = { group = "com.android.tools.screenshot", name = "screenshot-validation-api", version.ref = "screenshot" } turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } # Other @@ -282,6 +284,7 @@ detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } wire = { id = "com.squareup.wire", version.ref = "wire" } room = { id = "androidx.room", version.ref = "room" } +screenshot = { id = "com.android.compose.screenshot", version.ref = "screenshot" } spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } test-retry = { id = "org.gradle.test-retry", version.ref = "testRetry" } dependency-guard = { id = "com.dropbox.dependency-guard", version.ref = "dependency-guard" }