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.

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() } }