-
Notifications
You must be signed in to change notification settings - Fork 12
Espresso operations
Simple espresso operation looks like this
onView(withId(R.id.send_button)).check(isDisplayed()).perform(click())
the same with Ultron
withId(R.id.send_button).isDisplayed().click()
Names of all Ultron operations are the same as espresso one. There are a lot of additional operations those simplifies test development.
//------ actions ------
click()
doubleClick()
longClick()
typeText(text: String)
replaceText(text: String)
clearText()
pressKey(keyCode: Int)
pressKey(key: EspressoKey)
closeSoftKeyboard()
swipeLeft()
swipeRight()
swipeUp()
swipeDown()
scrollTo()
perform(viewAction: ViewAction) // execute custom espresso action as Ultron one
//------ assertions ------
isDisplayed()
isNotDisplayed()
isCompletelyDisplayed()
isDisplayingAtLeast(percentage: Int)
doesNotExist()
isEnabled()
isNotEnabled()
isSelected()
isNotSelected()
isClickable()
isNotClickable()
isChecked()
isNotChecked()
isFocusable()
isNotFocusable()
hasFocus()
isJavascriptEnabled()
hasText(text: String)
hasText(resourceId: Int)
hasText(stringMatcher: Matcher<String>)
textContains(text: String)
hasContentDescription(text: String)
hasContentDescription(resourceId: Int)
hasContentDescription(charSequenceMatcher: Matcher<CharSequence>)
contentDescriptionContains(text: String)
assertMatches(condition: Matcher<View>) // execute custom espresso assertion as Ultron one
//------ general ------
withTimeout(timeoutMs: Long) // set custom timeout for operations
withResultHandler(resultHandlerBlock) // set custom result handler and process operation result
Specify page elements as properties of PageObject class.
object SomePage : Page<SomePage>() {
private val button = withId(R.id.button1)
private val eventStatus = withId(R.id.last_event_status)
}
Use this properties in page steps
object SomePage : Page<SomePage>() {
//page elements
fun someUserStepOnPage(expectedEventText: String){
button.click()
eventStatus.hasText(expectedEventText)
}
}
withId(R.id.last_event_status).withTimeout(10_000).isDisplayed()
There are 2 ways of using custom timeout:
- Specify it for page property and it will be applied for all operations with this element
object SomePage : Page<SomePage>() {
private val eventStatus = withId(R.id.last_event_status).withTimeout(10_000)
}
- Specify it inside special step there the element operation could take more time. This timeout value will be applied only once for single operation.
object SomePage : Page<SomePage>() {
fun someLongUserStep(expectedEventText: String){
longRequestButton.click()
eventStatus.withTimeout(20_000).hasText(expectedEventText)
}
}
To execute any operation inside dialog or popup with espresso you have to specify correct root element
onView(withText("OK"))).inRoot(isDialog()).perform(click())
onView(withText("Cancel")).inRoot(isPlatformPopup()).perform(click())
Here is a point we need to put our minds on.
Ultron extends not only Matcher<View>
object but also ViewInteraction
and DataInteraction
objects
onView(withText("OK"))).inRoot(isDialog())
returns ViewInteraction. Therefore it's possible to use Ultron operations with dialogs.
So the best way would be a following
object DialogPage : Page<DialogPage>() {
val okButton = onView(withText(R.string.ok_button))).inRoot(isDialog())
val cancelButton = onView(withText(R.string.cancel_button))).inRoot(isDialog())
}
...
fun someUserStepInsideSomePage(){
DialogPage.okButton.click()
somePageElement.isDisplayed()
}
Under the hood all espresso Ultron operations are described in UltronEspressoInteraction
class. That is why you just need to extend this class using kotlin extension function, e.g.
fun <T> UltronEspressoInteraction<T>.appendText(text: String) = apply {
UltronEspresso.executeAction(
UltronEspressoOperation(
operationBlock = getInteractionActionBlock(AppendTextAction(text)),
name = "AppendText '$text' to ${getInteractionMatcher()}",
description = "${interaction!!::class.simpleName} APPEND_TEXT to ${getInteractionMatcher()} during $timeoutMs ms",
type = EspressoActionType.CUSTOM,
timeoutMs = timeoutMs ?: UltronConfig.Espresso.ACTION_TIMEOUT
)
)
}
AppendTextAction
is a custom ViewAction, smth like that
class AppendTextAction(private val value: String) : ViewAction {
override fun getConstraints() = allOf(isDisplayed(), isAssignableFrom(TextView::class.java))
override fun perform(uiController: UiController, view: View) {
(view as TextView).apply {
this.text = "$text$value"
}
uiController.loopMainThreadUntilIdle()
}
...
}
To make your custom operation 100% native for Ultron framework it's required to add 3 lines more
//support action for all Matcher<View>
fun Matcher<View>.appendText(text: String) = UltronEspressoInteraction(onView(this)).appendText(text)
//support action for all ViewInteractions
fun ViewInteraction.appendText(text: String) = UltronEspressoInteraction(this).appendText(text)
//support action for all DataInteractions
fun DataInteraction.appendText(text: String) = UltronEspressoInteraction(this).appendText(text)
Finally you are able to use this custom operation
withId(R.id.text_input).appendText("some text to append")