diff --git a/compose/snippets/build.gradle.kts b/compose/snippets/build.gradle.kts index fbde90677..9f26b3a3f 100644 --- a/compose/snippets/build.gradle.kts +++ b/compose/snippets/build.gradle.kts @@ -165,6 +165,7 @@ dependencies { androidTestImplementation(libs.androidx.test.core) androidTestImplementation(libs.androidx.test.runner) androidTestImplementation(libs.androidx.test.espresso.core) + androidTestImplementation(libs.androidx.test.espresso.contrib) androidTestImplementation(libs.androidx.compose.ui.test) debugImplementation(libs.androidx.compose.ui.tooling) diff --git a/compose/snippets/src/androidTest/java/com/example/compose/snippets/test/TestSnippets.kt b/compose/snippets/src/androidTest/java/com/example/compose/snippets/test/TestSnippets.kt index 0676ded2e..1b72f1d3e 100644 --- a/compose/snippets/src/androidTest/java/com/example/compose/snippets/test/TestSnippets.kt +++ b/compose/snippets/src/androidTest/java/com/example/compose/snippets/test/TestSnippets.kt @@ -16,6 +16,7 @@ package com.example.compose.snippets.test +import android.view.View import androidx.compose.material3.Text import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -24,12 +25,23 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.v2.createComposeRule import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.onRootWithViewInteraction +import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runComposeUiTest +import androidx.recyclerview.widget.RecyclerView +import androidx.test.espresso.Espresso +import androidx.test.espresso.action.ViewActions.swipeLeft +import androidx.test.espresso.contrib.RecyclerViewActions +import androidx.test.espresso.matcher.ViewMatchers.hasDescendant +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText import kotlinx.coroutines.delay import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runTest +import org.hamcrest.CoreMatchers.allOf import org.junit.Rule import org.junit.Test @@ -84,3 +96,50 @@ class Test2 { } // [END android_compose_test_v2_apis] } + +@OptIn(ExperimentalTestApi::class) +class OnRootWithViewInteractionApiSnippets { + private val recyclerViewId = View.generateViewId() + private val rootViewId = View.generateViewId() + private val viewPagerViewId = View.generateViewId() + private val fragmentRootViewId = View.generateViewId() +// [START android_compose_test_onRootWithViewInteraction_api_1] + @Test + fun testComposeButtonInsideRecyclerViewItem() = runComposeUiTest { + // Scroll to the desired position using Espresso + Espresso.onView(withId(recyclerViewId)) + .perform(RecyclerViewActions.scrollToPosition(3)) + + // Define an Espresso ViewInteraction that uniquely identifies the row + val rowView = Espresso.onView( + allOf( + withId(rootViewId), + hasDescendant(withText("Item #3")) + ) + ) + + // Scope the Compose search strictly to that specific row View + onRootWithViewInteraction(rowView) + .onNode(hasText("Like")) + .performClick() + } +// [END android_compose_test_onRootWithViewInteraction_api_1] + +// [START android_compose_test_onRootWithViewInteraction_api_2] + @Test + fun testComposeButtonInsideViewPagerItem() = runComposeUiTest { + // Swipe to the desired page using Espresso + Espresso.onView(withId(viewPagerViewId)).perform(swipeLeft()) + + // Identify the specific container view using Espresso + val fragmentB = Espresso.onView(withId(fragmentRootViewId)) + + // The generic text "Save" is now unique within this view scope + onRootWithViewInteraction(fragmentB) + .onNode(hasText("Save")) + .assertIsDisplayed() + } +// [END android_compose_test_onRootWithViewInteraction_api_2] +} + +private class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) diff --git a/compose/snippets/src/main/java/com/example/compose/snippets/components/DatePickers.kt b/compose/snippets/src/main/java/com/example/compose/snippets/components/DatePickers.kt index 4d59ea4ef..f5dca89af 100644 --- a/compose/snippets/src/main/java/com/example/compose/snippets/components/DatePickers.kt +++ b/compose/snippets/src/main/java/com/example/compose/snippets/components/DatePickers.kt @@ -61,6 +61,7 @@ import com.example.compose.snippets.ui.theme.SnippetsTheme import java.text.SimpleDateFormat import java.util.Date import java.util.Locale +import androidx.compose.ui.platform.LocalLocale @Preview @Composable @@ -105,7 +106,7 @@ fun DatePickerExamples() { // [END_EXCLUDE] if (selectedDate != null) { val date = Date(selectedDate!!) - val formattedDate = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()).format(date) + val formattedDate = SimpleDateFormat("MMM dd, yyyy", LocalLocale.current.platformLocale).format(date) Text("Selected date: $formattedDate") } else { Text("No date selected") @@ -121,8 +122,8 @@ fun DatePickerExamples() { if (selectedDateRange.first != null && selectedDateRange.second != null) { val startDate = Date(selectedDateRange.first!!) val endDate = Date(selectedDateRange.second!!) - val formattedStartDate = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()).format(startDate) - val formattedEndDate = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()).format(endDate) + val formattedStartDate = SimpleDateFormat("MMM dd, yyyy", LocalLocale.current.platformLocale).format(startDate) + val formattedEndDate = SimpleDateFormat("MMM dd, yyyy", LocalLocale.current.platformLocale).format(endDate) Text("Selected date range: $formattedStartDate - $formattedEndDate") } else { Text("No date range selected") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 75e676435..167bd87cf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -47,7 +47,7 @@ appcompat = "1.7.1" coil = "2.7.0" # @keep compileSdk = "37" -compose-latest = "1.10.5" +compose-latest = "1.12.0-alpha01" composeUiTooling = "1.5.6" coreSplashscreen = "1.2.0" coroutines = "1.10.2" @@ -216,6 +216,7 @@ androidx-registry-provider-play-services = { module = "androidx.credentials.regi androidx-startup-runtime = { module = "androidx.startup:startup-runtime", version.ref = "androidx-startup-runtime" } androidx-test-core = { module = "androidx.test:core", version.ref = "androidx-test" } androidx-test-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-test-espresso" } +androidx-test-espresso-contrib = { module = "androidx.test.espresso:espresso-contrib", version.ref = "androidx-test-espresso" } androidx-test-ext-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-test-junit" } androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test" } androidx-tiles = { module = "androidx.wear.tiles:tiles", version.ref = "tiles" }