DeviceAgent

Joshua Moody edited this page Dec 7, 2016 · 9 revisions
Clone this wiki locally

DeviceAgent

Apple has removed UIAutomation from Xcode 8. Our replacement for UIAutomation is DeviceAgent. DeviceAgent is based on Apple's XCUITest framework.

Our goal for this transition is 100% backward compatibility with UIAutomation. We think we are close, but we need your help to discover what is missing. Since UIAutomation is not available, all uia_* calls now raise an error when tests are run with DeviceAgent. The text of the error will have workarounds and examples to help you transition your tests. Please read the error message and try the suggested replacements. When you find something you cannot do with DeviceAgent, please create a GitHub issue.

When should I use DeviceAgent methods?

The short answer is almost never.

The query engine in the Calabash iOS Server (LPServer) is faster and can find more views that DeviceAgent.

In general, you should use DeviceAgent for views are outside of your application or for views that are presented by the OS. The classic examples are Safari WebView Controllers and Email Compose Controllers. Because these views are outside of your application, the LPServer that is embedded in your application cannot detect them. The DeviceAgent can, for the most part, detect these kinds of views.

Physical Device Testing

run-loop 2.2.3

Setting the CODE_SIGN_IDENTITY is no longer necessary. The CODE_SIGN_IDENTITY environment variable is still respected if, for some reason, you want to force a particular signing identity.

run-loop < 2.2.3

Testing on physical devices now has an additional requirement: code signing.

You must provide a valid code signing identity.

# Find the valid code signing identities
$ xcrun security find-identity -v -p codesigning
  1) 18<snip>84 "iPhone Developer: Your Name (ABCDEF1234)"
  2) 23<snip>33 "iPhone Distribution: Your Company Name (A1B2C3D4EF)"
  3) 38<snip>11 "iPhone Developer: Your Colleague (1234ABCDEF)"

# Chose an "iPhone Developer" certificate.
$ CODE_SIGN_IDENTITY="iPhone Developer: Your Name (ABCDEF1234)" \
   DEVICE_TARGET=< device udid > \
   DEVICE_ENDPOINT=http://< device ip >:37265 \
   bundle exec cucumber

Swipe and Flick

The behavior of the swipe and flick gestures will be different.

Flick

Scenario: Flick to Go Back in UINavigationController
And I am looking at the Scrollplications page
When I full-screen flick to go back, I see the Pan menu
But flick to go back does not work with DeviceAgent

The example above demonstrates that flick gesture has different behaviors with the same arguments depending on whether the gesture is performed with UIAutomation or with DeviceAgent. The reverse is also true: a flick-to-go-back that works with DeviceAgent will not work with UIAutomation.

# Flick to go back
if uia_available?
  flick( < arguments that work for UIA > )
else
  flick( < arguments that work for DeviceAgent > )
end

Swipe

The behavior of swipe is fairly uniform.

Scenario: Full Screen Pan
And I am looking at the Pan Palette page
Then I can swipe to go back to the Pan menu

There is probably a set of arguments for swipe that has the same behavior under UIAutomation and DeviceAgent - you will have to experiment to find the right arguments.

Pan

If you want swipes and flicks that work for both UIAutomation and DeviceAgent, we recommend trying pan and pan_coordinates.

Examples and Documentation

API Doc Feature Steps Comments
flick flick.feature flick.rb Use swipe or pan whenever possible.
swipe swipe.feature swipe.rb DeviceAgent ignores the "swipe-delta" option
pan_coordinates pan.feature pan.rb See also pan

When should I use the new DeviceAgent methods?

DeviceAgent#query is not a substitute for Core#query.

You should use the new DeviceAgent only when a regular Core#query or Core gesture does not work.

In many apps, the view hierarchy is completely opaque (invisible) to DeviceAgent.

The obvious exceptions are views that are presented for your application by the operating system or views that are presented by SpringBoard. Some examples are Mail Compose View, Photo Roll, and Health Kit views. These views are not visible to the Calabash Server, but are visible to DeviceAgent.

Why does DeviceAgent#query return no views?

DeviceAgent is based on XCUITest. In our testing, we found that XCUITest itself could not automate many apps because it could not identify individual views - the whole app appears to XCUITest as a single view. The other reason DeviceAgent#query might not return any views is that XCUITest does not return the correct visibility information about an element. You can try to use DeviceAgent#query with the all: true option.

What should I do if Core#query and DeviceAgent#query fail?

You should create a GitHub issue.

  1. At a high level, what you are trying to do.
  2. Provide a screenshot of the view.

