Skip to content

fix: Update "find elements using"-strings - #334

Closed
hanneshauer wants to merge 1 commit into
appium:masterfrom
hanneshauer:hanneshauer-fix-findelements-strings
Closed

fix: Update "find elements using"-strings#334
hanneshauer wants to merge 1 commit into
appium:masterfrom
hanneshauer:hanneshauer-fix-findelements-strings

Conversation

@hanneshauer

@hanneshauerhanneshauer commented May 23, 2020

Copy link
Copy Markdown

Problem

Appium-clients can't use the iOS Class Chain and iOS Predicate String queries because the strings WDA expects don't match the strings the clients send.

Expected behaviour

When the client (I'm using the Python-client, but behaviour in other clients should be the same) requests to find elements using a class chain or predicate string WebElements matching the query should be returned if any are found.

>>>s.wd.find_element_by_ios_class_chain('XCUIElementTypeAny')
# Sent request: URL: http://10.10.10.120:8100/session/B2C73E2E-0FDE-44FF-8321-A193F36BE13E/element, data: {"using": "-ios class chain", "value": "XCUIElementTypeAny"}<appium.webdriver.webelement.WebElement (session="B2C73E2E-0FDE-44FF-8321-A193F36BE13E", element="04000000-0000-0000-813C-000000000000")>>>>s.wd.find_element_by_ios_predicate('visible == 1')
# Sent request: URL: http://10.10.10.120:8100/session/B2C73E2E-0FDE-44FF-8321-A193F36BE13E/element, data: {"using": "-ios predicate string", "value": "visible == 1"}<appium.webdriver.webelement.WebElement (session="B2C73E2E-0FDE-44FF-8321-A193F36BE13E", element="01000000-0000-0000-813C-000000000000")>

Actual behaviour

Requesting to find elements results in an error because the WDA doesn't know how to handle the strings sent by the client.

>>>s.wd.find_element_by_ios_class_chain('XCUIElementTypeAny')
# Sent request: URL: http://10.10.10.120:8100/session/C953E926-BEC0-4A35-9D6A-ABEAECB6C18E/element, data: {"using": "-ios class chain", "value": "XCUIElementTypeAny"}responsevalue: {
"value" : {
"error" : "invalid argument",
"message" : "Invalid locator requested: -ios class chain",
"traceback" : "(\n\t0 CoreFoundation 0x00000001899969a4 <redacted> + 252\n\t1 libobjc.A.dylib 0x0000000188b6f9f8 objc_exception_throw + 56\n\t2 CoreFoundation 0x00000001898b3e10 <redacted> + 0\n\t3 WebDriverAgentLib 0x0000000102b85a50 +[FBFindElementCommands elementsUsing:withValue:under:shouldReturnAfterFirstMatch:] + 1412\n\t4 WebDriverAgentLib 0x0000000102b85468 +[FBFindElementCommands elementUsing:withValue:under:] + 148\n\t5 WebDriverAgentLib 0x0000000102b8419c +[FBFindElementCommands handleFindElement:] + 380\n\t6 WebDriverAgentLib 0x0000000102b6304c -[FBRoute_TargetAction mountRequest:intoResponse:] + 212\n\t7 WebDriverAgentLib 0x0000000102b4cc44 __37-[FBWebServer registerRouteHandlers:]_block_invoke + 492\n\t8 RoutingHTTPServer 0x0000000102c6e490 -[RoutingHTTPServer handleRoute:withRequest:response:] + 144\n\t9 RoutingHTTPServer 0x0000000102c6ec50 __72-[RoutingHTTPServer routeMethod:withPath:parameters:request:connection:]_block_invoke + 44\n\t10 libdispatch.dylib 0x00000001893d57d4 <redacted> + 16\n\t11 libdispatch.dylib 0x0000000189383cec <redacted> + 92\n\t12 libdispatch.dylib 0x00000001893d57d4 <redacted> + 16\n\t13 libdispatch.dylib 0x0000000189383008 <redacted> + 1068\n\t14 CoreFoundation 0x000000018992832c <redacted> + 12\n\t15 CoreFoundation 0x0000000189923264 <redacted> + 1924\n\t16 CoreFoundation 0x00000001899227c0 CFRunLoopRunSpecific + 436\n\t17 Foundation 0x000000018a2f0eac <redacted> + 300\n\t18 WebDriverAgentLib 0x0000000102b4b6fc -[FBWebServer startServing] + 440\n\t19 WebDriverAgentRunner 0x00000001028e7bac -[UITestingUITests testRunner] + 116\n\t20 CoreFoundation 0x000000018999e010 <redacted> + 144\n\t21 CoreFoundation 0x000000018987fbe0 <redacted> + 292\n\t22 XCTest 0x00000001010c55f4 __24-[XCTestCase invokeTest]_block_invoke_3 + 52\n\t23 XCTest 0x00000001010c55a4 __24-[XCTestCase invokeTest]_block_invoke_2 + 312\n\t24 XCTest 0x00000001011353c0 -[XCTMemoryChecker _assertInvalidObjectsDeallocatedAfterScope:] + 68\n\t25 XCTest 0x00000001010cffe0 -[XCTestCase assertInvalidObjectsDeallocatedAfterScope:] + 112\n\t26 XCTest 0x00000001010c543c __24-[XCTestCase invokeTest]_block_invoke.206 + 200\n\t27 XCTest 0x000000010111c0d8 +[XCTestCase(Failures) performFailableBlock:testCase:testCaseRun:shouldInterruptTest:] + 84\n\t28 XCTest 0x000000010111bfdc -[XCTestCase(Failures) _performTurningExceptionsIntoFailuresInterruptAfterHandling:block:] + 132\n\t29 XCTest 0x00000001010c4ef0 -[XCTestCase invokeTest] + 1120\n\t30 XCTest 0x00000001010c68b8 __26-[XCTestCase performTest:]_block_invoke_2 + 44\n\t31 XCTest 0x000000010111c0d8 +[XCTestCase(Failures) performFailableBlock:testCase:testCaseRun:shouldInterruptTest:] + 84\n\t32 XCTest 0x000000010111bfdc -[XCTestCase(Failures) _performTurningExceptionsIntoFailuresInterruptAfterHandling:block:] + 132\n\t33 XCTest 0x00000001010c67f0 __26-[XCTestCase performTest:]_block_invoke.366 + 96\n\t34 XCTest 0x000000010112e48c +[XCTContext runInContextForTestCase:block:] + 212\n\t35 XCTest 0x00000001010c60dc -[XCTestCase performTest:] + 540\n\t36 XCTest 0x000000010110986c -[XCTest runTest] + 60\n\t37 XCTest 0x00000001010c05c8 __27-[XCTestSuite performTest:]_block_invoke + 268\n\t38 XCTest 0x00000001010bfe58 __59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 40\n\t39 XCTest 0x000000010112e48c +[XCTContext runInContextForTestCase:block:] + 212\n\t40 XCTest 0x00000001010bfe00 -[XCTestSuite _performProtectedSectionForTest:testSection:] + 156\n\t41 XCTest 0x00000001010c0150 -[XCTestSuite performTest:] + 320\n\t42 XCTest 0x000000010110986c -[XCTest runTest] + 60\n\t43 XCTest 0x00000001010c05c8 __27-[XCTestSuite performTest:]_block_invoke + 268\n\t44 XCTest 0x00000001010bfe58 __59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 40\n\t45 XCTest 0x000000010112e48c +[XCTContext runInContextForTestCase:block:] + 212\n\t46 XCTest 0x00000001010bfe00 -[XCTestSuite _performProtectedSectionForTest:testSection:] + 156\n\t47 XCTest 0x00000001010c0150 -[XCTestSuite performTest:] + 320\n\t48 XCTest 0x000000010110986c -[XCTest runTest] + 60\n\t49 XCTest 0x00000001010c05c8 __27-[XCTestSuite performTest:]_block_invoke + 268\n\t50 XCTest 0x00000001010bfe58 __59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 40\n\t51 XCTest 0x000000010112e48c +[XCTContext runInContextForTestCase:block:] + 212\n\t52 XCTest 0x00000001010bfe00 -[XCTestSuite _performProtectedSectionForTest:testSection:] + 156\n\t53 XCTest 0x00000001010c0150 -[XCTestSuite performTest:] + 320\n\t54 XCTest 0x000000010110986c -[XCTest runTest] + 60\n\t55 XCTest 0x00000001011405f0 __44-[XCTTestRunSession runTestsAndReturnError:]_block_invoke + 176\n\t56 XCTest 0x00000001011406f0 __44-[XCTTestRunSession runTestsAndReturnError:]_block_invoke.100 + 108\n\t57 XCTest 0x00000001010da354 -[XCTestObservationCenter _observeTestExecutionForBlock:] + 588\n\t58 XCTest 0x0000000101140388 -[XCTTestRunSession runTestsAndReturnError:] + 592\n\t59 XCTest 0x00000001010a4bbc -[XCTestDriver runTestsAndReturnError:] + 428\n\t60 XCTest 0x000000010112a424 _XCTestMain + 2396\n\t61 WebDriverAgentRunner-Runner 0x0000000100bdb818 -[_XCTRunnerAppDelegate applicationWillResignActive:] + 0\n\t62 WebDriverAgentRunner-Runner 0x0000000100bdb720 _XCTRunnerRunTests + 0\n\t63 CoreFoundation 0x0000000189928578 <redacted> + 20\n\t64 CoreFoundation 0x0000000189927e7c <redacted> + 272\n\t65 CoreFoundation 0x0000000189922ee0 <redacted> + 1024\n\t66 CoreFoundation 0x00000001899227c0 CFRunLoopRunSpecific + 436\n\t67 GraphicsServices 0x000000018bb2379c GSEventRunModal + 104\n\t68 UIKitCore 0x00000001b62a1c38 UIApplicationMain + 212\n\t69 WebDriverAgentRunner-Runner 0x0000000100bdb9e4 main + 192\n\t70 libdyld.dylib 0x00000001893e68e0 <redacted> + 4\n)"
},
"sessionId" : "C953E926-BEC0-4A35-9D6A-ABEAECB6C18E"
}
Traceback (mostrecentcalllast):
File"<stdin>", line1, in<module>File"xxx/env/lib/python3.7/site-packages/appium/webdriver/extensions/search_context/ios.py", line104, infind_element_by_ios_class_chainreturnself.find_element(by=MobileBy.IOS_CLASS_CHAIN, value=class_chain_string)
File"xxx/env/lib/python3.7/site-packages/appium/webdriver/webdriver.py", line284, infind_element'value': value})['value']
File"xxx/env/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line321, inexecuteself.error_handler.check_response(response)
File"xxx/env/lib/python3.7/site-packages/appium/webdriver/errorhandler.py", line24, incheck_responsesuper(MobileErrorHandler, self).check_response(response)
File"xxx/env/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py", line131, incheck_responsestatus=value["status"]
KeyError: 'status'>>>s.wd.find_element_by_ios_predicate('visible == 1')
Sentrequest: URL: http://10.10.10.120:8100/session/C953E926-BEC0-4A35-9D6A-ABEAECB6C18E/element, data: {"using": "-ios predicate string", "value": "visible == 1"}
responsevalue: {
"value" : {
"error" : "invalid argument",
"message" : "Invalid locator requested: -ios predicate string",
"traceback" : "(\n\t0 CoreFoundation 0x00000001899969a4 <redacted> + 252\n\t1 libobjc.A.dylib 0x0000000188b6f9f8 objc_exception_throw + 56\n\t2 CoreFoundation 0x00000001898b3e10 <redacted> + 0\n\t3 WebDriverAgentLib 0x0000000102b85a50 +[FBFindElementCommands elementsUsing:withValue:under:shouldReturnAfterFirstMatch:] + 1412\n\t4 WebDriverAgentLib 0x0000000102b85468 +[FBFindElementCommands elementUsing:withValue:under:] + 148\n\t5 WebDriverAgentLib 0x0000000102b8419c +[FBFindElementCommands handleFindElement:] + 380\n\t6 WebDriverAgentLib 0x0000000102b6304c -[FBRoute_TargetAction mountRequest:intoResponse:] + 212\n\t7 WebDriverAgentLib 0x0000000102b4cc44 __37-[FBWebServer registerRouteHandlers:]_block_invoke + 492\n\t8 RoutingHTTPServer 0x0000000102c6e490 -[RoutingHTTPServer handleRoute:withRequest:response:] + 144\n\t9 RoutingHTTPServer 0x0000000102c6ec50 __72-[RoutingHTTPServer routeMethod:withPath:parameters:request:connection:]_block_invoke + 44\n\t10 libdispatch.dylib 0x00000001893d57d4 <redacted> + 16\n\t11 libdispatch.dylib 0x0000000189383cec <redacted> + 92\n\t12 libdispatch.dylib 0x00000001893d57d4 <redacted> + 16\n\t13 libdispatch.dylib 0x0000000189383008 <redacted> + 1068\n\t14 CoreFoundation 0x000000018992832c <redacted> + 12\n\t15 CoreFoundation 0x0000000189923264 <redacted> + 1924\n\t16 CoreFoundation 0x00000001899227c0 CFRunLoopRunSpecific + 436\n\t17 Foundation 0x000000018a2f0eac <redacted> + 300\n\t18 WebDriverAgentLib 0x0000000102b4b6fc -[FBWebServer startServing] + 440\n\t19 WebDriverAgentRunner 0x00000001028e7bac -[UITestingUITests testRunner] + 116\n\t20 CoreFoundation 0x000000018999e010 <redacted> + 144\n\t21 CoreFoundation 0x000000018987fbe0 <redacted> + 292\n\t22 XCTest 0x00000001010c55f4 __24-[XCTestCase invokeTest]_block_invoke_3 + 52\n\t23 XCTest 0x00000001010c55a4 __24-[XCTestCase invokeTest]_block_invoke_2 + 312\n\t24 XCTest 0x00000001011353c0 -[XCTMemoryChecker _assertInvalidObjectsDeallocatedAfterScope:] + 68\n\t25 XCTest 0x00000001010cffe0 -[XCTestCase assertInvalidObjectsDeallocatedAfterScope:] + 112\n\t26 XCTest 0x00000001010c543c __24-[XCTestCase invokeTest]_block_invoke.206 + 200\n\t27 XCTest 0x000000010111c0d8 +[XCTestCase(Failures) performFailableBlock:testCase:testCaseRun:shouldInterruptTest:] + 84\n\t28 XCTest 0x000000010111bfdc -[XCTestCase(Failures) _performTurningExceptionsIntoFailuresInterruptAfterHandling:block:] + 132\n\t29 XCTest 0x00000001010c4ef0 -[XCTestCase invokeTest] + 1120\n\t30 XCTest 0x00000001010c68b8 __26-[XCTestCase performTest:]_block_invoke_2 + 44\n\t31 XCTest 0x000000010111c0d8 +[XCTestCase(Failures) performFailableBlock:testCase:testCaseRun:shouldInterruptTest:] + 84\n\t32 XCTest 0x000000010111bfdc -[XCTestCase(Failures) _performTurningExceptionsIntoFailuresInterruptAfterHandling:block:] + 132\n\t33 XCTest 0x00000001010c67f0 __26-[XCTestCase performTest:]_block_invoke.366 + 96\n\t34 XCTest 0x000000010112e48c +[XCTContext runInContextForTestCase:block:] + 212\n\t35 XCTest 0x00000001010c60dc -[XCTestCase performTest:] + 540\n\t36 XCTest 0x000000010110986c -[XCTest runTest] + 60\n\t37 XCTest 0x00000001010c05c8 __27-[XCTestSuite performTest:]_block_invoke + 268\n\t38 XCTest 0x00000001010bfe58 __59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 40\n\t39 XCTest 0x000000010112e48c +[XCTContext runInContextForTestCase:block:] + 212\n\t40 XCTest 0x00000001010bfe00 -[XCTestSuite _performProtectedSectionForTest:testSection:] + 156\n\t41 XCTest 0x00000001010c0150 -[XCTestSuite performTest:] + 320\n\t42 XCTest 0x000000010110986c -[XCTest runTest] + 60\n\t43 XCTest 0x00000001010c05c8 __27-[XCTestSuite performTest:]_block_invoke + 268\n\t44 XCTest 0x00000001010bfe58 __59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 40\n\t45 XCTest 0x000000010112e48c +[XCTContext runInContextForTestCase:block:] + 212\n\t46 XCTest 0x00000001010bfe00 -[XCTestSuite _performProtectedSectionForTest:testSection:] + 156\n\t47 XCTest 0x00000001010c0150 -[XCTestSuite performTest:] + 320\n\t48 XCTest 0x000000010110986c -[XCTest runTest] + 60\n\t49 XCTest 0x00000001010c05c8 __27-[XCTestSuite performTest:]_block_invoke + 268\n\t50 XCTest 0x00000001010bfe58 __59-[XCTestSuite _performProtectedSectionForTest:testSection:]_block_invoke + 40\n\t51 XCTest 0x000000010112e48c +[XCTContext runInContextForTestCase:block:] + 212\n\t52 XCTest 0x00000001010bfe00 -[XCTestSuite _performProtectedSectionForTest:testSection:] + 156\n\t53 XCTest 0x00000001010c0150 -[XCTestSuite performTest:] + 320\n\t54 XCTest 0x000000010110986c -[XCTest runTest] + 60\n\t55 XCTest 0x00000001011405f0 __44-[XCTTestRunSession runTestsAndReturnError:]_block_invoke + 176\n\t56 XCTest 0x00000001011406f0 __44-[XCTTestRunSession runTestsAndReturnError:]_block_invoke.100 + 108\n\t57 XCTest 0x00000001010da354 -[XCTestObservationCenter _observeTestExecutionForBlock:] + 588\n\t58 XCTest 0x0000000101140388 -[XCTTestRunSession runTestsAndReturnError:] + 592\n\t59 XCTest 0x00000001010a4bbc -[XCTestDriver runTestsAndReturnError:] + 428\n\t60 XCTest 0x000000010112a424 _XCTestMain + 2396\n\t61 WebDriverAgentRunner-Runner 0x0000000100bdb818 -[_XCTRunnerAppDelegate applicationWillResignActive:] + 0\n\t62 WebDriverAgentRunner-Runner 0x0000000100bdb720 _XCTRunnerRunTests + 0\n\t63 CoreFoundation 0x0000000189928578 <redacted> + 20\n\t64 CoreFoundation 0x0000000189927e7c <redacted> + 272\n\t65 CoreFoundation 0x0000000189922ee0 <redacted> + 1024\n\t66 CoreFoundation 0x00000001899227c0 CFRunLoopRunSpecific + 436\n\t67 GraphicsServices 0x000000018bb2379c GSEventRunModal + 104\n\t68 UIKitCore 0x00000001b62a1c38 UIApplicationMain + 212\n\t69 WebDriverAgentRunner-Runner 0x0000000100bdb9e4 main + 192\n\t70 libdyld.dylib 0x00000001893e68e0 <redacted> + 4\n)"
},
"sessionId" : "C953E926-BEC0-4A35-9D6A-ABEAECB6C18E"
}
Traceback (mostrecentcalllast):
File"<stdin>", line1, in<module>File"xxx/env/lib/python3.7/site-packages/appium/webdriver/extensions/search_context/ios.py", line72, infind_element_by_ios_predicatereturnself.find_element(by=MobileBy.IOS_PREDICATE, value=predicate_string)
File"xxx/env/lib/python3.7/site-packages/appium/webdriver/webdriver.py", line284, infind_element'value': value})['value']
File"xxx/env/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line321, inexecuteself.error_handler.check_response(response)
File"xxx/env/lib/python3.7/site-packages/appium/webdriver/errorhandler.py", line24, incheck_responsesuper(MobileErrorHandler, self).check_response(response)
File"xxx/env/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py", line131, incheck_responsestatus=value["status"]
KeyError: 'status'

