diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aadcc5fc..f70a466e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -# Copyright 2020 Google LLC +# Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -45,3 +45,13 @@ jobs: - name: Build modules run: ./gradlew build jacocoTestReport --stacktrace + + - name: Run Screenshot Tests + run: ./gradlew validateDebugScreenshotTest + + - name: Upload build reports + uses: actions/upload-artifact@v4 + if: always() + with: + name: my-artifact + path: app/build/reports diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 093812ac..030af4ca 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,6 +3,7 @@ plugins { id("kotlin-android") id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") alias(libs.plugins.compose.compiler) + alias(libs.plugins.screenshot) } android { @@ -46,6 +47,14 @@ android { jvmTarget = "1.8" freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" } + + experimentalProperties["android.experimental.enableScreenshotTest"] = true + + testOptions { + screenshotTests { + imageDifferenceThreshold = 0.035f // 3.5% + } + } } dependencies { @@ -68,6 +77,8 @@ dependencies { androidTestImplementation(libs.androidx.test.compose.ui) androidTestImplementation(libs.kotlinx.coroutines.test) + screenshotTestImplementation(libs.androidx.compose.ui.tooling) + // Instead of the lines below, regular apps would load these libraries from Maven according to // the README installation instructions implementation(project(":maps-compose")) diff --git a/app/src/debug/screenshotTest/reference/com/google/maps/android/compose/ScaleBarTest/PreviewDisappearingScaleBar_0.png b/app/src/debug/screenshotTest/reference/com/google/maps/android/compose/ScaleBarTest/PreviewDisappearingScaleBar_0.png new file mode 100644 index 00000000..ffaf22e7 Binary files /dev/null and b/app/src/debug/screenshotTest/reference/com/google/maps/android/compose/ScaleBarTest/PreviewDisappearingScaleBar_0.png differ diff --git a/app/src/debug/screenshotTest/reference/com/google/maps/android/compose/ScaleBarTest/PreviewScaleBar_0.png b/app/src/debug/screenshotTest/reference/com/google/maps/android/compose/ScaleBarTest/PreviewScaleBar_0.png new file mode 100644 index 00000000..ffaf22e7 Binary files /dev/null and b/app/src/debug/screenshotTest/reference/com/google/maps/android/compose/ScaleBarTest/PreviewScaleBar_0.png differ diff --git a/app/src/main/java/com/google/maps/android/compose/ScaleBarActivity.kt b/app/src/main/java/com/google/maps/android/compose/ScaleBarActivity.kt index 172632b6..ba7d72b5 100644 --- a/app/src/main/java/com/google/maps/android/compose/ScaleBarActivity.kt +++ b/app/src/main/java/com/google/maps/android/compose/ScaleBarActivity.kt @@ -31,13 +31,18 @@ import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.google.android.gms.maps.model.CameraPosition +import com.google.android.gms.maps.model.LatLng +import com.google.maps.android.compose.theme.MapsComposeSampleTheme import com.google.maps.android.compose.widgets.DarkGray import com.google.maps.android.compose.widgets.DisappearingScaleBar import com.google.maps.android.compose.widgets.ScaleBar @@ -126,4 +131,26 @@ class ScaleBarActivity : ComponentActivity() { } } } +} + +@Preview +@Composable +fun PreviewScaleBar() { + val cameraPositionState = remember { + CameraPositionState( + position = CameraPosition( + LatLng(48.137154, 11.576124), // Example coordinates: Munich, Germany + 12f, + 0f, + 0f + ) + ) + } + + MapsComposeSampleTheme { + ScaleBar( + modifier = Modifier.padding(end = 4.dp), + cameraPositionState = cameraPositionState + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/google/maps/android/compose/markerexamples/MarkerClusteringActivity.kt b/app/src/main/java/com/google/maps/android/compose/markerexamples/MarkerClusteringActivity.kt index 77ff5cce..56857f01 100644 --- a/app/src/main/java/com/google/maps/android/compose/markerexamples/MarkerClusteringActivity.kt +++ b/app/src/main/java/com/google/maps/android/compose/markerexamples/MarkerClusteringActivity.kt @@ -42,6 +42,7 @@ import com.google.android.gms.maps.model.CameraPosition import com.google.android.gms.maps.model.LatLng import com.google.maps.android.clustering.ClusterItem import com.google.maps.android.clustering.algo.NonHierarchicalViewBasedAlgorithm +import com.google.maps.android.clustering.view.DefaultClusterRenderer import com.google.maps.android.compose.GoogleMap import com.google.maps.android.compose.MapsComposeExperimentalApi import com.google.maps.android.compose.MarkerInfoWindow @@ -218,6 +219,7 @@ fun CustomRendererClustering(items: List) { }, clusterManager = clusterManager, ) + SideEffect { clusterManager ?: return@SideEffect clusterManager.setOnClusterClickListener { diff --git a/app/src/screenshotTest/java/com/google/maps/android/compose/ScaleBarTest.kt b/app/src/screenshotTest/java/com/google/maps/android/compose/ScaleBarTest.kt new file mode 100644 index 00000000..c27c439b --- /dev/null +++ b/app/src/screenshotTest/java/com/google/maps/android/compose/ScaleBarTest.kt @@ -0,0 +1,60 @@ +package com.google.maps.android.compose + +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.google.android.gms.maps.model.CameraPosition +import com.google.android.gms.maps.model.LatLng +import com.google.maps.android.compose.theme.MapsComposeSampleTheme +import com.google.maps.android.compose.widgets.DisappearingScaleBar +import com.google.maps.android.compose.widgets.ScaleBar + + +class ScaleBarTest() { + @Preview + @Composable + fun PreviewScaleBar() { + val cameraPositionState = remember { + CameraPositionState( + position = CameraPosition( + LatLng(48.137154, 11.576124), // Example coordinates: Munich, Germany + 12f, + 0f, + 0f + ) + ) + } + + MapsComposeSampleTheme { + ScaleBar( + modifier = Modifier.padding(end = 4.dp), + cameraPositionState = cameraPositionState + ) + } + } + + @Preview + @Composable + fun PreviewDisappearingScaleBar() { + val cameraPositionState = remember { + CameraPositionState( + position = CameraPosition( + LatLng(48.137154, 11.576124), // Example coordinates: Munich, Germany + 12f, + 0f, + 0f + ) + ) + } + + MapsComposeSampleTheme { + DisappearingScaleBar( + modifier = Modifier.padding(end = 4.dp), + cameraPositionState = cameraPositionState + ) + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 96145c06..0ed08c6d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,4 +31,6 @@ sonatypeToken= sonatypeTokenPassword= android.nonTransitiveRClass=false -android.nonFinalResIds=false \ No newline at end of file +android.nonFinalResIds=false + +android.experimental.enableScreenshotTest=true \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fb4daa73..027597b8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,8 +1,9 @@ [versions] activitycompose = "1.9.3" agp = "8.7.2" -androidxtest = "1.6.1" -compose-bom = "2024.10.01" +androidxtest = "1.6.2" +androidCore = "1.6.1" +compose-bom = "2024.11.00" dokka = "1.9.20" espresso = "3.6.1" jacoco-plugin = "0.2.1" @@ -14,6 +15,7 @@ mapsktx = "5.1.1" mapsecrets = "2.0.1" org-jacoco-core = "0.8.11" androidx-core = "1.15.0" +screenshot = "0.0.1-alpha08" [libraries] android-gradle-plugin = { module = "com.android.tools.build:gradle", version.ref = "agp" } @@ -26,10 +28,10 @@ androidx-compose-ui-preview-tooling = { module = "androidx.compose.ui:ui-tooling androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" } androidx-test-compose-ui = { module = "androidx.compose.ui:ui-test-junit4" } -androidx-test-core = { module = "androidx.test:core", version.ref = "androidxtest" } +androidx-test-core = { module = "androidx.test:core", version.ref = "androidCore" } androidx-test-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" } androidx-test-junit-ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "junitktx" } -androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidxtest" } +androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidCore" } androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidxtest" } dokka-plugin = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" } jacoco-android-plugin = { module = "com.mxalbert.gradle:jacoco-android", version.ref = "jacoco-plugin", version.require = "0.2.1" } @@ -45,4 +47,5 @@ test-junit = { module = "junit:junit", version.ref = "junit" } [plugins] dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } -compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } \ No newline at end of file +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +screenshot = { id = "com.android.compose.screenshot", version.ref = "screenshot"} \ No newline at end of file