Keys provided as string in caps being converted to camel case from snake case since selenium v4 base
vm-iiit opened this issue · 27 comments
This is a
- Bug report
- Question
- Freature Request
Summary
Ruby appium is converting capabilities from snake case to camel case
Environment
- Appium version (or git revision): Appium v1.22.0
ruby_lib
version: appium_lib (12.0.1)- Mobile platform/version/device under test: NA
Actual behaviour and steps to reproduce
- Start a local appium server
- Use the following script to start session pass capabilities in snake case
require 'rubygems'
require 'appium_lib'
SERVER_URL = "tcp://localhost:4723/wd/hub"
desired_caps = {
"platformName" => "android",
"device" => "Samsung Galaxy S21 Ultra",
"app" => "/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk", #any local app path
"os_version" => "11.0",
"custom_cap" => "custom_value",
"custom_cap_2" => {
"custom_nested_key" => "custom_value"
},
"custom_cap_3" => {
"custom_nested_key_2" => {
"custom_nested_key_3" => "custom_value"
}
},
}
appium_driver = Appium::Driver.new({
'caps' => desired_caps,
'appium_lib' => {
:server_url => SERVER_URL
}}, true)
driver = appium_driver.start_driver
wait = Selenium::WebDriver::Wait.new(timeout: 40)
driver.quit
- See the caps received by appium server, in my case
[Appium]
[Appium] The next major version of Appium (2.x) will **require** the
[Appium] 'automationName' capability to be set for all sessions on all
[Appium] platforms
[Appium]
[Appium] In previous versions (Appium <= 1.13.x), the default was
[Appium] 'automationName=UiAutomator1'
[Appium]
[Appium] If you wish to use that automation instead of UiAutomator2, please
[Appium] add 'automationName=UiAutomator1' to your desired capabilities
[Appium]
[Appium] For more information about drivers, please visit
[Appium] http://appium.io/docs/en/about-appium/intro/ and explore the
[Appium] 'Drivers' menu
[Appium]
[Appium] ======================================================================
[Appium]
[Appium] Appium v1.22.0 creating new AndroidUiautomator2Driver (v1.69.0) session
[Appium] Applying relaxed security to 'AndroidUiautomator2Driver' as per server command line argument. All insecure features will be enabled unless explicitly disabled by --deny-insecure
[BaseDriver] Creating session with W3C capabilities: {
[BaseDriver] "alwaysMatch": {
[BaseDriver] "platformName": "android",
[BaseDriver] "appium:device": "Samsung Galaxy S21 Ultra",
[BaseDriver] "appium:app": "/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk",
[BaseDriver] "appium:os_version": "11.0",
[BaseDriver] "appium:custom_cap": "custom_value",
[BaseDriver] "appium:custom_cap_2": {
[BaseDriver] "customNestedKey": "custom_value"
[BaseDriver] },
[BaseDriver] "appium:custom_cap_3": {
[BaseDriver] "customNestedKey_2": {
[BaseDriver] "customNestedKey_3": "custom_value"
[BaseDriver] }
[BaseDriver] }
[BaseDriver] },
[BaseDriver] "firstMatch": [
[BaseDriver] {}
[BaseDriver] ]
[BaseDriver] }
[BaseDriver] The following capabilities were provided, but are not recognized by Appium:
[BaseDriver] device
[BaseDriver] os_version
[BaseDriver] custom_cap
[BaseDriver] custom_cap_2
[BaseDriver] custom_cap_3
[BaseDriver] Session created with session id: cc06c35d-3066-4edc-ae56-5154170364f6
[BaseDriver] Using local app '/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk'
[UiAutomator2] Checking whether app is actually present
[ADB] Using 'adb' from '/Users/viratmishra/Library/Android/sdk_old/platform-tools/adb'
[ADB] Running '/Users/viratmishra/Library/Android/sdk_old/platform-tools/adb -P 5037 start-server'
[AndroidDriver] Retrieving device list
[ADB] Trying to find a connected android device
The caps custom_nested_key
, custom_nested_key_2
and custom_nested_key_3
got converted to camelcase when received by appium server: "customNestedKey"
, "customNestedKey_2"
, "customNestedKey_3"
Expected behaviour
Caps should have remained as they were passed, i.e. in snake case, tried with python client as well and this didn't happen there.
Link to Appium/Ruby logs
https://gist.github.com/vm-iiit/f07fc52b1f915f52fd8603e2403d941b
Any additional comments
Selenium client does so when a key does not have a vendor prefix: https://github.com/SeleniumHQ/selenium/blob/604c23b3a5224e9890a80bf5f97e4512d9586ec0/rb/lib/selenium/webdriver/remote/capabilities.rb#L29
I've added more test cases in appium/ruby_lib_core#412 (I already had some of, but did not nested one) and did more investigation. Then, it seems like the converting behavior changed a bit since selenium webdriver v4. Before the v3, it seems like the convert occurred only for symbols, but since selenium webdriver v4, it concerts both string and symbol. It does not happen when the key has a vendor prefix.
hm, but still https://github.com/SeleniumHQ/selenium/blob/trunk/rb/lib/selenium/webdriver/remote/capabilities.rb#L295-L303
let me see something more
Actually this behavior changed since selenium base version updated. Maybe, so far, it is when capabilities class converts its value to JSON to send them to the server.
Potentially this is not this client's issue, but we can ask selenium team about this.
As a workaround, you can use selenium v3 based version, or update your capabilities to follow camel case like JSON mostly follows
Thanks for looking into this so promptly @KazuCocoa .
I still think it's ruby client's issue and not Selenium, reason being that I tried the same thing with python client, and did not encounter this scenario.
Version details
❯ pip3 show Appium-Python-Client ─╯
Name: Appium-Python-Client
Version: 2.7.0
Summary: Python client for Appium
Home-page: http://appium.io/
Author: Isaac Murchie
Author-email: isaac@saucelabs.com
License: Apache 2.0
Location: /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages
Requires: selenium
Required-by:
This is also based on Selenium 4 as per this page
Since v2.0.0, the base selenium client version is v4. The version only works in W3C WebDriver protocol format. If you would like to use the old protocol (MJSONWP), please use v1 Appium Python client.
Test script used
from unittest import TestCase
from appium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
import time
import sys
from selenium.webdriver.common.actions import interaction
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.actions.pointer_input import PointerInput
import base64
import random
hub_url = "0.0.0.0:4723/wd/hub"
desired_caps = {
"app" : "/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk",
"os_version": "11.0",
"platformName": "Android",
"deviceName": "Samsung Galaxy S21 Plus",
"custom_cap" : "custom_value",
"custom_cap_2" : {
"custom_nested_key" : "custom_value"
},
"custom_cap_3" : {
"custom_nested_key_2" : {
"custom_nested_key_3" : "custom_value"
}
},
}
driver = webdriver.Remote(
command_executor=hub_url,
desired_capabilities=desired_caps
)
wait = WebDriverWait(driver, 60)
driver.quit()
Appium server logs
[Appium]
[Appium] In previous versions (Appium <= 1.13.x), the default was
[Appium] 'automationName=UiAutomator1'
[Appium]
[Appium] If you wish to use that automation instead of UiAutomator2, please
[Appium] add 'automationName=UiAutomator1' to your desired capabilities
[Appium]
[Appium] For more information about drivers, please visit
[Appium] http://appium.io/docs/en/about-appium/intro/ and explore the
[Appium] 'Drivers' menu
[Appium]
[Appium] ======================================================================
[Appium]
[Appium] Appium v1.22.0 creating new AndroidUiautomator2Driver (v1.69.0) session
[Appium] Applying relaxed security to 'AndroidUiautomator2Driver' as per server command line argument. All insecure features will be enabled unless explicitly disabled by --deny-insecure
[BaseDriver] Creating session with W3C capabilities: {
[BaseDriver] "alwaysMatch": {
[BaseDriver] "platformName": "Android",
[BaseDriver] "appium:app": "/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk",
[BaseDriver] "appium:os_version": "11.0",
[BaseDriver] "appium:deviceName": "Samsung Galaxy S21 Plus",
[BaseDriver] "appium:custom_cap": "custom_value",
[BaseDriver] "appium:custom_cap_2": {
[BaseDriver] "custom_nested_key": "custom_value"
[BaseDriver] },
[BaseDriver] "appium:custom_cap_3": {
[BaseDriver] "custom_nested_key_2": {
[BaseDriver] "custom_nested_key_3": "custom_value"
[BaseDriver] }
[BaseDriver] }
[BaseDriver] },
[BaseDriver] "firstMatch": [
[BaseDriver] {}
[BaseDriver] ]
[BaseDriver] }
[BaseDriver] The following capabilities were provided, but are not recognized by Appium:
[BaseDriver] os_version
[BaseDriver] custom_cap
[BaseDriver] custom_cap_2
[BaseDriver] custom_cap_3
[BaseDriver] Session created with session id: 682cad7e-aac3-4d6a-827d-dddb03dd085d
[BaseDriver] Using local app '/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk'
[UiAutomator2] Checking whether app is actually present
[ADB] Found 1 'build-tools' folders under '/Users/viratmishra/Library/Android/sdk_old' (newest first):
[ADB] /Users/viratmishra/Library/Android/sdk_old/build-tools/23.0.1
[ADB] Using 'adb' from '/Users/viratmishra/Library/Android/sdk_old/platform-tools/adb'
[ADB] Running '/Users/viratmishra/Library/Android/sdk_old/platform-tools/adb -P 5037 start-server'
[AndroidDriver] Retrieving device list
[ADB] Trying to find a connected android device
[ADB] Getting connected devices
[ADB] No connected devices have been detected
[ADB] Could not find online devices
[ADB] Reconnecting adb (target offline)
[ADB] Running '/Users/viratmishra/Library/Android/sdk_old/platform-tools/adb -P 5037 reconnect offline'
[ADB] Getting connected devices
[ADB] No connected devices have been detected
As for the workaround suggested by you, it also occurred to me but the issue here would be that anyone using a ruby client can pass snake case and it will eventually be treated as valid input since it would be received as camel case whereas Ideally, this should not happen, and in other clients the same input would be invalid.
Also, just to rule out the unlikely possibility of something going wrong during JSON conversion
❯ irb ─╯
2.6.6 :001 > desired_caps = { "custom_cap" => "custom_value", "custom_cap_2" => { "custom_nested_key" => "custom_value" }, "custom_cap_3" => { "custom_nested_key_2" => { "custom_nested_key_3" => "custom_value" } } }
=> {"custom_cap"=>"custom_value", "custom_cap_2"=>{"custom_nested_key"=>"custom_value"}, "custom_cap_3"=>{"custom_nested_key_2"=>{"custom_nested_key_3"=>"custom_value"}}}
2.6.6 :002 > require 'json'
=> true
2.6.6 :003 > dc_json = desired_caps.to_json
=> "{\"custom_cap\":\"custom_value\",\"custom_cap_2\":{\"custom_nested_key\":\"custom_value\"},\"custom_cap_3\":{\"custom_nested_key_2\":{\"custom_nested_key_3\":\"custom_value\"}}}"
2.6.6 :004 > orig_hash = JSON.parse(dc_json)
=> {"custom_cap"=>"custom_value", "custom_cap_2"=>{"custom_nested_key"=>"custom_value"}, "custom_cap_3"=>{"custom_nested_key_2"=>{"custom_nested_key_3"=>"custom_value"}}}
2.6.6 :005 > desired_caps == orig_hash
=> true
2.6.6 :006 >
Sorry, I did not say other selenium clients, just Ruby implementation as my previous links for selenium repository.
Added tests in appium/ruby_lib_core#412 worked as you posted when I downgraded the ruby_lib_core implementation with selenium v3, which behavior was changed in v4 based ruby_lib_core version as you reported.
Maybe related to as_json
/to_json
thing in ::Selenium::WebDriver::Remote::Capabilities
. (I need more time to investigate the cause). So, converting camel case in symbol has been behaved the same, but string changed in them.
this is selenium v3 based one:
[debug] [AndroidUiautomator2Driver@e7b4] "appium:custom_cap": "custom_value",
[debug] [AndroidUiautomator2Driver@e7b4] "appium:custom_cap_2": {
[debug] [AndroidUiautomator2Driver@e7b4] "custom_nested_key": "custom_value"
[debug] [AndroidUiautomator2Driver@e7b4] },
[debug] [AndroidUiautomator2Driver@e7b4] "appium:custom_cap_3": {
[debug] [AndroidUiautomator2Driver@e7b4] "custom_nested_key_2": {
[debug] [AndroidUiautomator2Driver@e7b4] "custom_nested_key_3": "custom_value"
[debug] [AndroidUiautomator2Driver@e7b4] }
[debug] [AndroidUiautomator2Driver@e7b4] },
[debug] [AndroidUiautomator2Driver@e7b4] "appium:language": "en
Probably I found the root cause as #945, I was not sure the root motivation about the method I removed in #945, but it converted keys into symbols forcefully. It was legacy code before I started ruby_lib related code. Nowadays it no makes sense in most cases, so I have removed it.
Then, the caps is now:
[debug] [AndroidUiautomator2Driver@f0cf] "appium:custom_cap": "custom_value",
[debug] [AndroidUiautomator2Driver@f0cf] "appium:custom_cap_2": {
[debug] [AndroidUiautomator2Driver@f0cf] "custom_nested_key": "custom_value"
[debug] [AndroidUiautomator2Driver@f0cf] },
[debug] [AndroidUiautomator2Driver@f0cf] "appium:custom_cap_3": {
[debug] [AndroidUiautomator2Driver@f0cf] "custom_nested_key_2": {
[debug] [AndroidUiautomator2Driver@f0cf] "custom_nested_key_3": "custom_value"
[debug] [AndroidUiautomator2Driver@f0cf] }
[debug] [AndroidUiautomator2Driver@f0cf] },
[debug] [AndroidUiautomator2Driver@f0cf] "appium:language": "en",
Since selenium v4, the converting keys into camel case applied entire nested ones as well, so this issue started. But I think it would be nice to remove legacy code from the ruby_lib_core is more proper than changing selenium side.
Since the change, keys will stay string if given ones were string. Only symbols will keep getting the camel case conversion
Please try out appium_lib_core 5.5.0.
As appium_lib, it needs to be reinstalled or update appium_lib_core dependency to 5.5.0
@KazuCocoa apparently the issue isn't fixed yet.
❯ ruby sample.rb ─╯
No matched driver by platformName: and automationName:
Traceback (most recent call last):
43: from sample.rb:20:in `<main>'
42: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib-12.0.1/lib/appium_lib/driver.rb:516:in `start_driver'
41: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/driver.rb:369:in `start_driver'
40: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/driver.rb:369:in `new'
39: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/common/base/driver.rb:58:in `initialize'
38: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/common/driver.rb:74:in `initialize'
37: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/common/base/driver.rb:72:in `create_bridge'
36: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/common/base/bridge.rb:81:in `create_session'
35: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/bridge.rb:592:in `execute'
34: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/common/base/http_default.rb:97:in `call'
33: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/http/default.rb:103:in `request'
32: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/http/common.rb:83:in `create_response'
31: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/http/common.rb:83:in `new'
30: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/response.rb:35:in `initialize'
29: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/response.rb:56:in `assert_ok'
28: from at processTicksAndRejections (internal/process/task_queues.js:77:11)
27: from at endReadableNT (_stream_readable.js:1168:12)
26: from at IncomingMessage.emit (events.js:208:15)
25: from at IncomingMessage.onEnd (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/raw-body/index.js:273:7)
24: from at done (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/raw-body/index.js:213:7)
23: from at invokeCallback (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/raw-body/index.js:224:16)
22: from at /Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/body-parser/lib/read.js:130:5
21: from at next (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:275:10)
20: from at Function.process_params (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:335:12)
19: from at /Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:284:7
18: from at trim_prefix (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:317:13)
17: from at Layer.handle [as handle_request] (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/layer.js:95:5)
16: from at logger (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/morgan/index.js:144:5)
15: from at next (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:275:10)
14: from at Function.process_params (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:335:12)
13: from at /Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:281:22
12: from at Layer.handle [as handle_request] (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/layer.js:95:5)
11: from at Route.dispatch (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/route.js:112:3)
10: from at next (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/route.js:137:13)
9: from at Layer.handle [as handle_request] (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/layer.js:95:5)
8: from at /Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/protocol/protocol.js:423:15
7: from at asyncHandler (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/protocol/protocol.js:297:34)
6: from at AppiumDriver.executeCommand (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/lib/appium.js:549:26)
5: from at AppiumDriver.executeCommand (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/basedriver/driver.js:349:15)
4: from at commandExecutor (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/basedriver/driver.js:335:9)
3: from at AppiumDriver.createSession (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/lib/appium.js:325:26)
2: from at parseCapsForInnerDriver (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/lib/utils.js:116:21)
1: from at processCapabilities (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/basedriver/capabilities.js:220:13)
InvalidArgumentError: 'platformName' can't be blank: 'platformName' can't be blank (Selenium::WebDriver::Error::InvalidArgumentError)
I've updated the ruby client and core library.
❯ gem list | grep appium ─╯
appium_lib (12.0.1)
appium_lib_core (5.5.0)
Seeing the same behaviour for other existing scripts as well which were working fine.
Script used
require 'rubygems'
require 'appium_lib'
SERVER_URL = "tcp://localhost:4723/wd/hub"
desired_caps = {
"platformName" => "android",
"platformVersion" => "9.0",
"deviceName" => "Google Pixel 3",
"app" => "/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk",
}
appium_driver = Appium::Driver.new({
'caps' => desired_caps,
'appium_lib' => {
:server_url => SERVER_URL
}}, true)
driver = appium_driver.start_driver
wait = Selenium::WebDriver::Wait.new(timeout: 40)
driver.quit
Could you share the appium server log?
Sorry, I'm confusing. The desired capability does not have below capabilities, you originally reported. What do you mean "isn't fixed" without the reported one?
"custom_cap" : "custom_value",
"custom_cap_2" : {
"custom_nested_key" : "custom_value"
},
"custom_cap_3" : {
"custom_nested_key_2" : {
"custom_nested_key_3" : "custom_value"
}
},
The behaviour is same whether I add the above custom caps hash or not, I just excluded them and re-ran to see if the issue is related to them.
Appium server logs
[HTTP] Request idempotency key: 47bccb60-719a-43fa-8140-273e18d71cbe
[HTTP] --> POST /wd/hub/session
[HTTP] {"capabilities":{"alwaysMatch":{},"firstMatch":[{}]}}
[W3C] Calling AppiumDriver.createSession() with args: [null,null,{"alwaysMatch":{},"firstMatch":[{}]}]
[BaseDriver] Event 'newSessionRequested' logged at 1665380198034 (11:06:38 GMT+0530 (India Standard Time))
[BaseDriver] Event 'newSessionStarted' logged at 1665380198035 (11:06:38 GMT+0530 (India Standard Time))
[W3C] Encountered internal error running command: InvalidArgumentError: 'platformName' can't be blank
[W3C] at processCapabilities (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/basedriver/capabilities.js:220:13)
[W3C] at parseCapsForInnerDriver (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/lib/utils.js:116:21)
[W3C] at AppiumDriver.createSession (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/lib/appium.js:325:26)
[W3C] at commandExecutor (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/basedriver/driver.js:335:9)
[W3C] at AppiumDriver.executeCommand (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/basedriver/driver.js:349:15)
[W3C] at AppiumDriver.executeCommand (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/lib/appium.js:549:26)
[W3C] at asyncHandler (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/protocol/protocol.js:297:34)
[W3C] at /Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/protocol/protocol.js:423:15
[W3C] at Layer.handle [as handle_request] (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/layer.js:95:5)
[W3C] at next (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/route.js:137:13)
[W3C] at Route.dispatch (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/route.js:112:3)
[W3C] at Layer.handle [as handle_request] (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/layer.js:95:5)
[W3C] at /Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:281:22
[W3C] at Function.process_params (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:335:12)
[W3C] at next (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:275:10)
[W3C] at logger (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/morgan/index.js:144:5)
[W3C] at Layer.handle [as handle_request] (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/layer.js:95:5)
[W3C] at trim_prefix (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:317:13)
[W3C] at /Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:284:7
[W3C] at Function.process_params (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:335:12)
[W3C] at next (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/express/lib/router/index.js:275:10)
[W3C] at /Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/body-parser/lib/read.js:130:5
[W3C] at invokeCallback (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/raw-body/index.js:224:16)
[W3C] at done (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/raw-body/index.js:213:7)
[W3C] at IncomingMessage.onEnd (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/raw-body/index.js:273:7)
[W3C] at IncomingMessage.emit (events.js:208:15)
[W3C] at endReadableNT (_stream_readable.js:1168:12)
[W3C] at processTicksAndRejections (internal/process/task_queues.js:77:11)
[HTTP] <-- POST /wd/hub/session 400 5 ms - 4077
[HTTP]
Thank you for the log.
Maybe... i guess you set "caps" as string, not symbol. So the fix breaks the case...
appium_driver = Appium::Driver.new({
'caps' => desired_caps,
'appium_lib' => {
:server_url => SERVER_URL
}}, true)
I expected the value was symbol like examples in https://github.com/appium/ruby_lib_core#run-a-test-case and https://github.com/appium/ruby_lib_core#run-a-test-case, but it worked before with the legacy code what I removed one (presented before i started maintain this lib as undocumented behavior) as a fix.
Maybe this client should raise an exception to give the caps
and appium_lib
as symbols when they get string to reduce implicit behavior.
Didn't understand, earlier also we were expecting caps
to be symbol here, right ?
Also, when trying to set caps
as symbol
require 'rubygems'
require 'appium_lib'
SERVER_URL = "tcp://localhost:4723/wd/hub"
desired_caps = {
"platformName" => "android",
"platformVersion" => "9.0",
"deviceName" => "Google Pixel 3",
"app" => "/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk",
}
appium_driver = Appium::Driver.new({
:caps => "desired_caps",
'appium_lib' => {
:server_url => SERVER_URL
}}, true)
driver = appium_driver.start_driver
wait = Selenium::WebDriver::Wait.new(timeout: 40)
driver.quit
❯ ruby sample.rb ─╯
Traceback (most recent call last):
10: from sample.rb:15:in `<main>'
9: from sample.rb:15:in `new'
8: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib-12.0.1/lib/appium_lib/driver.rb:162:in `initialize'
7: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core.rb:48:in `for'
6: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/driver.rb:278:in `for'
5: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/driver.rb:278:in `new'
4: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/driver.rb:297:in `initialize'
3: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/driver.rb:557:in `get_caps'
2: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/driver.rb:557:in `new'
1: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/capabilities.rb:179:in `initialize'
/Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/capabilities.rb:179:in `[]': no implicit conversion of Symbol into Integer (TypeError)
desired_caps = {
"platformName" => "android",
"platformVersion" => "9.0",
"deviceName" => "Google Pixel 3",
"app" => "/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk",
}
appium_driver = Appium::Driver.new({
:caps => desired_caps,
:appium_lib => {
:server_url => SERVER_URL
}}, true)
driver = appium_driver.start_driver
What about this? You set desired_caps
as a string, in the above case.
I'm working on to convert the 'caps' and 'appium_lib' into symbol with deprecation message to keep only the top level behavior for compatibility.
Sorry, my bad. Sharing logs
require 'rubygems'
require 'appium_lib'
SERVER_URL = "tcp://localhost:4723/wd/hub"
desired_caps = {
"platformName" => "android",
"platformVersion" => "9.0",
"deviceName" => "Google Pixel 3",
"app" => "/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk",
"custom_cap" => "custom_value",
"custom_cap_2" => {
"custom_nested_key" => "custom_value"
},
"custom_cap_3" => {
"custom_nested_key_2" => {
"custom_nested_key_3" => "custom_value"
}
},
}
appium_driver = Appium::Driver.new({
:caps => desired_caps,
'appium_lib' => {
:server_url => SERVER_URL
}}, true)
driver = appium_driver.start_driver
wait = Selenium::WebDriver::Wait.new(timeout: 40)
driver.quit
[BaseDriver] Event 'newSessionRequested' logged at 1665385100779 (12:28:20 GMT+0530 (India Standard Time))
[Appium]
[Appium] ======================================================================
[Appium] DEPRECATION WARNING:
[Appium]
[Appium] The 'automationName' capability was not provided in the desired
[Appium] capabilities for this Android session
[Appium]
[Appium] Setting 'automationName=UiAutomator2' by default and using the
[Appium] UiAutomator2 Driver
[Appium]
[Appium] The next major version of Appium (2.x) will **require** the
[Appium] 'automationName' capability to be set for all sessions on all
[Appium] platforms
[Appium]
[Appium] In previous versions (Appium <= 1.13.x), the default was
[Appium] 'automationName=UiAutomator1'
[Appium]
[Appium] If you wish to use that automation instead of UiAutomator2, please
[Appium] add 'automationName=UiAutomator1' to your desired capabilities
[Appium]
[Appium] For more information about drivers, please visit
[Appium] http://appium.io/docs/en/about-appium/intro/ and explore the
[Appium] 'Drivers' menu
[Appium]
[Appium] ======================================================================
[Appium]
[Appium] Appium v1.22.0 creating new AndroidUiautomator2Driver (v1.69.0) session
[Appium] Applying relaxed security to 'AndroidUiautomator2Driver' as per server command line argument. All insecure features will be enabled unless explicitly disabled by --deny-insecure
[BaseDriver] Creating session with W3C capabilities: {
[BaseDriver] "alwaysMatch": {
[BaseDriver] "platformName": "android",
[BaseDriver] "appium:platformVersion": "9.0",
[BaseDriver] "appium:deviceName": "Google Pixel 3",
[BaseDriver] "appium:app": "/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk",
[BaseDriver] "appium:custom_cap": "custom_value",
[BaseDriver] "appium:custom_cap_2": {
[BaseDriver] "custom_nested_key": "custom_value"
[BaseDriver] },
[BaseDriver] "appium:custom_cap_3": {
[BaseDriver] "custom_nested_key_2": {
[BaseDriver] "custom_nested_key_3": "custom_value"
[BaseDriver] }
[BaseDriver] }
[BaseDriver] },
[BaseDriver] "firstMatch": [
[BaseDriver] {}
[BaseDriver] ]
[BaseDriver] }
[BaseDriver] The following capabilities were provided, but are not recognized by Appium:
[BaseDriver] custom_cap
[BaseDriver] custom_cap_2
[BaseDriver] custom_cap_3
[BaseDriver] Session created with session id: 4c895d9f-0bbe-49cb-b0ce-e321381f802f
[BaseDriver] Using local app '/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk'
[UiAutomator2] Checking whether app is actually present
[ADB] Using 'adb' from '/Users/viratmishra/Library/Android/sdk_old/platform-tools/adb'
[ADB] Running '/Users/viratmishra/Library/Android/sdk_old/platform-tools/adb -P 5037 start-server'
[AndroidDriver] Retrieving device list
[ADB] Trying to find a connected android device
[ADB] Getting connected devices
[ADB] No connected devices have been detected
Script output
❯ ruby sample.rb ─╯
No matched driver by platformName: and automationName:
Traceback (most recent call last):
17: from sample.rb:29:in `<main>'
16: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib-12.0.1/lib/appium_lib/driver.rb:516:in `start_driver'
15: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/driver.rb:369:in `start_driver'
14: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/driver.rb:369:in `new'
13: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/common/base/driver.rb:58:in `initialize'
12: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/common/driver.rb:74:in `initialize'
11: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/common/base/driver.rb:72:in `create_bridge'
10: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/common/base/bridge.rb:81:in `create_session'
9: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/bridge.rb:592:in `execute'
8: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib_core-5.5.0/lib/appium_lib_core/common/base/http_default.rb:97:in `call'
7: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/http/default.rb:103:in `request'
6: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/http/common.rb:83:in `create_response'
5: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/http/common.rb:83:in `new'
4: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/response.rb:35:in `initialize'
3: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/response.rb:56:in `assert_ok'
2: from at asyncHandler (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/protocol/protocol.js:380:37)
1: from at getResponseForW3CError (/Applications/Appium Server GUI.app/Contents/Resources/app/node_modules/appium/node_modules/appium-base-driver/lib/protocol/errors.js:804:9)
UnknownError: An unknown server-side error occurred while processing the command. Original error: Could not find a connected Android device in 20090ms.: An unknown server-side error occurred while processing the command. Original error: Could not find a connected Android device in 20090ms. (Selenium::WebDriver::Error::UnknownError)
I see, thanks.
Quoted from #945 (comment):
[BaseDriver] custom_cap_3
[BaseDriver] Session created with session id: 682cad7e-aac3-4d6a-827d-dddb03dd085d
[BaseDriver] Using local app '/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk'
[UiAutomator2] Checking whether app is actually present
[ADB] Found 1 'build-tools' folders under '/Users/viratmishra/Library/Android/sdk_old' (newest first):
[ADB] /Users/viratmishra/Library/Android/sdk_old/build-tools/23.0.1
[ADB] Using 'adb' from '/Users/viratmishra/Library/Android/sdk_old/platform-tools/adb'
[ADB] Running '/Users/viratmishra/Library/Android/sdk_old/platform-tools/adb -P 5037 start-server'
[AndroidDriver] Retrieving device list
[ADB] Trying to find a connected android device
[ADB] Getting connected devices
[ADB] No connected devices have been detected
[ADB] Could not find online devices
[ADB] Reconnecting adb (target offline)
[ADB] Running '/Users/viratmishra/Library/Android/sdk_old/platform-tools/adb -P 5037 reconnect offline'
[ADB] Getting connected devices
[ADB] No connected devices have been detected
So, the appium server seems the same. The error message indicates the host did not have Google Pixel 3
emulator. The Python example also said no connected devices. So, the fix itself worked as expected for the reported issue
@KazuCocoa yes, the snake case capabilities now persists in snake case and do no get converted to camel case. However, if you see the script output
No matched driver by platformName: and automationName:
This error gets raised from here
I tried passing both "android"
and :android
in "platformName"
capability - same behaviour.
Then checked the code and found out that @device
gets populated here which is being used in above error logline as device
So tried using :platformName
in place of "platformName"
and then I am not seeing the above error.
Yes, appium/ruby_lib_core#414 will keep the converting behavior until the keys in capabilities like platformName
. The root cause was the removed one affected other capability handlings in some places since my previous understanding also affected by the removed one. I'll work on some update to fix the internal handling issue after the 414 PR to remove the legacy code.
btw, appium_lib_core 5.5.1 has the fix
Still getting error, a different one though
❯ ruby sample.rb ─╯
[Deprecation] The key 'platformVersion' must be a symbol while currently it is String. Please define the key as a Symbol. Converting it to Symbol for now.
[Deprecation] The key 'deviceName' must be a symbol while currently it is String. Please define the key as a Symbol. Converting it to Symbol for now.
[Deprecation] The key 'app' must be a symbol while currently it is String. Please define the key as a Symbol. Converting it to Symbol for now.
[Deprecation] The key 'custom_cap' must be a symbol while currently it is String. Please define the key as a Symbol. Converting it to Symbol for now.
[Deprecation] The key 'custom_cap_2' must be a symbol while currently it is String. Please define the key as a Symbol. Converting it to Symbol for now.
[Deprecation] The key 'custom_cap_3' must be a symbol while currently it is String. Please define the key as a Symbol. Converting it to Symbol for now.
[Deprecation] The key 'appium_lib' must be a symbol while currently it is String. Please define the key as a Symbol. Converting it to Symbol for now.
[Deprecation] The key 'appium_lib' must be a symbol while currently it is String. Please define the key as a Symbol. Converting it to Symbol for now.
Traceback (most recent call last):
4: from sample.rb:24:in `<main>'
3: from sample.rb:24:in `new'
2: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib-12.0.1/lib/appium_lib/driver.rb:181:in `initialize'
1: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib-12.0.1/lib/appium_lib/driver.rb:256:in `set_app_path'
/Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib-12.0.1/lib/appium_lib/driver.rb:387:in `absolute_app_path': absolute_app_path invoked and app is not set! (RuntimeError)
script
require 'rubygems'
require 'appium_lib'
SERVER_URL = "tcp://localhost:4723/wd/hub"
desired_caps = {
:platformName => "android",
"platformVersion" => "9.0",
"deviceName" => "Google Pixel 3",
"app" => "/Users/viratmishra/Downloads/fast-speed-test-1-0-5.apk",
"custom_cap" => "custom_value",
"custom_cap_2" => {
"custom_nested_key" => "custom_value"
},
"custom_cap_3" => {
"custom_nested_key_2" => {
"custom_nested_key_3" => "custom_value"
}
},
}
appium_driver = Appium::Driver.new({
:caps => desired_caps,
'appium_lib' => {
:server_url => SERVER_URL
}}, true)
driver = appium_driver.start_driver
wait = Selenium::WebDriver::Wait.new(timeout: 40)
driver.quit
Exception being raised from here
❯ gem list | grep appium ─╯
appium_lib (12.0.1)
appium_lib_core (5.5.1)
thanks.
ruby_lib_core 5.5.2 will prevent printing the deprecation messages. (Sorry they were enabled for debugging)
ruby_lib 12.1.0 will have the fix
Hey @KazuCocoa , apologies for the late reply, the above script runs fine. However, when running a different ruby script, I am getting error.
❯ ruby prod_android.rb ─╯
[Deprecation] The key 'caps' must be a symbol while currently it is String. Please define the key as a Symbol. Converting it to Symbol for now.
[Deprecation] The key 'appium_lib' must be a symbol while currently it is String. Please define the key as a Symbol. Converting it to Symbol for now.
[Deprecation] The key 'caps' must be a symbol while currently it is String. Please define the key as a Symbol. Converting it to Symbol for now.
[Deprecation] The key 'appium_lib' must be a symbol while currently it is String. Please define the key as a Symbol. Converting it to Symbol for now.
Traceback (most recent call last):
4: from prod_android.rb:46:in `<main>'
3: from prod_android.rb:46:in `new'
2: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib-12.1.0/lib/appium_lib/driver.rb:181:in `initialize'
1: from /Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib-12.1.0/lib/appium_lib/driver.rb:265:in `set_app_path'
/Users/viratmishra/.rvm/gems/ruby-2.7.2/gems/appium_lib-12.1.0/lib/appium_lib/driver.rb:395:in `absolute_app_path': undefined method `warning' for Appium::Logger:Module (NoMethodError)
Did you mean? warn
oh, sorry, its my bad
12.1.1 has the fix