Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Espresso and Robots

Espresso and Robots

This is a walkthrough of implementing a Robot pattern in Espresso, using Kotlin and infix extension functions.

Avatar for Rick Busarow

Rick Busarow

April 22, 2019
Tweet

More Decks by Rick Busarow

Other Decks in Programming

Transcript

  1. VIEWINTERACTION interface ViewInteraction { fun check(viewAssertion: ViewAssertion): ViewInteraction fun perform(vararg

    viewActions: ViewAction): ViewInteraction fun inRoot(rootMatcher: Matcher<Root>): ViewInteraction fun noActivity(): ViewInteraction fun withFailureHandler(failureHandler: FailureHandler): ViewInteraction }
  2. VIEWINTERACTION interface ViewInteraction { fun check(viewAssertion: ViewAssertion): ViewInteraction fun perform(vararg

    viewActions: ViewAction): ViewInteraction fun inRoot(rootMatcher: Matcher<Root>): ViewInteraction fun noActivity(): ViewInteraction fun withFailureHandler(failureHandler: FailureHandler): ViewInteraction }
  3. VIEWINTERACTION interface ViewInteraction { fun check(viewAssertion: ViewAssertion): ViewInteraction fun perform(vararg

    viewActions: ViewAction): ViewInteraction fun inRoot(rootMatcher: Matcher<Root>): ViewInteraction fun noActivity(): ViewInteraction fun withFailureHandler(failureHandler: FailureHandler): ViewInteraction }
  4. TWO MOVES OF ESPRESSO ▸ ViewActions ▸ perform(), type(), click()

    ▸ ViewAssertions ▸ isDisplayed(), isSelected(), isEnabled()
  5. EspressoTest.kt interface EspressoTest { val click: ViewAction get() = ViewActions.click()

    val visible: ViewMatcher get() = ViewMatchers.isDisplayed() infix fun type(text: String): ViewAction = ViewActions.typeText(text) infix fun Int.shouldBe(viewMatcher: ViewMatcher): ViewInteraction = Espresso.onView(ViewMatchers.withId(this)) .check(ViewAssertions.matches(viewMatcher)) infix fun Int.shouldHaveText(text: String): ViewInteraction = Espresso.onView(ViewMatchers.withId(this)) .check(ViewAssertions.matches(withText(text))) }
  6. Robot.kt abstract class Robot<ViewClass : Any> { @get:LayoutRes protected abstract

    val layout: Int fun setFailureHandler(context: Context) { Espresso.setFailureHandler { error, viewMatcher !-> takeScreenshot("test_failed") DefaultFailureHandler(context).handle(error, viewMatcher) } } fun takeScreenshot(description: String) { Timber.v("click click! "-- $description") } }
  7. abstract class Robot<ViewClass : Any> { @get:LayoutRes protected abstract val

    layout: Int fun setFailureHandler(context: Context) { Espresso.setFailureHandler { error, viewMatcher !-> takeScreenshot("test_failed") DefaultFailureHandler(context).handle(error, viewMatcher) } } fun takeScreenshot(description: String) { Timber.v("click click! "-- $description") } } Robot.kt
  8. abstract class Robot<ViewClass : Any> { @get:LayoutRes protected abstract val

    layout: Int fun setFailureHandler(context: Context) { Espresso.setFailureHandler { error, viewMatcher !-> takeScreenshot("test_failed") DefaultFailureHandler(context).handle(error, viewMatcher) } } fun takeScreenshot(description: String) { Timber.v("click click! "-- $description") } } Robot.kt
  9. abstract class Robot<ViewClass : Any> { @get:LayoutRes protected abstract val

    layout: Int fun setFailureHandler(context: Context) { Espresso.setFailureHandler { error, viewMatcher !-> takeScreenshot("test_failed") DefaultFailureHandler(context).handle(error, viewMatcher) } } fun takeScreenshot(description: String) { Timber.v("click click! "-- $description") } } Robot.kt
  10. LogInRobot.kt class LogInRobot : Robot<LogInActivity>(), EspressoTest { override val layout:

    Int = R.layout.activity_login object Ids { const val USERNAME = R.id.etUsername const val PASSWORD = R.id.etPassword const val SHOW_PASSWORD = R.id.btnShowPassword const val SIGN_IN = R.id.btnSignIn const val EULA = R.id.btnEula } … }
  11. LogInRobot.kt class LogInRobot : Robot<LogInActivity>(), EspressoTest { fun typeUsername(userName: String

    = USERNAME) { click on Ids.USERNAME type(userName) on Ids.USERNAME Espresso.closeSoftKeyboard() takeScreenshot("type username $userName") } fun verifyUserName(userName: String) { Ids.USERNAME shouldHaveText userName takeScreenshot(“compare username $userName") } }
  12. LogInActivityTest.kt fun EspressoTest.logIn(func: LogInRobot.() "-> Unit): LogInRobot = LogInRobot().apply {

    func() } @Test fun emailField_displaysWhatIsTyped() { logIn { typeUsername("[email protected]") verifyUserName("[email protected]") } }
  13. LogInActivityTest.kt @Test fun demoThings() = runBlocking { landing { "//""...

    } logIn { typeUsername("[email protected]") typePassword("Start123") verifyUsername("[email protected]") clickSignIn() } }