Skip to content

Commit

Permalink
Introduce generic assertAnyView function (#198)
Browse files Browse the repository at this point in the history
* Extract ugly try/catch code to a magicAssertOnView function and use it

I also created some infix extension functions to make it even easier to write. It extends any Matcher<View>, String or Int (resource).
I added a `not` operator to Matcher<View>.
I documented the behaviour the best I could.

I replaced the in-site code with this function, and applied it to other methods of the BaristaVisibilityAssertions that were not doing any magic.

* Rename and improve error message of BaristaArgumentTypeException

* Apply magicAssert to EnabledAssertions

* Apply magicAsset on CheckedAssertions

* Apply magicAssert to BackgroundAssertions

* Apply magicAssert to FocusedAssertions

* Apply magicAssert to HintAssertions

* Apply magicAssert to ImageViewAssertions

* Extract assertion attempts to methods

* Remove  operator for matchers

* Simplify magicAssert api

* Rename to assertAny
  • Loading branch information
Sloy authored Mar 1, 2018
1 parent 6bd0a27 commit b720c50
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,26 @@ package com.schibsted.spain.barista.assertion

import android.support.annotation.DrawableRes
import android.support.annotation.IdRes
import android.support.test.espresso.Espresso
import android.support.test.espresso.Espresso.*
import android.support.test.espresso.assertion.ViewAssertions
import android.support.test.espresso.assertion.ViewAssertions.*
import android.support.test.espresso.matcher.ViewMatchers
import com.schibsted.spain.barista.internal.matcher.BackgroundMatcher
import com.schibsted.spain.barista.internal.matcher.DrawableMatcher
import com.schibsted.spain.barista.internal.assertAny
import com.schibsted.spain.barista.internal.matcher.BackgroundMatcher.Companion.withAnyBackground
import com.schibsted.spain.barista.internal.matcher.BackgroundMatcher.Companion.withBackground
import com.schibsted.spain.barista.internal.matcher.BackgroundMatcher.Companion.withoutBackground
import com.schibsted.spain.barista.internal.util.resourceMatcher

object BaristaBackgroundAssertions {

@JvmStatic
fun assertHasBackground(@IdRes id: Int, @DrawableRes drawable: Int) {
onView(ViewMatchers.withId(id)).check(matches(BackgroundMatcher.withBackground(drawable)))
}
@JvmStatic
fun assertHasBackground(@IdRes viewId: Int, @DrawableRes drawable: Int) {
viewId.resourceMatcher().assertAny(withBackground(drawable))
}

@JvmStatic
fun assertHasAnyBackground(@IdRes id: Int) {
onView(ViewMatchers.withId(id)).check(matches(BackgroundMatcher.withAnyBackground()))
}
@JvmStatic
fun assertHasAnyBackground(@IdRes viewId: Int) {
viewId.resourceMatcher().assertAny(withAnyBackground())
}

@JvmStatic
fun assertHasNoBackground(@IdRes id: Int) {
onView(ViewMatchers.withId(id)).check(matches(BackgroundMatcher.withoutBackground()))
}
@JvmStatic
fun assertHasNoBackground(@IdRes viewId: Int) {
viewId.resourceMatcher().assertAny(withoutBackground())
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
package com.schibsted.spain.barista.assertion

import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.*
import android.support.test.espresso.matcher.ViewMatchers.isChecked
import android.support.test.espresso.matcher.ViewMatchers.withText
import com.schibsted.spain.barista.internal.assertAny
import com.schibsted.spain.barista.internal.util.resourceMatcher
import org.hamcrest.Matchers.not

object BaristaCheckedAssertions {

@JvmStatic
fun assertChecked(resId: Int) {
onView(resId.resourceMatcher()).check(matches(isChecked()))
resId.resourceMatcher().assertAny(isChecked())
}

@JvmStatic
fun assertChecked(text: String) {
onView(withText(text)).check(matches(isChecked()))
withText(text).assertAny(isChecked())
}

@JvmStatic
fun assertUnchecked(resId: Int) {
onView(resId.resourceMatcher()).check(matches(isNotChecked()))
resId.resourceMatcher().assertAny(not(isChecked()))
}

@JvmStatic
fun assertUnchecked(text: String) {
onView(withText(text)).check(matches(isNotChecked()))
withText(text).assertAny(not(isChecked()))
}
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
package com.schibsted.spain.barista.assertion

import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.isEnabled
import android.support.test.espresso.matcher.ViewMatchers.withText
import com.schibsted.spain.barista.internal.assertAny
import com.schibsted.spain.barista.internal.util.resourceMatcher
import org.hamcrest.core.IsNot.not
import org.hamcrest.Matchers.not

object BaristaEnabledAssertions {

@JvmStatic
fun assertEnabled(resId: Int) {
onView(resId.resourceMatcher()).check(matches(isEnabled()))
resId.resourceMatcher().assertAny(isEnabled())
}

@JvmStatic
fun assertEnabled(text: String) {
onView(withText(text)).check(matches(isEnabled()))
withText(text).assertAny(isEnabled())
}

@JvmStatic
fun assertDisabled(resId: Int) {
onView(resId.resourceMatcher()).check(matches(not(isEnabled())))
resId.resourceMatcher().assertAny(not(isEnabled()))
}

@JvmStatic
fun assertDisabled(text: String) {
onView(withText(text)).check(matches(not(isEnabled())))
withText(text).assertAny(not(isEnabled()))
}
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
package com.schibsted.spain.barista.assertion

import android.support.annotation.IdRes
import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.hasFocus
import android.support.test.espresso.matcher.ViewMatchers.withText
import com.schibsted.spain.barista.internal.assertAny
import com.schibsted.spain.barista.internal.util.resourceMatcher
import org.hamcrest.core.IsNot.not
import org.hamcrest.Matchers.not

object BaristaFocusedAssertions {

@JvmStatic
fun assertFocused(@IdRes resId: Int) {
onView(resId.resourceMatcher()).check(matches(hasFocus()))
fun assertFocused(resId: Int) {
resId.resourceMatcher().assertAny(hasFocus())
}

@JvmStatic
fun assertNotFocused(@IdRes resId: Int) {
onView(resId.resourceMatcher()).check(matches(not(hasFocus())))
resId.resourceMatcher().assertAny(not(hasFocus()))
}

@JvmStatic
fun assertFocused(text: String) {
onView(withText(text)).check(matches(hasFocus()))
withText(text).assertAny(hasFocus())
}

@JvmStatic
fun assertNotFocused(text: String) {
onView(withText(text)).check(matches(not(hasFocus())))
withText(text).assertAny(not(hasFocus()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@ package com.schibsted.spain.barista.assertion

import android.support.annotation.IdRes
import android.support.annotation.StringRes
import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.withHint
import android.support.test.espresso.matcher.ViewMatchers.withId
import com.schibsted.spain.barista.internal.assertAny

object BaristaHintAssertions {

@JvmStatic
fun assertHint(@IdRes id: Int, @StringRes text: Int) {
onView(withId(id)).check(matches(withHint(text)))
fun assertHint(@IdRes viewId: Int, @StringRes text: Int) {
withId(viewId).assertAny(withHint(text))
}

@JvmStatic
fun assertHint(@IdRes id: Int, text: String) {
onView(withId(id)).check(matches(withHint(text)))
fun assertHint(@IdRes viewId: Int, text: String) {
withId(viewId).assertAny(withHint(text))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package com.schibsted.spain.barista.assertion

import android.support.annotation.DrawableRes
import android.support.annotation.IdRes
import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.withId
import com.schibsted.spain.barista.internal.assertAny
import com.schibsted.spain.barista.internal.matcher.DrawableMatcher.Companion.withAnyDrawable
import com.schibsted.spain.barista.internal.matcher.DrawableMatcher.Companion.withDrawable
import com.schibsted.spain.barista.internal.matcher.DrawableMatcher.Companion.withoutDrawable
Expand All @@ -13,16 +12,16 @@ object BaristaImageViewAssertions {

@JvmStatic
fun assertHasDrawable(@IdRes imageViewId: Int, @DrawableRes drawable: Int) {
onView(withId(imageViewId)).check(matches(withDrawable(drawable)))
withId(imageViewId).assertAny(withDrawable(drawable))
}

@JvmStatic
fun assertHasAnyDrawable(@IdRes imageViewId: Int) {
onView(withId(imageViewId)).check(matches(withAnyDrawable()))
withId(imageViewId).assertAny(withAnyDrawable())
}

@JvmStatic
fun assertHasNoDrawable(@IdRes imageViewId: Int) {
onView(withId(imageViewId)).check(matches(withoutDrawable()))
withId(imageViewId).assertAny(withoutDrawable())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,31 @@ package com.schibsted.spain.barista.assertion

import android.support.annotation.ColorRes
import android.support.annotation.IdRes
import android.support.test.espresso.AmbiguousViewMatcherException
import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.NoMatchingViewException
import android.support.test.espresso.assertion.ViewAssertions.doesNotExist
import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.*
import android.view.View
import com.schibsted.spain.barista.internal.failurehandler.SpyFailureHandler
import com.schibsted.spain.barista.internal.failurehandler.description
import com.schibsted.spain.barista.internal.matcher.HelperMatchers
import com.schibsted.spain.barista.internal.assertAny
import com.schibsted.spain.barista.internal.matcher.TextColorMatcher
import com.schibsted.spain.barista.internal.util.resourceMatcher
import org.hamcrest.CoreMatchers.containsString
import org.hamcrest.Matcher
import org.hamcrest.Matchers.allOf
import org.hamcrest.core.IsNot.not
import org.hamcrest.Matchers.not

object BaristaVisibilityAssertions {

@JvmStatic
fun assertDisplayed(resId: Int) {
assertDisplayed(resId.resourceMatcher())
fun assertDisplayed(viewId: Int) {
viewId.resourceMatcher().assertAny(isDisplayed())
}

@JvmStatic
fun assertDisplayed(text: String) {
assertDisplayed(withText(text))
withText(text).assertAny(isDisplayed())
}

@JvmStatic
fun assertDisplayed(@IdRes resId: Int, text: String) {
onView(withId(resId)).check(matches(withText(text)))
}

/**
* Attempts to find the view with multiple conditions:
* 1. Simplest case
* 2. More than one view
*/
private fun assertDisplayed(matcher: Matcher<View>) {
val spyFailureHandler = SpyFailureHandler()
try {
onView(matcher)
.withFailureHandler(spyFailureHandler)
.check(matches(isDisplayed()))
} catch (firstError: RuntimeException) {
try {
onView(HelperMatchers.firstViewOf(allOf(matcher, isDisplayed())))
.withFailureHandler(spyFailureHandler)
.check(matches(isDisplayed()))
} catch (secondError: RuntimeException) {
spyFailureHandler.resendFirstError("View ${matcher.description()} wasn't displayed on the screen")
}
}
fun assertDisplayed(@IdRes viewId: Int, text: String) {
viewId.resourceMatcher().assertAny(withText(text))
}

@JvmStatic
Expand All @@ -69,28 +40,28 @@ object BaristaVisibilityAssertions {
}

@JvmStatic
fun assertNotDisplayed(resId: Int) {
onView(resId.resourceMatcher()).check(matches(not(isDisplayed())))
fun assertNotDisplayed(viewId: Int) {
viewId.resourceMatcher().assertAny(not(isDisplayed()))
}

@JvmStatic
fun assertNotDisplayed(text: String) {
onView(withText(text)).check(matches(not(isDisplayed())))
withText(text).assertAny(not(isDisplayed()))
}

@JvmStatic
fun assertNotDisplayed(@IdRes resId: Int, text: String) {
onView(withId(resId)).check(matches(not(withText(text))))
fun assertNotDisplayed(@IdRes viewId: Int, text: String) {
viewId.resourceMatcher().assertAny(not(withText(text)))
}

@JvmStatic
fun assertContains(text: String) {
assertDisplayed(withText(containsString(text)))
withText(containsString(text)).assertAny(isDisplayed())
}

@JvmStatic
fun assertContains(@IdRes resId: Int, text: String) {
onView(withId(resId)).check(matches(withText(containsString(text))))
fun assertContains(@IdRes viewId: Int, text: String) {
viewId.resourceMatcher().assertAny(withText(containsString(text)))
}

@JvmStatic
Expand All @@ -104,12 +75,12 @@ object BaristaVisibilityAssertions {
}

@JvmStatic
fun assertTextColorIs(@IdRes resId: Int, @ColorRes colorRes: Int) {
onView(withId(resId)).check(matches(TextColorMatcher(colorRes)))
fun assertTextColorIs(@IdRes viewId: Int, @ColorRes colorRes: Int) {
viewId.resourceMatcher().assertAny(TextColorMatcher(colorRes))
}

@JvmStatic
fun assertTextColorIsNot(@IdRes resId: Int, @ColorRes colorRes: Int) {
onView(withId(resId)).check(matches(not(TextColorMatcher(colorRes))))
fun assertTextColorIsNot(@IdRes viewId: Int, @ColorRes colorRes: Int) {
viewId.resourceMatcher().assertAny(not(TextColorMatcher(colorRes)))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.schibsted.spain.barista.internal

import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.assertion.ViewAssertions
import android.view.View
import com.schibsted.spain.barista.internal.failurehandler.SpyFailureHandler
import com.schibsted.spain.barista.internal.failurehandler.description
import com.schibsted.spain.barista.internal.matcher.HelperMatchers.firstViewOf
import org.hamcrest.Matcher
import org.hamcrest.Matchers.allOf

/**
* Extension function alias for [assertAnyView]
*/
fun Matcher<View>.assertAny(condition: Matcher<View>) {
assertAnyView(viewMatcher = this, condition = condition)
}

/**
* Performs an assertion of a [condition] on a view described by [viewMatcher].
*
* Attempts to assert using multiple scenarios for the [viewMatcher]:
* 1. Just one view matches the [viewMatcher].
* 2. Multiple views match the [viewMatcher]: will pass if at least one of them matches the [condition].
*/
fun assertAnyView(viewMatcher: Matcher<View>, condition: Matcher<View>) {
val spyFailureHandler = SpyFailureHandler()
try {
tryToAssert(viewMatcher, condition, spyFailureHandler)
} catch (firstError: RuntimeException) {
try {
tryToAssertFirstView(viewMatcher, condition, spyFailureHandler)
} catch (secondError: RuntimeException) {
spyFailureHandler.resendFirstError("View ${viewMatcher.description()} wasn't displayed on the screen")
}
}
}

private fun tryToAssertFirstView(viewMatcher: Matcher<View>, condition: Matcher<View>, spyFailureHandler: SpyFailureHandler) {
onView(firstViewOf(allOf(viewMatcher, condition)))
.withFailureHandler(spyFailureHandler)
.check(ViewAssertions.matches(condition))
}

private fun tryToAssert(viewMatcher: Matcher<View>, condition: Matcher<View>, spyFailureHandler: SpyFailureHandler) {
onView(viewMatcher)
.withFailureHandler(spyFailureHandler)
.check(ViewAssertions.matches(condition))
}
Loading

0 comments on commit b720c50

Please sign in to comment.