Ruby Appium::TouchAction .perform returns error - Method has not yet been implemented

I’m quiet new to Appium so maybe this is really simple to answer, but I just don’t know what to do next.

Setup:
Appium server 1.6.5
Ruby 2.3.3 (32 bit)
Android Phone (Nexus 5) connected via usb
gems:

  • appium_lib 9.5.0 & 9.6.0
  • selenium-webdriver 3.5.1

Script

require 'appium_lib'
capabilities = {
    deviceName:        'Nexus5',
    browserName:	   'chrome',
    platformName:      :android,
    newCommandTimeout: 15000,
}
appium = Appium::Driver.new(caps: capabilities)
driver = appium.start_driver
driver.get("https://www.google.nl")

Action I want to perform
Now I want to tap/press on any location on the screen (preferably on a certain element, but let’s take smaller steps)

I tried, but I get the error

irb(main):014:0> appium.tap(x:900, y:670).perform
ArgumentError: wrong number of arguments (given 1, expected 0)
        from (irb):14:in `tap'
        from (irb):14
        from C:/Ruby23/bin/irb.cmd:19:in `<main>'
irb(main):015:0> action = Appium::TouchAction.new
=> #<Appium::TouchAction:0x3426528 @actions=[]>
irb(main):016:0> action.tap(x:900, y:670).perform
Selenium::WebDriver::Error::UnknownError: Method has not yet been implemented
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/response.rb:69:in `assert_ok'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/response.rb:32:in `initialize'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/http/common.rb:83:in `new'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/http/common.rb:83:in `create_response'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/http/default.rb:107:in `request'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/http/common.rb:61:in `call'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/bridge.rb:170:in `execute'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/oss/bridge.rb:579:in `execute'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/appium_lib-9.5.0/lib/appium_lib/device/device.rb:488:in `touch_actions'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/appium_lib-9.5.0/lib/appium_lib/device/touch_actions.rb:180:in `perform'
        from (irb):16
        from C:/Ruby23/bin/irb.cmd:19:in `<main>'
