Am I using the Appium button method the wrong way? Ruby

I have a button that shows up to a blind person as, button. So I tried using appium.button(0) and got this
RuntimeError: 0 is not a valid xpath index. Must be >= 1

I see the code in Appium::Ios ele_index and was worried that it was using Fortran indexing (from 1) but then I found out that buttons[1] was the same as button(1) and for 2 as well.

My work around, until I get a label on that button, is to just use buttons[0] but it seems like a bug.

Using appium_lib (4.1.0)

index must be >= 1

def button value
          # return button at index.
          return ele_index UIAButton, value if value.is_a? Numeric
          ele_by_json_visible_contains UIAButton, value
        end

witch in turn calls:

def ele_index class_name, index
      raise 'Index must be >= 1' unless index == 'last()' ......

I think I had noticed in the past that simple buttons and ele_index are returning a different order.

button(1) gives me buttons[1] and I want buttons[0]

Use tags(:UIAButton)[0] or buttons[0]

If you want to check the problem, try the size of each reply if you have buttons.size equal to 5 does the button(5) returns a valid element?

button(1) says return the first button (this follows XPath index rules, 1 is the first element)

buttons says generate a Ruby array (Ruby is 0 indexed) of all buttons. The first button in this array is buttons.first which is buttons[0]. The second button is buttons[1]. Note that the [] syntax is indexing into a Ruby array and those are always zero indexed.

No, it doesn’t. See the code on GitHub:

button(1) gives you buttons[0].

I did more debugging and found that button(3) was buttons[0] and button(1) was the same as buttons[1] for my app

I ran this code while on the page I’m looking at:

def debug_buttons
  sleep 2 #make sure there are no transitions
  buttons =  appium.buttons
  5.times do |index|
    begin
      puts "  Dump button(#{index}):  #{dump appium.button(index)}\n"
    rescue Exception => e
      puts "  Dump button(#{index}):  #{e.to_s}"
    end
    puts "  Dump buttons[#{index}]: #{dump buttons[index]}"
  end
end

def dump element
  "l(#{element.location.x},#{element.location.y}) s(#{element.size.width},#{element.size.height}) text: #{element.text}"
rescue Exception => e
  e.to_s
end

The output I got was

  Dump button(0):  0 is not a valid xpath index. Must be >= 1
  Dump buttons[0]: l(5.859375,31.15625) s(49.21875,35.15625) text: 
  Dump button(1):  l(0,607.71875) s(187.5,58.59375) text: Create a new list
  Dump buttons[1]: l(0,607.71875) s(187.5,58.59375) text: Create a new list
  Dump button(2):  l(187.5,607.71875) s(187.5,58.59375) text: Edit
  Dump buttons[2]: l(187.5,607.71875) s(187.5,58.59375) text: Edit
  Dump button(3):  l(5.859375,31.15625) s(49.21875,35.15625) text: 
  Dump buttons[3]: undefined method `location' for nil:NilClass
  Dump button(4):  An element could not be located on the page using the given search parameters.
  Dump buttons[4]: undefined method `location' for nil:NilClass

I wanted to try this on the iOS sample app however it keeps crashing for me.

Instruments finally stopped crashing. From the output, you can see there are 5 buttons. The button order is as expected. Note that iOS often duplicates elements so it’s not unusual to see the same element more than once. To uniquely identify an element on iOS, you’ll need to look at the path attribute in the xml output.

<UIAElement  path="/0/3/0/1"
[7] pry(main)> buttons_names = buttons.map { |e| e.name }
[
    [0] "Back",
    [1] "Back",
    [2] "Gray",
    [3] "Right pointing arrow",
    [4] "Rounded"
]
[9] pry(main)> button(1).name
"Back"
[10] pry(main)> button(2).name
"Back"
[11] pry(main)> button(3).name
"Gray"
[12] pry(main)> button(4).name
"Right pointing arrow"
[13] pry(main)> button(5).name
"Rounded"

So I guess it just works different for UICatalog than it does for my app. I have a feeling the way my app is built is causing things to be different in a number of areas. I need to learn iOS development.

I wonder if the button method (and friends) should be 0 indexed instead of 1 indexed since most languages are 0 indexed. Watir 1.X was 1 based and it was a pain converting it to 0 based when watir webdriver came out.

The problem is XPath is super popular with appium’s non-technical users and that’s 1 indexed. I think button(1) returning the first button makes more sense for that.

I see the argument in favor of 0 indexing though and that’s how it was setup originally, before xpath was supported. If a bunch of ruby_lib users expressed interest then I’d be open to changing it however it’ll break everyones code.