Issue#67 Extract ViewActions into Library
This commit is contained in:
parent
a27f19302a
commit
99141c0f17
12 changed files with 46 additions and 40 deletions
|
|
@ -31,7 +31,14 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
|
||||
|
||||
implementation "androidx.test:core:$androidx_test_version"
|
||||
implementation"androidx.test.espresso:espresso-core:$espresso_version"
|
||||
implementation "androidx.test.espresso:espresso-core:$espresso_version"
|
||||
implementation "androidx.test.espresso:espresso-intents:$espresso_version"
|
||||
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
|
||||
|
||||
implementation "com.google.android.material:material:$androidx_material_version"
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:$androidx_swiperefreshlayout_version"
|
||||
implementation "androidx.core:core-ktx:$androidx_core_version"
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package org.fnives.test.showcase.android.testutil.intent
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.test.espresso.intent.Intents.intended
|
||||
import org.hamcrest.Matcher
|
||||
import org.hamcrest.StringDescription
|
||||
|
||||
fun notIntended(matcher: Matcher<Intent>) {
|
||||
try {
|
||||
intended(matcher)
|
||||
} catch (assertionError: AssertionError) {
|
||||
return
|
||||
}
|
||||
val description = StringDescription()
|
||||
matcher.describeMismatch(null, description)
|
||||
throw IllegalStateException("Navigate to intent found matching $description")
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package org.fnives.test.showcase.android.testutil.snackbar
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.test.espresso.Espresso
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.ViewAction
|
||||
import androidx.test.espresso.action.ViewActions
|
||||
import androidx.test.espresso.assertion.ViewAssertions
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import com.google.android.material.R as MaterialR
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.hamcrest.Matcher
|
||||
import org.hamcrest.Matchers
|
||||
|
||||
object SnackbarVerificationHelper {
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
fun assertSnackBarIsShownWithText(@StringRes stringResID: Int, doDismiss: Boolean = true) {
|
||||
Espresso.onView(ViewMatchers.withId(MaterialR.id.snackbar_text))
|
||||
.check(ViewAssertions.matches(ViewMatchers.withText(stringResID)))
|
||||
if (doDismiss) {
|
||||
Espresso.onView(ViewMatchers.isAssignableFrom(Snackbar.SnackbarLayout::class.java)).perform(ViewActions.swipeRight())
|
||||
Espresso.onView(ViewMatchers.isRoot()).perform(LoopMainUntilSnackbarDismissed())
|
||||
}
|
||||
}
|
||||
|
||||
fun assertSnackBarIsNotShown() {
|
||||
Espresso.onView(ViewMatchers.withId(MaterialR.id.snackbar_text)).check(ViewAssertions.doesNotExist())
|
||||
}
|
||||
|
||||
class LoopMainUntilSnackbarDismissed : ViewAction {
|
||||
override fun getConstraints(): Matcher<View> = Matchers.isA(View::class.java)
|
||||
|
||||
override fun getDescription(): String = "loop MainThread until Snackbar is Dismissed"
|
||||
|
||||
override fun perform(uiController: UiController, view: View?) {
|
||||
while (view?.findViewById<View>(com.google.android.material.R.id.snackbar_text) != null) {
|
||||
uiController.loopMainThreadForAtLeast(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package org.fnives.test.showcase.android.testutil.viewaction.imageview
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.PorterDuff
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import org.hamcrest.Description
|
||||
import org.hamcrest.TypeSafeMatcher
|
||||
|
||||
class WithDrawable(
|
||||
@DrawableRes
|
||||
private val id: Int,
|
||||
@ColorRes
|
||||
private val tint: Int? = null,
|
||||
private val tintMode: PorterDuff.Mode = PorterDuff.Mode.SRC_IN
|
||||
) : TypeSafeMatcher<View>() {
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("ImageView with drawable same as drawable with id $id")
|
||||
tint?.let { description.appendText(", tint color id: $tint, mode: $tintMode") }
|
||||
}
|
||||
|
||||
override fun matchesSafely(view: View): Boolean {
|
||||
val context = view.context
|
||||
val tintColor = tint?.let { ContextCompat.getColor(view.context, it) }
|
||||
val expectedBitmap = ContextCompat.getDrawable(context, id)?.apply {
|
||||
if (tintColor != null) {
|
||||
setTintList(ColorStateList.valueOf(tintColor))
|
||||
setTintMode(tintMode)
|
||||
}
|
||||
}
|
||||
return view is ImageView && view.drawable.toBitmap().sameAs(expectedBitmap?.toBitmap())
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package org.fnives.test.showcase.android.testutil.viewaction.progressbar
|
||||
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.view.View
|
||||
import android.widget.ProgressBar
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.ViewAction
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
|
||||
import org.hamcrest.Matcher
|
||||
|
||||
class ReplaceProgressBarDrawableToStatic : ViewAction {
|
||||
override fun getConstraints(): Matcher<View> =
|
||||
isAssignableFrom(ProgressBar::class.java)
|
||||
|
||||
override fun getDescription(): String =
|
||||
"replace the ProgressBar drawable"
|
||||
|
||||
override fun perform(uiController: UiController, view: View) {
|
||||
val progressBar: ProgressBar = view as ProgressBar
|
||||
progressBar.indeterminateDrawable = ColorDrawable(Color.GREEN)
|
||||
uiController.loopMainThreadUntilIdle()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package org.fnives.test.showcase.android.testutil.viewaction.swiperefresh
|
||||
|
||||
import android.view.View
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import androidx.swiperefreshlayout.widget.listener
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.ViewAction
|
||||
import org.fnives.test.showcase.android.testutil.synchronization.runOnUIAwaitOnCurrent
|
||||
import org.hamcrest.BaseMatcher
|
||||
import org.hamcrest.CoreMatchers.isA
|
||||
import org.hamcrest.Description
|
||||
import org.hamcrest.Matcher
|
||||
|
||||
// swipe-refresh-layout swipe-down doesn't work, inspired by https://github.com/robolectric/robolectric/issues/5375
|
||||
class PullToRefresh : ViewAction {
|
||||
|
||||
override fun getConstraints(): Matcher<View> {
|
||||
return object : BaseMatcher<View>() {
|
||||
override fun matches(item: Any): Boolean {
|
||||
return isA(SwipeRefreshLayout::class.java).matches(item)
|
||||
}
|
||||
|
||||
override fun describeMismatch(item: Any, mismatchDescription: Description) {
|
||||
mismatchDescription.appendText("Expected SwipeRefreshLayout or its Descendant, but got other View")
|
||||
}
|
||||
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("Action SwipeToRefresh to view SwipeRefreshLayout or its descendant")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDescription(): String {
|
||||
return "Perform pull-to-refresh on the SwipeRefreshLayout"
|
||||
}
|
||||
|
||||
override fun perform(uiController: UiController, view: View) {
|
||||
val swipeRefreshLayout = view as SwipeRefreshLayout
|
||||
runOnUIAwaitOnCurrent {
|
||||
swipeRefreshLayout.isRefreshing = true
|
||||
swipeRefreshLayout.listener().onRefresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
@file:Suppress("PackageDirectoryMismatch")
|
||||
|
||||
package androidx.swiperefreshlayout.widget
|
||||
|
||||
fun SwipeRefreshLayout.listener() = mListener
|
||||
Loading…
Add table
Add a link
Reference in a new issue