EarlGrey UI Interactions: Taps, Scrolls, Gestures, and Text Input

EarlGrey UI Interactions: Taps, Scrolls, Gestures, and Text Input

EarlGrey's interaction API covers the full range of touch gestures and UI interactions available on iOS. Every interaction runs after EarlGrey confirms the app is idle and the target element is visible and hittable.

Basic Interactions

Tap

// Single tap
EarlGrey.selectElement(with: grey_accessibilityID("submitButton"))
    .perform(grey_tap())

// Tap at specific point within element
EarlGrey.selectElement(with: grey_accessibilityID("mapView"))
    .perform(grey_tapAtPoint(CGPoint(x: 100, y: 150)))

// Tap with specific interaction point
EarlGrey.selectElement(with: grey_accessibilityID("button"))
    .perform(grey_tapAtPoint(.topLeft))  // .center, .topLeft, .bottomRight, etc.

Long Press

EarlGrey.selectElement(with: grey_accessibilityID("messageCell"))
    .perform(grey_longPress())

// Long press with duration
EarlGrey.selectElement(with: grey_accessibilityID("messageCell"))
    .perform(grey_longPressWithDuration(2.0))

// Long press at point
EarlGrey.selectElement(with: grey_accessibilityID("canvas"))
    .perform(grey_longPressAtPointWithDuration(CGPoint(x: 50, y: 50), 1.5))

Double Tap

EarlGrey.selectElement(with: grey_accessibilityID("zoomView"))
    .perform(grey_doubleTap())

Text Input

let textField = EarlGrey.selectElement(with: grey_accessibilityID("searchField"))

// Type text (appends to existing)
textField.perform(grey_typeText("search query"))

// Clear existing text and type new
textField.perform(grey_clearText())
textField.perform(grey_typeText("new value"))

// Replace all text
textField
    .perform(grey_tap())
    .perform(grey_clearText())
    .perform(grey_typeText("replacement"))

// Dismiss keyboard
EarlGrey.selectElement(with: grey_keyWindow())
    .perform(grey_tap())

For secure text fields (passwords):

EarlGrey.selectElement(with: grey_accessibilityID("passwordField"))
    .perform(grey_tap())
    .perform(grey_typeText("myPassword"))

Swipe Gestures

let view = EarlGrey.selectElement(with: grey_accessibilityID("carousel"))

// Fast swipe (like a flick)
view.perform(grey_swipeFastInDirection(.left))
view.perform(grey_swipeFastInDirection(.right))
view.perform(grey_swipeFastInDirection(.up))
view.perform(grey_swipeFastInDirection(.down))

// Slow swipe (deliberate drag)
view.perform(grey_swipeSlowInDirection(.left))

// Swipe from a specific starting point (0.0–1.0 of element size)
view.perform(grey_swipeFastInDirection(.left, startPercent: CGPoint(x: 0.9, y: 0.5)))

Scrolling

let tableView = EarlGrey.selectElement(with: grey_accessibilityID("resultsTable"))

// Scroll in direction by amount (points)
tableView.perform(grey_scrollInDirection(.down, amount: 300))
tableView.perform(grey_scrollInDirection(.up, amount: 300))

// Scroll to content edge
tableView.perform(grey_scrollToContentEdge(.bottom))
tableView.perform(grey_scrollToContentEdge(.top))

// Scroll until element is visible
EarlGrey.selectElement(with: grey_accessibilityID("lastItem"))
    .using(searchAction: grey_scrollInDirection(.down, amount: 100),
           onElementWith: grey_accessibilityID("resultsTable"))
    .assert(grey_sufficientlyVisible())

Pinch and Zoom

let mapView = EarlGrey.selectElement(with: grey_accessibilityID("mapView"))

// Pinch in (zoom out)
mapView.perform(grey_pinchFastInDirection(.inward, angle: .right))

// Pinch out (zoom in)  
mapView.perform(grey_pinchFastInDirection(.outward, angle: .right))

// Slow pinch (more control)
mapView.perform(grey_pinchSlowInDirection(.outward, angle: CGFloat.pi / 4))

Table and Collection Views

// Scroll to a cell by accessibility ID
EarlGrey.selectElement(with: grey_accessibilityID("cell_42"))
    .using(searchAction: grey_scrollInDirection(.down, amount: 50),
           onElementWith: grey_accessibilityID("tableView"))
    .perform(grey_tap())

// Select cell at index path
EarlGrey.selectElement(
    with: grey_allOf(
        grey_accessibilityID("orderCell"),
        grey_interactable()
    )
)
.atIndex(2)  // zero-indexed
.perform(grey_tap())

Alerts and Action Sheets

EarlGrey handles system alerts automatically if you configure it to:

// Dismiss alerts automatically (configure in setUp)
GREYConfiguration.shared.setValue(true, forConfigKey: kGREYConfigKeyDisableAlertHandling)

// Or handle manually
EarlGrey.selectElement(with: grey_buttonTitle("OK"))
    .perform(grey_tap())

EarlGrey.selectElement(with: grey_buttonTitle("Cancel"))
    .perform(grey_tap())

For system permission alerts (camera, notifications):

// Add UI Interruption Monitor (XCTest)
addUIInterruptionMonitor(withDescription: "Permission dialog") { alert in
    alert.buttons["Allow"].tap()
    return true
}

Picker Views

// Scroll picker to a specific value
EarlGrey.selectElement(with: grey_accessibilityID("datePicker"))
    .perform(grey_setPickerColumnToValue(1, value: "June"))

// For UIDatePicker
EarlGrey.selectElement(with: grey_accessibilityID("birthdayPicker"))
    .perform(grey_setDate(Date(), onDatePickerWithFormat: "MM/dd/yyyy"))

Sliders

// Move slider to a value (0.0 to 1.0)
EarlGrey.selectElement(with: grey_accessibilityID("volumeSlider"))
    .perform(grey_moveSliderToValue(0.75))

Switches and Toggles

let toggle = EarlGrey.selectElement(with: grey_accessibilityID("notificationsToggle"))

// Turn on
toggle.perform(grey_turnSwitchOn(true))

// Turn off
toggle.perform(grey_turnSwitchOn(false))

// Assert state
toggle.assert(grey_switchWithOnState(true))

Chaining Multiple Actions

EarlGrey.selectElement(with: grey_accessibilityID("emailField"))
    .perform(grey_tap())
    .perform(grey_clearText())
    .perform(grey_typeText("new@example.com"))

// Chain with element reuse
let button = EarlGrey.selectElement(with: grey_accessibilityID("submitBtn"))
button
    .assert(grey_enabled())
    .perform(grey_tap())

Interaction Failures

When an interaction fails, EarlGrey reports:

EarlGrey: Failed to perform action due to:
Element not found. Searched for:
  Accessibility ID: submitButton
Screenshots and element hierarchy saved to:
  /path/to/earlgrey-screenshots/

The element hierarchy dump shows the complete view tree, which makes it easy to verify your selector matches the right element.

Read more

Start now free