Last active
February 16, 2022 07:24
-
-
Save MeNiks/fa9efd83ca6f5f873a8ea8ba552fc0f1 to your computer and use it in GitHub Desktop.
Espresso UI Testing Extensions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.yourpackagename | |
import android.os.Environment | |
import android.view.View | |
import android.view.ViewGroup | |
import android.widget.EditText | |
import android.widget.TextView | |
import androidx.core.content.ContextCompat | |
import androidx.test.InstrumentationRegistry.getTargetContext | |
import androidx.test.espresso.Espresso | |
import androidx.test.espresso.PerformException | |
import androidx.test.espresso.UiController | |
import androidx.test.espresso.ViewAction | |
import androidx.test.espresso.ViewInteraction | |
import androidx.test.espresso.action.ViewActions | |
import androidx.test.espresso.assertion.ViewAssertions | |
import androidx.test.espresso.assertion.ViewAssertions.matches | |
import androidx.test.espresso.matcher.BoundedMatcher | |
import androidx.test.espresso.matcher.RootMatchers | |
import androidx.test.espresso.matcher.ViewMatchers | |
import androidx.test.uiautomator.UiDevice | |
import com.google.android.material.tabs.TabLayout | |
import com.google.android.material.textfield.TextInputLayout | |
import com.mindtickle.android.core.utils.ResourceHelper | |
import java.io.File | |
import org.hamcrest.Description | |
import org.hamcrest.Matcher | |
import org.hamcrest.Matchers | |
import org.hamcrest.Matchers.not | |
import org.hamcrest.TypeSafeMatcher | |
fun getView(id: Int, isDialog: Boolean = false): ViewInteraction { | |
val viewInteraction = Espresso.onView(ViewMatchers.withId(id)) | |
if (isDialog) | |
viewInteraction.inRoot(RootMatchers.isDialog()) | |
return viewInteraction | |
} | |
fun getView(text: String): ViewInteraction { | |
return Espresso.onView(ViewMatchers.withText(text)) | |
} | |
fun getView(parentId: Int, position: Int, childId: Int): ViewInteraction { | |
val parentMatcher = ViewMatchers.withId(parentId) | |
return Espresso.onView( | |
object : TypeSafeMatcher<View?>() { | |
override fun describeTo(description: Description) { | |
description.appendText("with $childId child view of type parentMatcher") | |
} | |
override fun matchesSafely(view: View?): Boolean { | |
view ?: return false | |
if (view.id != childId) | |
return false | |
val parentView: View? = view.rootView.findViewById(parentId) | |
if (parentView !is ViewGroup) { | |
return false | |
} | |
return parentMatcher.matches(parentView) && parentView.getChildAt(position).findViewById<View>(childId) == view | |
} | |
} | |
) | |
} | |
fun ViewInteraction.isVisible(): ViewInteraction { | |
return check(ViewAssertions.matches(ViewMatchers.isDisplayed())) | |
} | |
fun ViewInteraction.isEnabled(): ViewInteraction { | |
return check(ViewAssertions.matches(ViewMatchers.isEnabled())) | |
} | |
fun ViewInteraction.isDisabled(): ViewInteraction { | |
return check(ViewAssertions.matches(not(ViewMatchers.isEnabled()))) | |
} | |
fun ViewInteraction.isInvisible(): ViewInteraction { | |
return check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.INVISIBLE))) | |
} | |
fun ViewInteraction.isGone(): ViewInteraction { | |
return check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.GONE))) | |
} | |
fun ViewInteraction.hasString(resourceHelper: ResourceHelper, stringRes: Int): ViewInteraction { | |
return check(ViewAssertions.matches(ViewMatchers.withText(resourceHelper.getString(stringRes)))) | |
} | |
fun ViewInteraction.hasString(string: String): ViewInteraction { | |
return check(ViewAssertions.matches(ViewMatchers.withText(string))) | |
} | |
fun ViewInteraction.performClick(): ViewInteraction { | |
return perform(ViewActions.click()) | |
} | |
var enableScreenShot = false | |
fun takeScreenshot(fileName: String, uiDevice: UiDevice) { | |
if (!enableScreenShot) | |
return | |
val filePath = File(Environment.getExternalStorageDirectory().absolutePath + "/Pictures", "$fileName.png") | |
if (filePath.exists()) | |
filePath.delete() | |
uiDevice.takeScreenshot(filePath) | |
} | |
fun ViewInteraction.selectTabAtPosition(tabIndex: Int) { | |
perform( | |
object : ViewAction { | |
override fun getDescription() = "with tab at index $tabIndex" | |
override fun getConstraints() = Matchers.allOf(ViewMatchers.isDisplayed(), ViewMatchers.isAssignableFrom(TabLayout::class.java)) | |
override fun perform(uiController: UiController, view: View) { | |
val tabLayout = view as TabLayout | |
val tabAtIndex: TabLayout.Tab = tabLayout.getTabAt(tabIndex) | |
?: throw PerformException.Builder() | |
.withCause(Throwable("No tab at index $tabIndex")) | |
.build() | |
tabAtIndex.select() | |
} | |
} | |
) | |
} | |
fun ViewInteraction.hasHint(expectedHint: String): ViewInteraction { | |
return check(matches(object : TypeSafeMatcher<View>() { | |
override fun describeTo(description: Description) { | |
description.appendText("View has hint '$expectedHint'") | |
} | |
override fun matchesSafely(item: View?) = | |
item is TextInputLayout && expectedHint == item.hint || item is TextView && expectedHint == item.hint || item is EditText && expectedHint == item.hint | |
})) | |
} | |
fun ViewInteraction.hasError(expectedError: String?): ViewInteraction { | |
return check(matches(object : TypeSafeMatcher<View>() { | |
override fun describeTo(description: Description) { | |
description.appendText("View has Error '$expectedError'") | |
} | |
override fun matchesSafely(item: View?) = | |
item is TextInputLayout && expectedError == item.error || item is TextView && expectedError == item.error || item is EditText && expectedError == item.error | |
})) | |
} | |
fun ViewInteraction.matchesWithTextColor(color: Int): ViewInteraction? { | |
return check(matches(object : BoundedMatcher<View?, TextView>(TextView::class.java) { | |
override fun matchesSafely(textView: TextView): Boolean { | |
return ContextCompat.getColor(getTargetContext(), color) == textView.currentTextColor | |
} | |
override fun describeTo(description: Description) { | |
description.appendText("with text color: ") | |
} | |
})) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment