Actions
Detox uses matchers to find UI elements in your app and actions to simulate user interaction with those elements.
Use expectations to verify element states.
Methods
.tap()
.multiTap()
.longPress()
.longPressAndDrag()
.swipe()
.pinch()
iOS only.scrollToIndex()
Android only.scroll()
.scrollTo()
.typeText()
.replaceText()
.clearText()
.tapReturnKey()
.tapBackspaceKey()
.setColumnToValue()
iOS only.setDatePickerDate()
.adjustSliderToPosition()
.getAttributes()
.takeScreenshot(name)
.performAccessibilityAction()
tap(point)
Simulates a tap on the element at the specified point, or at element’s activation point if no point is specified.
point
—a point in the element’s coordinate space (optional, valid input: object with x and y numerical values, default is null
)
Note: Special care should be applied when specifying a point with this method. Elements may have different dimensions when displayed on different device screen sizes, different text sizes, etc.
await element(by.id('tappable')).tap();
await element(by.id('tappable')).tap({x:5, y:10});
multiTap(times)
Simulates multiple taps on the element at its activation point. All taps are applied as a part of the same gesture and there is no synchronization attempt between taps.
times
—the number of taps to simulate (number, 1 and above)
await element(by.id('tappable')).multiTap(3);
longPress(point, duration)
Simulates a long press on the element at its activation point or at the specified point.
point
— a point in the element’s coordinate space (optional, object with x
and y
numerical values, default is null
).
duration
— press during time, in milliseconds. Optional (defaults to the standard long-press duration for the platform).
await element(by.id('tappable')).longPress();
await element(by.id('tappable')).longPress({x:5, y:10});
await element(by.id('tappable')).longPress(1500);
await element(by.id('tappable')).longPress({x:5, y:10}, 1500);
Custom durations should be used cautiously, as they can affect test consistency and user experience expectations. They are typically necessary when testing components that behave differently from the platform's defaults or when simulating unique user interactions.
longPressAndDrag(duration, normalizedPositionX, normalizedPositionY, targetElement, normalizedTargetPositionX, normalizedTargetPositionY, speed, holdDuration)
Simulates a long press on the element and then drag it to a position of another element.
duration
—the duration to press for, in ms (required)normalizedPositionX
— X coordinate of the starting point, relative to the element width (required, a number between 0.0 and 1.0,NaN
— choose an optimal value automatically)normalizedPositionY
— Y coordinate of the starting point, relative to the element height (required, a number between 0.0 and 1.0,NaN
— choose an optimal value automatically)targetElement
— the target element to drag to (required)normalizedTargetPositionX
— X coordinate of the ending point, relative to the target element width (optional, a number between 0.0 and 1.0,NaN
— choose an optimal value automatically)normalizedTargetPositionY
— Y coordinate of the ending point, relative to the target element height (optional, a number between 0.0 and 1.0,NaN
— choose an optimal value automatically)speed
— the speed of the drag (optional, valid input:"fast"
/"slow"
, default is"fast"
)holdDuration
— the duration before releasing at the end, in ms (optional, default is 1000)
await element(by.id('elementToDrag')).longPressAndDrag(2000, NaN, NaN, element(by.id('targetElement')), NaN, NaN);
await element(by.id('cellId_1')).longPressAndDrag(2000, 0.9, NaN, element(by.id('cellId_6')), 0.9, NaN, 'slow', 0);
swipe(direction[, speed, normalizedOffset, normalizedStartingPointX, normalizedStartingPointY])
Simulates a swipe on the element with the provided options.
direction
— the direction of the swipe (required, valid input:"left"
/"right"
/"up"
/"down"
)speed
— the speed of the swipe (optional, valid input:"fast"
/"slow"
, default is"fast"
)normalizedOffset
— swipe amount relative to the screen width/height (optional, a number between 0.0 and 1.0, default isNaN
— choose an optimal value automatically)normalizedStartingPointX
— X coordinate of the swipe starting point, relative to the element width (optional, a number between 0.0 and 1.0, default isNaN
— choose an optimal value automatically)normalizedStartingPointY
— Y coordinate of the swipe starting point, relative to the element height (optional, a number between 0.0 and 1.0, default isNaN
— choose an optimal value automatically)
await element(by.id('scrollView')).swipe('down');
await element(by.id('scrollView')).swipe('down', 'slow'); // set swipe speed
await element(by.id('scrollView')).swipe('down', 'fast', 0.75); // set swipe amount
await element(by.id('scrollView')).swipe('down', 'fast', NaN, 0.8); // set starting point X
await element(by.id('scrollView')).swipe('down', 'fast', NaN, NaN, 0.25); // set starting point Y
pinch(scale, speed, angle)
iOS only
Simulates a pinch on the element with the provided options.
scale
—the scale of the pinch gesture; use a scale between 0 and 1 to zoom out, and a scale greater than 1 to zoom in; the system makes a best effort to accommodate the requested scale, taking into account the element’s dimensions (valid input: (0.0, inf])
speed
—the speed of the pinch (optional, valid input: "fast"
/"slow"
, default is "slow"
)
angle
—the angle of the pinch, in radians (optional, default is 0.0)
await element(by.id('PinchableScrollView')).pinch(1.1); //Zooms in a little bit
await element(by.id('PinchableScrollView')).pinch(2.0); //Zooms in a lot
await element(by.id('PinchableScrollView')).pinch(0.001); //Zooms out a lot
scrollToIndex(index)
Android only
Scrolls until it reaches the element with the provided index. This works for ReactScrollView
and ReactHorizontalScrollView
.
index
—the index of the target element
await element(by.id('scrollView')).scrollToIndex(0);
scroll(offset, direction[, startPositionX, startPositionY])
Simulates a scroll on the element with the provided options.
offset
—the offset to scroll, in points
direction
—the scroll’s direction (valid input: "left"
/"right"
/"up"
/"down"
)
startPositionX
—the normalized x percentage of the element to use as scroll start point (optional, valid input: [0.0, 1.0], NaN
—choose an optimal value automatically, default is NaN
)
startPositionY
—the normalized y percentage of the element to use as scroll start point (optional, valid input: [0.0, 1.0], NaN
—choose an optimal value automatically, default is NaN
)
await element(by.id('scrollView')).scroll(100, 'up');
await element(by.id('scrollView')).scroll(100, 'down', NaN, 0.85);
whileElement(element)
Continuously scrolls the scroll element until the specified expectation is resolved. If the edge of the scroll element is reached while the expectation is not resolved, the operation is failed.
await waitFor(element(by.text('Text5'))).toBeVisible().whileElement(by.id('ScrollView630')).scroll(50, 'down');
scrollTo(edge[, startPositionX, startPositionY])
Simulates a scroll to the specified edge.
edge
—the edge to scroll to (valid input: "left"
/"right"
/"top"
/"bottom"
)
startPositionX
—the normalized x percentage of the element to use as scroll start point (optional, valid input: [0.0, 1.0], NaN
—choose an optimal value automatically, default is NaN
)
startPositionY
—the normalized y percentage of the element to use as scroll start point (optional, valid input: [0.0, 1.0], NaN
—choose an optimal value automatically, default is NaN
)
await element(by.id('scrollView')).scrollTo('bottom');
await element(by.id('scrollView')).scrollTo('top', NaN, 0.2);
typeText(text)
Simulates typing of the specified text into the element, using the system’s builtin keyboard and typing behavior.
On iOS, any element can be typed into, as long as it can become first responder and conforms to the UITextInput
protocol. Before typing the text, Detox attempts making the element the first responder, if it isn’t already. If the element’s window is not key window, Detox attempts making it the key window.
text
—the text to type (valid input: string)
await element(by.id('textField')).typeText('passcode');
replaceText(text)
Replaces the element’s text with the specified text, without using the system’s builtin keyboard or typing behavior. Note, that using this method is faster than using .typeText()
, but may not trigger all text input callbacks, causing an undefined state in your app.
On iOS, any element’s text can be replaced, as long as it can become first responder and conforms to the UITextInput
protocol. Before replacing the text, Detox attempts making the element the first responder, if it isn’t already. If the element’s window is not key window, Detox attempts making it the key window.
text
—the text to replace with (valid input: string)
await element(by.id('textField')).replaceText('passcode again');
clearText()
Simulates clearing the text of the element, using the system’s builtin keyboard and typing behavior.
On iOS, any element’s text can be cleared, as long as it can become first responder and conforms to the UITextInput
protocol. Before clearing the text, Detox attempts making the element the first responder, if it isn’t already. If the element’s window is not key window, Detox attempts making it the key window.
await element(by.id('textField')).clearText();
tapReturnKey()
Simulates tapping on the return key into the element, using the system’s builtin keyboard and typing behavior.
On iOS, any element can be sent return key input, as long as it can become first responder and conforms to the UITextInput
protocol. Before tapping on the return key, Detox attempts making the element the first responder, if it isn’t already. If the element’s window is not key window, Detox attempts making it the key window.
await element(by.id('textField')).tapReturnKey();
tapBackspaceKey()
Simulates tapping of the backspace key into the element, using the system’s builtin keyboard and typing behavior.
On iOS, any element can be sent backspace key input, as long as it can become first responder and conforms to the UITextInput
protocol. Before tapping on the backspace key, Detox attempts making the element the first responder, if it isn’t already. If the element’s window is not key window, Detox attempts making it the key window.
await element(by.id('textField')).tapBackspaceKey();
setColumnToValue(column, value)
iOS only
Sets the element’s specified column to the specified value, using the system’s picker view APIs.
Values accepted by this method are strings only, and the system will do its best to match complex picker view cells to the string.
This function does not support date pickers. Use .setDatePickerDate()
instead.
column
—the element’s column to set (valid input: number, 0 and above)
value
—the string value to set (valid input: string)
await element(by.id('pickerView')).setColumnToValue(1, "6");
await element(by.id('pickerView')).setColumnToValue(2, "Hello World");
Note: When working with date pickers, you should always set an explicit locale when launching your app in order to prevent flakiness from different date and time styles. See here for more information.
setDatePickerDate(dateString, dateFormat)
Sets the date-picker’s date to the specified date and time.
dateString
—The date to set. Should match the format provided by dateFormat
.
dateFormat
—The format of dateString
. Should be either 'ISO8601'
, or an explicit date representation format, as supported by NSDateFormatter
on iOS / DateTimeFormatter
on Android (e.g. 'yyyy/MM/dd'
).
The recommended
dateFormat
isISO8601
.
Examples:
const datePicker = element(by.id('datePicker'));
// ISO8601:
await datePicker.setDatePickerDate('2019-02-06T05:10:00-08:00', 'ISO8601');
await datePicker.setDatePickerDate(new Date().toISOString(), 'ISO8601'); // toISOString returns an ISO8601 format with no timezone (UTC-0)
// Explicit format:
await datePicker.setDatePickerDate('2019/02/06', "yyyy/MM/dd");
As far as element-matching is concerned, on Android, older versions of the popular @react-native-community/datetimepicker
package don’t allow for the specification of your own testID
prop for the date-picker component. Therefore, you'd have to either upgrade your package to a newer version containing PR datetimepicker#705 inside, or use Detox's by.type
matcher as a workaround. For example:
const datePicker = device.getPlatform() === 'android'
? element(by.type('android.widget.DatePicker'))
: element(by.id('datePicker'));
adjustSliderToPosition(normalizedPosition)
Manipulates the UI to change the displayed value of the slider element to a new value, based on a normalized position.
normalizedPosition
—The normalized position to adjust the slider element. (valid input: [0, 1], 0 corresponds to the minimum value of the slider, and 1 corresponds to the maximum value)
await element(by.id('slider')).adjustSliderToPosition(0.75);
getAttributes()
Returns an object, representing various attributes of the element.
Retrieved attributes are:
text
: The text value of any textual element.label
: The label of the element. MatchesaccessibilityLabel
for iOS, andcontentDescription
for android. Refer to the.toHaveLabel()
API in order to learn about caveats associated with this attribute in React Native apps.placeholder
: The placeholder text value of the element. Matcheshint
on android.enabled
: Whether the element is enabled for user interaction.identifier
: The identifier of the element. MatchesaccessibilityIdentifier
on iOS, and the main view tag, on Android - both commonly holding the component’s test ID in React Native apps.visible
: Whether the element is visible. On iOS, visibility is calculated for the activation point. On Android, the attribute directly holds the value returned by View.getLocalVisibleRect()).value
: The value of the element, where applicable. For example: the position of a slider, or whether a checkbox has been marked. MatchesaccessibilityValue
, on iOS.frame
: The frame of the element, in screen coordinate space.
iOS-Only
activationPoint
: The activation point of the element, in element coordinate space.normalizedActivationPoint
: The activation point of the element, in normalized percentage ([0.0, 1.0]).hittable
: Whether the element is hittable at the activation point.elementFrame
: The frame of the element, in container coordinate space.elementBounds
: The bounds of the element, in element coordinate space.safeAreaInsets
: The safe area insets of the element, in element coordinate space.elementSafeBounds
: The safe area bounds of the element, in element coordinate space.date
: The date of the element (in case the element is a date picker).normalizedSliderPosition
: The normalized slider position (in case the element is a slider).contentOffset
: The content offset (in case the element is a scroll view).contentInset
: The content inset (in case the element is a scroll view).adjustedContentInset
: The adjusted content inset (in case the element is a scroll view).
Android-Only
visibility
: The OS visibility type associated with the element:visible
,invisible
orgone
.width
: Width of the element, in pixels (deprecated).height
: Height of the element, in pixels (deprecated).elevation
: Elevation of the element.alpha
: Alpha value for the element.focused
: Whether the element is the one currently in focus.textSize
: The text size for the text element.length
: The length of the text element (character count).
If the value for a given attribute is null or cannot be otherwise computed, the key will not be present, but empty strings may be found in the object.
If the query matches multiple elements, the attributes of all matched elements is returned as an array of objects under the elements
key.
// import jestExpect from 'expect';
const jestExpect = require('expect').default;
// ...
const attributes = await element(by.text('Tap Me')).getAttributes();
jestExpect(attributes.text).toBe('Tap Me');
const multipleMatchedElements = await element(by.text('Multiple')).getAttributes();
jestExpect(multipleMatchedElements.elements.length).toBe(5);
jestExpect(multipleMatchedElements.elements[0].identifier).toBe('FirstElement');
takeScreenshot(name)
Takes a screenshot of the matched element. For full details on taking screenshots with Detox, refer to the screenshots guide.
name
—the name of the screenshot
performAccessibilityAction(actionName)
Triggers an accessibility action.
actionName
—the name of the accessibility action
await element(by.id('scrollView')).performAccessibilityAction("activate");
Deprecated Methods
.tapAtPoint()
.pinchWithAngle()
iOS only
tapAtPoint(point)
Deprecated: Use .tap()
instead.
Simulates a tap at on the element at the specified point.
point
—a point in the element’s coordinate space
await element(by.id('tappable')).tapAtPoint({x:5, y:10});
pinchWithAngle(direction, speed, angle)
iOS only
Deprecated: Use .pinch()
instead.
Simulates a pinch on the element with the provided options.
direction
—the direction of the pinch gesture (valid input: "inward"
/"outward"
)
speed
—the speed of the pinch (optional, valid input: "fast"
/"slow"
, default is "slow"
)
angle
—the angle of the pinch, in radians (optional, default is 0.0)
await element(by.id('PinchableScrollView')).pinchWithAngle('outward', 'slow', 0);