diff --git a/ui/espresso/RecyclerViewSample/app/build.gradle b/ui/espresso/RecyclerViewSample/app/build.gradle index abc7ba7b9..17328232f 100644 --- a/ui/espresso/RecyclerViewSample/app/build.gradle +++ b/ui/espresso/RecyclerViewSample/app/build.gradle @@ -16,6 +16,10 @@ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +apply plugin: 'kotlin-android-extensions' + android { compileSdkVersion 30 buildToolsVersion rootProject.buildToolsVersion @@ -40,6 +44,12 @@ android { } } +tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { + kotlinOptions { + jvmTarget = "1.8" + } +} + dependencies { // App dependencies implementation 'androidx.annotation:annotation:' + rootProject.androidxAnnotationVersion; @@ -47,8 +57,11 @@ dependencies { implementation 'androidx.multidex:multidex:2.0.1' // Testing-only dependencies + androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"; androidTestImplementation 'androidx.test:core:' + rootProject.coreVersion; + androidTestImplementation 'androidx.test:core-ktx:' + rootProject.coreVersion; androidTestImplementation 'androidx.test.ext:junit:' + rootProject.extJUnitVersion; + androidTestImplementation 'androidx.test.ext:junit-ktx:' + rootProject.extJUnitVersion; androidTestImplementation 'androidx.test:runner:' + rootProject.runnerVersion; androidTestImplementation 'androidx.test.espresso:espresso-core:' + rootProject.espressoVersion; androidTestImplementation 'androidx.test.espresso:espresso-contrib:' + rootProject.espressoVersion; diff --git a/ui/espresso/RecyclerViewSample/app/src/androidTest/java/com/example/android/testing/espresso/RecyclerViewSample/RecyclerViewSampleKtTest.kt b/ui/espresso/RecyclerViewSample/app/src/androidTest/java/com/example/android/testing/espresso/RecyclerViewSample/RecyclerViewSampleKtTest.kt new file mode 100644 index 000000000..d954e5756 --- /dev/null +++ b/ui/espresso/RecyclerViewSample/app/src/androidTest/java/com/example/android/testing/espresso/RecyclerViewSample/RecyclerViewSampleKtTest.kt @@ -0,0 +1,81 @@ +package com.example.android.testing.espresso.RecyclerViewSample + +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.PerformException +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.RecyclerViewActions +import androidx.test.espresso.matcher.ViewMatchers.* +import androidx.test.ext.junit.rules.activityScenarioRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import org.hamcrest.Description +import org.hamcrest.Matcher +import org.hamcrest.TypeSafeMatcher +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@LargeTest +class RecyclerViewSampleKtTest { + + /** + * Use {@link ActivityScenario} to create and launch the activity under test. This is a + * replacement for {@link androidx.test.rule.ActivityTestRule}. + */ + @get:Rule + var activityScenarioRule = activityScenarioRule() + + @Test(expected = PerformException::class) + fun itemWithText_doesNotExist() { + // Attempt to scroll to an item that contains the special text. + onView(withId(R.id.recyclerView)) + // scrollTo will fail the test if no item matches. + .perform(RecyclerViewActions.scrollTo( + hasDescendant(withText("not in the list")) + )) + } + + @Test + fun scrollToItemBelowFold_checkItsText() { + // First scroll to the position that needs to be matched and click on it. + onView(withId(R.id.recyclerView)) + .perform(RecyclerViewActions.actionOnItemAtPosition(ITEM_BELOW_THE_FOLD, click())) + + // Match the text in an item below the fold and check that it's displayed. + val itemElementText = "This is element #${ITEM_BELOW_THE_FOLD}" + onView(withText(itemElementText)).check(matches(isDisplayed())) + } + + @Test + fun itemInMiddleOfList_hasSpecialText() { + // First, scroll to the view holder using the isInTheMiddle matcher. + onView(withId(R.id.recyclerView)) + .perform(RecyclerViewActions.scrollToHolder(isInTheMiddle())) + + // Check that the item has the special text. + val middleElementText = "This is the middle!" + onView(withText(middleElementText)).check(matches(isDisplayed())) + } + + /** + * Matches the {@link CustomAdapter.ViewHolder}s in the middle of the list. + */ + private fun isInTheMiddle(): Matcher { + return object: TypeSafeMatcher() { + override fun matchesSafely(customHolder: CustomAdapter.ViewHolder): Boolean { + return customHolder.isInTheMiddle + } + + override fun describeTo(description: Description) { + description.appendText("item in the middle") + } + } + } + + companion object { + val ITEM_BELOW_THE_FOLD = 40 + } + +} \ No newline at end of file diff --git a/ui/espresso/RecyclerViewSample/build.gradle b/ui/espresso/RecyclerViewSample/build.gradle index 0e31c8118..4a8097aeb 100644 --- a/ui/espresso/RecyclerViewSample/build.gradle +++ b/ui/espresso/RecyclerViewSample/build.gradle @@ -17,6 +17,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlinVersion = "1.6.10" ext.agpVersion = "7.3.0-alpha07" repositories { // Insert local test repo here @@ -25,6 +26,7 @@ buildscript { } dependencies { classpath "com.android.tools.build:gradle:$agpVersion" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files