irb(main):017:0> tap = action.tap(x:900, y:670)
=> #<Appium::TouchAction:0x3426528 @actions=[{:action=>:tap, :options=>{:x=>900, :y=>670, :count=>1}}, {:action=>:tap, :options=>{:x=>900, :y=>670, :count=>1}}]>
irb(main):018:0> tap.perform
Selenium::WebDriver::Error::UnknownError: Method has not yet been implemented
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/response.rb:69:in `assert_ok'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/response.rb:32:in `initialize'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/http/common.rb:83:in `new'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/http/common.rb:83:in `create_response'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/http/default.rb:107:in `request'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/http/common.rb:61:in `call'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/bridge.rb:170:in `execute'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/oss/bridge.rb:579:in `execute'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/appium_lib-9.5.0/lib/appium_lib/device/device.rb:488:in `touch_actions'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/appium_lib-9.5.0/lib/appium_lib/device/touch_actions.rb:180:in `perform'
        from (irb):18
        from C:/Ruby2

I did read about similar issues, like TouchAction().perform() - Method has not yet been implemented
But that did not give me enough information to understand what I’m doing wrong. It must be something small since I see examples that work. If someone could point me to information to understand the issue that would also be helpful.

I read some people mentioning in the Java examles to use the Android driver.
But when I was reading this document I think I already do that with the platformName :android capability.
Also when I read this documentation about the appium_lib I used the exact copy of that code to start the driver (so far so good) but again when performing a tap I get the same error message as the one I just have with my example.
http://www.rubydoc.info/github/appium/ruby_lib/Appium/Driver

So I’m clueless about what is going wrong. Is it my setup or is it a bug?

@mark0203 same examples in case:

  1. https://github.com/appium/ruby_lib/blob/master/android_tests/lib/android/specs/common/device_touchaction.rb
  2. https://github.com/appium/ruby_lib/blob/master/android_tests/lib/android/specs/common/web_context.rb

How about press, release and perform mentioned the above comment?
I guess if press and release work well, tap command’s count parameter is wrong for current spec. (the tap method hasn’t been changed for three years.

I forgot to mention I also tried press. Results are the same as tap.
Here I use the example where I press on a certain element

irb(main):045:0>   e =driver.find_element(:id, 'lst-ib')
=> #<Selenium::WebDriver::Element:0x..f926f926a id="0.9853208960371109-1">
irb(main):046:0>   touch_action = Appium::TouchAction.new.press(element: e, x: 0.5, y: 0.5).release(element: e)
=> #<Appium::TouchAction:0x2f651d0 @actions=[{:action=>:press, :options=>{:element=>"0.9853208960371109-1", :x=>0.5, :y=>0.5}}, {:action=>:release, :options=>{:element=>"0.9853208960371109-1"}}]>
irb(main):047:0>   touch_action.perform
Selenium::WebDriver::Error::UnknownError: Method has not yet been implemented
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/response.rb:69:in `assert_ok'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/response.rb:32:in `initialize'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/http/common.rb:83:in `new'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/http/common.rb:83:in `create_response'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/http/default.rb:107:in `request'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/http/common.rb:61:in `call'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/bridge.rb:170:in `execute'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/selenium-webdriver-3.5.1/lib/selenium/webdriver/remote/oss/bridge.rb:579:in `execute'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/appium_lib-9.6.0/lib/appium_lib/device/device.rb:478:in `touch_actions'
        from C:/Ruby23/lib/ruby/gems/2.3.0/gems/appium_lib-9.6.0/lib/appium_lib/device/touch_actions.rb:188:in `perform'
        from (irb):47
        from C:/Ruby23/bin/irb.cmd:19:in `<main>'

I did read something about not needing to switch context when you test a website (because it’s not a app native/hybrid, but always a webview). If that is not the case let me know how to do this.
I tried the examples, but I’m not 100% sure how to use this (see below)

irb(main):050:0> browser.contexts = available_contexts
NameError: undefined local variable or method `available_contexts' for main:Object
        from (irb):50
        from C:/Ruby23/bin/irb.cmd:19:in `<main>'
irb(main):051:0> contexts = available_contexts
NameError: undefined local variable or method `available_contexts' for main:Object
        from (irb):51
        from C:/Ruby23/bin/irb.cmd:19:in `<main>'
irb(main):052:0>
irb(main):053:0> contexts = Appium::Device.available_contexts
NoMethodError: undefined method `available_contexts' for Appium::Device:Module
        from (irb):53
        from C:/Ruby23/bin/irb.cmd:19:in `<main>'

I’ve confirmed the behaviour in https://github.com/appium/ruby_lib/pull/646/files and tap works well for NATIVE_APP. If webview context, current behaviour is expected: https://github.com/appium/appium/issues/9040 . You can find Touch Actions and Mobile Web for web context.

For available_contexts, I guess you should call driver.available_contexts. Could you try to driver.available_contexts after driver = appium.start_driver?
@mark0203

@KazuCocoa thnx, that was the mistake I made, wrong object.

irb(main):010:0> contexts = driver.available_contexts
=> ["NATIVE_APP", "CHROMIUM"]

So now it seems to work like this

appium = Appium::Driver.new(caps: capabilities)
driver = appium.start_driver

contexts = driver.available_contexts
=> ["NATIVE_APP", "CHROMIUM"]
current_context = driver.current_context
=> "CHROMIUM"

webview_context = contexts.detect { |e| e.start_with?('WEBVIEW') }
=> nil
nativeview_context = contexts.detect { |e| e.start_with?('NATIVE_APP') }
=> "NATIVE_APP"
chromiumview_context = contexts.detect { |e| e.start_with?('CHROMIUM') }
=> "CHROMIUM"
driver.get("https://www.google.nl")

driver.set_context nativeview_context

elm = driver.find_element(:id, 'lst-ib')

tap_action = Appium::TouchAction.new.tap(element: e, x:0.5, y:0.5)
tap_action.perform

Many thanks, this was what I was looking for.

1 Like

require ‘rubygems’
require ‘appium_lib_core’

opts = {
desired_capabilities: { # or { caps: {…} }
platformName: :ios,
platformVersion: ‘14.2’,
deviceName: ‘iPhone 8 Plus’,
automationName: ‘XCUITest’,
uuid: ‘599D9064-42E5-45C4-A47F-EBAA320FC312’,
app: ‘/Development.app’
},
appium_lib: {
wait: 30
}
}
@core = Appium::Core.for(opts) # create a core driver with opts
@driver = @core.start_driver
@driver.available_contexts

#1. allow location
TouchAction.new(@driver).press(x: 199, y: 527).perform

Why I run this code still have error: uninitialized constant TouchAction (NameError)

Why I run this code still have error: uninitialized constant TouchAction (NameError)

How about calling it as Appium::Core::TouchAction.new()? (Full module path)