Proposed fix

Change WDA to match the strings the clients are sending, i.e. prepend "-ios " to the "class chain" and "predicate string" usingTexts.

While it might seem backwards to change this in the server rather than adapt the clients, because multiple clients already use the same string and the "-ios "-prefix seems to have been established (in order to differentiate between lookup strategies that work exclusively on the iOS server) adapting the server seems like the more straight-forward fix.

Background

I've tried to find out when changes were introduced that made the server and client behaviour diverge but it turns out the respective strings have remained unchanged from when they were added around 3 years ago. I only tested the Python client because that's what I'm working with right now but searched through the other clients and all that have added support for class chain and predicate string lookups share the same strings, so the problem should exist for all of them. From what I can see none of those clients has been able to use these lookup strategies for years which seems odd but accurate from my research. I have found six clients linked from the official Appium documentation that all use the same "-ios..."-strings, so they seem to be an established pattern and fixing the server should make all of them work at the same time instead of having to fix all clients individually (it also seems like a reasonable idea to specially format strategies that work exclusively on iOS and are not supported by other Appium/Selenium servers).

Relevant GitHub code, issues and PRs:

Appium-clients have broadly agreed on using "-ios "-prefixes on strings used for iOS-exclusive element lookup strategies but the server can't provide those due to a mismatch
@hanneshauerhanneshauer changed the title Fix: Update "find elements using"-stringsfix: Update "find elements using"-stringsMay 23, 2020
@electricbubble

