diff --git a/.github/renovate.json b/.github/renovate.json index c9993abac..0a4ddeab0 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -71,7 +71,6 @@ "!/^androidx\\.compose\\.material3:material3-adaptive-navigation-suite$/", "!/^androidx\\.test\\.espresso/", "!/^androidx\\.test\\.ext/", - "!/^androidx\\.compose\\.ui:ui-test-junit4$/", "!/^androidx\\.hilt/" ] }, @@ -118,8 +117,7 @@ "groupSlug": "androidx-testing", "matchPackageNames": [ "/^androidx\\.test\\.espresso/", - "/^androidx\\.test\\.ext/", - "/^androidx\\.compose\\.ui:ui-test-junit4$/" + "/^androidx\\.test\\.ext/" ], "automerge": true }, diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2005e9320..0942756c0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -305,7 +305,7 @@ dependencies { testImplementation(libs.kotlinx.coroutines.test) testImplementation(libs.robolectric) testImplementation(libs.androidx.test.core) - testImplementation(libs.androidx.compose.ui.test.junit4) + testImplementation(libs.compose.multiplatform.ui.test) testImplementation(libs.androidx.test.ext.junit) testImplementation(libs.androidx.glance.appwidget) } diff --git a/app/src/test/kotlin/org/meshtastic/app/ui/NavigationAssemblyTest.kt b/app/src/test/kotlin/org/meshtastic/app/ui/NavigationAssemblyTest.kt index 0665d50db..de6062d33 100644 --- a/app/src/test/kotlin/org/meshtastic/app/ui/NavigationAssemblyTest.kt +++ b/app/src/test/kotlin/org/meshtastic/app/ui/NavigationAssemblyTest.kt @@ -16,12 +16,12 @@ */ package org.meshtastic.app.ui -import androidx.compose.ui.test.junit4.v2.createComposeRule +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.runComposeUiTest import androidx.navigation3.runtime.NavKey import androidx.navigation3.runtime.entryProvider import androidx.navigation3.runtime.rememberNavBackStack import kotlinx.coroutines.flow.emptyFlow -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.meshtastic.core.navigation.NodesRoute @@ -35,15 +35,14 @@ import org.meshtastic.feature.settings.radio.channel.channelsGraph import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config +@OptIn(ExperimentalTestApi::class) @RunWith(RobolectricTestRunner::class) @Config(sdk = [34]) class NavigationAssemblyTest { - @get:Rule val composeTestRule = createComposeRule() - @Test - fun verifyNavigationGraphsAssembleWithoutCrashing() { - composeTestRule.setContent { + fun verifyNavigationGraphsAssembleWithoutCrashing() = runComposeUiTest { + setContent { val backStack = rememberNavBackStack(NodesRoute.NodesGraph) entryProvider { contactsGraph(backStack, emptyFlow()) diff --git a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt index 1d4e2ea56..0768629fc 100644 --- a/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt +++ b/build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/AndroidCompose.kt @@ -24,6 +24,24 @@ import org.gradle.kotlin.dsl.dependencies internal fun Project.configureAndroidCompose(commonExtension: CommonExtension) { commonExtension.apply { buildFeatures.compose = true } + // CMP skips Android version enforcement; third-party BOMs and atomic-group alignment + // can silently override AndroidX Compose versions. Force core groups to the CMP version. + // Material/Material3 excluded — CMP maps those to different AndroidX version numbers. + val cmpVersion = libs.version("compose-multiplatform") + val cmpAlignedGroups = setOf( + "androidx.compose.animation", + "androidx.compose.foundation", + "androidx.compose.runtime", + "androidx.compose.ui", + ) + configurations.configureEach { + resolutionStrategy.eachDependency { + if (requested.group in cmpAlignedGroups) { + useVersion(cmpVersion) + } + } + } + val hasAndroidTest = project.projectDir.resolve("src/androidTest").exists() dependencies { "debugImplementation"(libs.library("compose-multiplatform-ui-tooling")) diff --git a/core/barcode/build.gradle.kts b/core/barcode/build.gradle.kts index c8dbc078e..711cccc09 100644 --- a/core/barcode/build.gradle.kts +++ b/core/barcode/build.gradle.kts @@ -52,6 +52,6 @@ dependencies { testImplementation(libs.junit) testRuntimeOnly(libs.junit.vintage.engine) testImplementation(libs.robolectric) - testImplementation(libs.androidx.compose.ui.test.junit4) + testImplementation(libs.compose.multiplatform.ui.test) debugImplementation(libs.androidx.compose.ui.test.manifest) } diff --git a/core/barcode/src/test/kotlin/org/meshtastic/core/barcode/BarcodeScannerTest.kt b/core/barcode/src/test/kotlin/org/meshtastic/core/barcode/BarcodeScannerTest.kt index e06562cfb..aa222b7c2 100644 --- a/core/barcode/src/test/kotlin/org/meshtastic/core/barcode/BarcodeScannerTest.kt +++ b/core/barcode/src/test/kotlin/org/meshtastic/core/barcode/BarcodeScannerTest.kt @@ -16,21 +16,17 @@ */ package org.meshtastic.core.barcode -import androidx.compose.ui.test.junit4.v2.createComposeRule -import org.junit.Rule +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.runComposeUiTest import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config +@OptIn(ExperimentalTestApi::class) @RunWith(RobolectricTestRunner::class) @Config(sdk = [34]) class BarcodeScannerTest { - @get:Rule val composeTestRule = createComposeRule() - - @Test - fun testRememberBarcodeScanner() { - composeTestRule.setContent { rememberBarcodeScanner { _ -> } } - } + @Test fun testRememberBarcodeScanner() = runComposeUiTest { setContent { rememberBarcodeScanner { _ -> } } } } diff --git a/desktop/build.gradle.kts b/desktop/build.gradle.kts index 14075fbda..df5122a4d 100644 --- a/desktop/build.gradle.kts +++ b/desktop/build.gradle.kts @@ -256,6 +256,7 @@ dependencies { // Compose Desktop implementation(compose.desktop.currentOs) + implementation(libs.compose.multiplatform.animation) implementation(libs.compose.multiplatform.material3) implementation(libs.compose.multiplatform.runtime) implementation(libs.compose.multiplatform.foundation) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c62bda180..dc9d0fe2d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,6 @@ appcompat = "1.7.1" accompanist = "0.37.3" # androidx -androidxTracing = "1.10.6" datastore = "1.2.1" glance = "1.2.0-rc01" lifecycle = "2.10.0" @@ -118,11 +117,10 @@ androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version = androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version = "2.11.2" } androidx-work-testing = { module = "androidx.work:work-testing", version = "2.11.2" } -# AndroidX Compose (explicit versions — BOM removed to avoid transitive compileSdk conflicts with CMP adaptive fork) +# AndroidX Compose (explicit versions — BOM removed; CMP is the sole version authority) androidx-compose-material-iconsExtended = { module = "androidx.compose.material:material-icons-extended", version = "1.7.8" } # Only used by deprecated mesh_service_example — remove when that module is deleted -androidx-compose-runtime-tracing = { module = "androidx.compose.runtime:runtime-tracing", version.ref = "androidxTracing" } -androidx-compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version = "1.11.0-rc01" } -androidx-compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version = "1.11.0-rc01" } +androidx-compose-runtime-tracing = { module = "androidx.compose.runtime:runtime-tracing", version.ref = "compose-multiplatform" } +androidx-compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "compose-multiplatform" } # Required by Robolectric Compose tests (registers ComponentActivity) # Compose Multiplatform compose-multiplatform-animation = { module = "org.jetbrains.compose.animation:animation", version.ref = "compose-multiplatform" }