iOS page source discrepancies [Ruby bindings]

Currently trying to automate a native iOS app on 7.1 using Appium server version 1.2. I’m having a lot of trouble reliably clicking on a UIATableCell.

If I print the size of all the elements with :name "profileCell" I get about 80+. However, this does not match the results when printing driver.source.

Most of the time the click fails with: elementId x could not be tapped

Here is a gist of the output from a recent driver.source command. Immediately following this, puts driver.find_elements(:name, "profileCell").size returned with 122.

Can anyone explain what’s going on to cause this discrepancy?

I think the ruby binding automatically removes elements which are not visible? @bootstraponline has details

That gist has 19 elements matching name=“profileCell”. The selenium-webdriver methods don’t perform any filtering find_elements(:xpath, "...") The helper methods xpath("...") will filter out invisible elements.

If you want consistency with driver.source, you’ll want to do a name search via xpath. The regular name search uses a different implementation on the appium server. It’s not related to the Ruby bindings.

Using driver.page name: "profileCell" seems to return what’s being displayed on the screen (I think).

Would it be in my best interest then to abandon the webdriver finders (at least for iOS, haven’t had much issue with Android)?

From what I understand is it also the case that :name finders implementation won’t work how I would expect :xpath to? Is there a finder for :label?

The framework I’ve been working with is entirely devoid of xpath finders and I’d prefer to keep it that way.

It’s up to you to find out which locators work well for your app. If you don’t care about invisible elements, then the regular finders are fine. If you want to interact with visible elements as end users do, then the regular finders are unable to do this currently.

The fix I implemented in the Ruby bindings is to filter out invisible element by default. The way this works is via xpath.

I’m a little confused still.

If I want to find all elements matching :name, "profileCell" and only return visible elements, which ruby_lib method should I be using? Is the only finder that returns visible elements only xpath?

Ok. Here is an example.

UIATableCell
   name: Transitions, Shows UIViewAnimationTransitions
   id: TransitionsExplain => Shows UIViewAnimationTransitions
       TransitionsTitle   => Transitions
> find_ele_by_attr :UIATableCell, :name, 'Transitions, Shows UIViewAnimationTransitions'
post /element
{
    :using => "xpath",
    :value => "//UIATableCell[@visible=\"true\" and @name='Transitions, Shows UIViewAnimationTransitions']"
}
#<Selenium::WebDriver::Element:0x21f510b9910ad1da id="1">

See this page for more iOS methods.

Thanks that makes it clear. Curiously enough this code correctly clicks the element in version 1.1 but fails to click it in 1.2. Unfortunately downgrading to 1.1 breaks some other things so for now I will have to wait on some bug fixes.

I’ve finally had a chance to play with this again and I’m still noticing some weirdness.

We have a customized UISegmentedControl controlled by 4 tabs. Each tab contains a scrollable table view that usually displayed about 6 cells.

When I call find_ele_by_attr :UIATableCell, :name, example name, it doesn’t behave the same every time (using arc). The first time it usually fails with:

Selenium::WebDriver::Error::UnknownError: elementId 67 could not be tapped

If I run the command again, it fails about 50% of the time, but the elementId increments.

It has succeeded every time so far on the third attempt.

Is there any reason why the collection of elements being returned is changing, even through app state is not changing?

[28] pry(main)> finds("Message")[0].click
post /elements
{
    :using => "xpath",
    :value => "//*[@visible=\"true\" and (contains(translate(@name,\"MESSAGE\",\"message\"), \"message\") or contains(translate(@hint,\"MESSAGE\",\"message\"), \"message\") or contains(translate(@label,\"MESSAGE\",\"message\"), \"message\") or contains(translate(@value,\"MESSAGE\",\"message\"), \"message\"))]"
}
post /element/92/click
Selenium::WebDriver::Error::UnknownError: elementId 92 could not be tapped
from /Users/jmiele/.rvm/gems/ruby-2.1.3/gems/selenium-webdriver-2.43.0/lib/selenium/webdriver/remote/response.rb:52:in `assert_ok'
[29] pry(main)>
[30] pry(main)>
[31] pry(main)>
[32] pry(main)> finds("Message")[0].click
post /elements
{
    :using => "xpath",
    :value => "//*[@visible=\"true\" and (contains(translate(@name,\"MESSAGE\",\"message\"), \"message\") or contains(translate(@hint,\"MESSAGE\",\"message\"), \"message\") or contains(translate(@label,\"MESSAGE\",\"message\"), \"message\") or contains(translate(@value,\"MESSAGE\",\"message\"), \"message\"))]"
}
post /element/98/click
""

xpath on ios is busted. If you checkout master, you’ll see I replaced all the helpers with a specially crafted json locator strategy.

The random element could not be tapped error is a gift apple has given us. The work around is to wrap the command in a wait. wait { find('some element text').click }