Copy link
Copy Markdown

Why don't you modify find_element_by_ios_predicate ?

Although I haven't used appium/python-client

I personally think that such modification makes the code of WDA not tidy.
For example, class name and name and other usingText have no -ios prefix.

@KazuCocoaKazuCocoa left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appium-clients can't use the iOS Class Chain and iOS Predicate String queries because the strings WDA expects don't match the strings the clients send.

Sorry, what do you mean? Do you mean when your client sends requests to WDA directly case?

This module is designed to get requests by appium-xcuitest-driver. Appium clients communicate with Appium server (not directly to appium/WDA)
https://github.com/appium/appium-xcuitest-driver/blob/08ac6564964f5e7c7fcb7d32beb6ce22eee57d75/lib/commands/find.js#L26 transfers the -ios class chain to class chain for WDA. For WDA, all contexts are for iOS, so such prefix does not so much make sense for WDA.

I'd also recommend you to modify client side.
You can call find_element('class chain', 'your target') directly if you wanted to send a custom find element.
https://github.com/appium/python-client/blob/8205776240b4c92e021064751e5b113d0c915d50/appium/webdriver/webelement.py#L80

@hanneshauer

Copy link
Copy Markdown
Author

This module is designed to get requests by appium-xcuitest-driver. Appium clients communicate with Appium server (not directly to appium/WDA)
https://github.com/appium/appium-xcuitest-driver/blob/08ac6564964f5e7c7fcb7d32beb6ce22eee57d75/lib/commands/find.js#L26 transfers the -ios class chain to class chain for WDA. For WDA, all contexts are for iOS, so such prefix

You are, of course, correct. My mistake was communicating with WDA directly instead of using appium-xcuitest-driver as a mediator which handles the string conversion and thus avoids the problems I've described. Sorry for the misunderstanding resulting from my setup, this obviously renders this PR moot.

@hanneshauer
hanneshauer deleted the hanneshauer-fix-findelements-strings branch May 24, 2020 09:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@hanneshauer@electricbubble@KazuCocoa