Replacements for UIA Methods

If you cannot find an equivalent DeviceAgent workaround, please create an issue and include:

  1. At a high level, what you are trying to do.
  2. The JavaScript you are trying to invoke.

uia

It is not possible to make raw UIAutomation JavaScript calls.

If you are trying to make query, use the DeviceAgent query API.

    device_agent.query({type: "TextField", index:1})
    device_agent.query({marked: "Cancel"})

If you are trying to perform a gesture or enter text, in most cases the normal Core method will work. If a normal Core method does work, try the DeviceAgent Gesture API.

    device_agent.touch({type: "TextField", index:1})
    device_agent.touch({marked: "Button"})

Gestures

uia_tap, uia_tap_mark, uia_tap_offset,
uia_double_tap, uia_double_tap_mark, uia_double_tap_offset,
uia_two_finger_tap, uia_two_finger_tap_offset,
uia_touch_hold, uia_touch_hold_offset,
uia_pan, uia_pan_offset,
uia_swipe, uia_swipe_offset, uia_flick_offset,
uia_drag_inside, uia_drag_inside_mark,
uia_pinch, uia_pinch_offset, uia_scroll_to

In most cases, you will not need to use a special DeviceAgent gesture method like you did with UIAutomation.

If a Core gesture method does not work, there is a DeviceAgent gesture API.

    device_agent.touch({type: "Button", marked: "Back"})

For UIA pan gestures (flick, swipe, pan) use pan_coordinates.

    from_point = device_agent.query_for_coordinate({marked: "From"})
    to_point = device_agent.query_for_coordinate({marked: "To"})
    pan_coordinates(from_point, to_point)

uia_call, uia_call_windows, uia_call_method, uia_names

There is no suggested workaround for these methods. Please review the DeviceAgent API for a replacement. If you can find no replacement, please create an issue and include:

If you are trying to make query, use the DeviceAgent query API.

    device_agent.query({type: "TextField", index:1})
    device_agent.query({marked: "Cancel"})

If you are trying to perform a gesture or enter text, in most cases the normal Core method will work. If a normal Core method does work, try the DeviceAgent Gesture API.

    device_agent.touch({type: "TextField", index:1})
    device_agent.touch({marked: "Button"})

uia_element_exists?, uia_element_does_not_exist?

Use the DeviceAgent wait API.

    device_agent.wait_for_view({marked: "Cancel"})
    device_agent.wait_for_no_view({marked: "Cancel"})

uia_query, uia_query_el, uia_query_windows

Try to use the DeviceAgent query API.

    device_agent.query({marked: "Cancel"})
    device_agent.query({type: "TextField", index:1})

If the DeviceAgent query API does not find the correct views, please create an issue.

uia_query_windows

    device_agent.query({marked: "Cancel"})
    device_agent.query({type: "TextField", index:1})

uia_type_string, uia_type_string_raw, uia_enter, uia_set_responder_value

In general, you should use the the text input methods defined in Core.

In some cases you will need to use the DeviceAgent query and keyboard API.

    device_agent.touch({type: "TextField", index: 1})
    wait_for_keyboard
    keyboard_enter_text("Hello")

It is important to note that the DeviceAgent implementations of:

    * keyboard_enter_text
    * keyboard_enter_char
    * enter_text_in
    * enter_text
    * fast_enter_text

have exactly the same performance.

You should prefer enter_text or enter_text_in because it matches the Calabash 2.0 API.

uia_keyboard_visible?, uia_wait_for_keyboard

We have not found a case (yet) where the the Core keyboard_visible? and wait_for_keyboard methods do not work when using DeviceAgent. If you find a case where the Core methods do not work, please create a GitHub issue.

The current DeviceAgent keyboard API is scheduled for removal. It is crucial that you report workflows that require the DeviceAgent keyboard API.

    device_agent.keyboard_visible?
    wait_for { device_agent.keyboard_visible? }

uia_screenshot

There is no replacement for this method.

uia_orientation, uia_rotate_home_button_to, uia_rotate

You should not be using this method. In any context (UIA or DeviceAgent) always use the orientation methods defined in the Core API.

uia_send_app_to_background

You should not use this method. If the Core send_app_to_background is not working under UIAutomation, please create a GitHub issue.

uia_set_location

This method has been broken for various iOS versions and device combinations for years.

At the moment, we do not have replacement for location spoofing with DeviceAgent.

Misc

uia_handle_command, uia_serialize_command,
uia_serialize_arguments, uia_serialize_argument
escape_uia_string, send_uia_command

There is no replacement.