appium: isDisplayed and getAttribute always raise exception in W3C mode

The problem

client: selenium-java library, v3.8.1 and 3.14.0 (latest) connection to appium: direct or via grid-hub (reault is same) Appium version: 1.9.1, Communication protocol: W3C (does not reproduced on JSonWire mode from java-client side)

When I call element.isDisplayed() or element.getAttribute() I always get exception. Arrors are: “Original error: Argument to isShown must be of type Element (for isPresent)” Original error: a.getAttributeNode is not a function. (In ‘a.getAttributeNode(b)’, ‘a.getAttributeNode’ is undefined) for getAttribute.

After digging I find:

  • java-client and appium use W3C protocol for communication

  • selenium java client use atoms to emulate both those commands: isDisplayed.js and getAttribute.js (see W3CHttpCommandCodec). This cause issue on appiums side (actually atoms returns errors which then proxied to appium and client.

    Then I tried to invoke endpoint “/session/{session id}/element/{element id}/displayed” directly (actually from browser address bar). In that case request was finished without any exception and returns “true”.

So in other words: when atom is sent by java-client for execution - we have Exception when atom invoked by appium - all is OK selenium-java has only 2commands which are exacuted via atoms and both them failed on appium side

I think appium-java client will have the same issue because it reuse W3CHttpCommandCodec from appium-java.

Other notes: (maybe they will help to localize issue)

  1. when java-client sends atom for execution it encodes web-element as json with 1 field only {"element-6066-11e4-a52e-4f735466cecf": "5000"} Which is different from executeScript() where there are 2 fields: {"element-6066-11e4-a52e-4f735466cecf": "5000", "ELEMENT": "5000"}
  2. selenium-java wraps atom function to: return(<atom-function>).apply(null, arguments); before isending over http, See here
  3. As I can see from appium log (after ‘Sending javascript command")’ atom which was sent from java-client is wrapped by some function by appium. While atoms which are invoked bу appium are sent without additional wrapping.

Environment

  • Appium version (or git revision) that exhibits the issue: 1.9.0
  • Last Appium version that did not exhibit the issue (if applicable):
  • Desktop OS/version used to run Appium: MacOS hight sierra
  • Node.js version (unless using Appium.app|exe):
  • Mobile platform/version under test: iOS 11.3, 11.4
  • Real device or emulator/simulator: sim
  • Appium CLI or Appium.app|exe: cli

Code To Reproduce Issue [ Good To Have ]

@Test public void isDisplayedTest() {

		WebDriver wd = RemoteWebDriver 
				.builder()   // requires web-driver v3.14
				.url("http://ta-mac-01:4724/wd/hub")
				.setCapability("platformName", "iOS")
				.setCapability("browserName", "safari")
				.setCapability("appium:automationName", "XCUITest")
				.setCapability("appium:platformVersion", "11.4")
				.setCapability("appium:deviceName", "iPhone 7")
				.build();

		wd.get("http://the-internet.herokuapp.com/");

		WebElement title = wd.findElement(By.cssSelector("h1"));

		// raise error: Original error: Argument to isShown must be of type Element
		System.out.println(title.isDisplayed());
		wd.quit();
	}

Logs

https://gist.github.com/kool79/3c51849b098788f9036b78a0a7966e22

Here logs for isDisplayed with W3C protocol (failled), isDisplayed with JSonWire protocol and for executeScript command (just for refrence)

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 16 (7 by maintainers)

Most upvoted comments

Update: after HUGE amount of tries found that everything is working fine for windows dektop version 1.2.7

@dpgraham

Hello, also having this issue, checked on pre-release

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.SetCapability("deviceName", "device");
capabilities.SetCapability("platformName", "Android");
capabilities.SetCapability("udid", "emulator-5554");
capabilities.SetCapability("platfomVersion", "9.0.0");
capabilities.SetCapability("browserName", "Chrome");
//capabilities.SetCapability("automationName", "UiAutomator2");
//capabilities.SetCapability("forceMjsonwp", true);

String baseURL = "http://127.0.0.1:";
String minorURL = "/wd/hub";
String port = "4723";

IWebDriver mobileInstance = new RemoteWebDriver(new Uri(baseURL + port + minorURL), capabilities, TimeSpan.FromSeconds(100));

mobileInstance.Navigate().GoToUrl("someurl");
mobileInstance.FindElement(By.Id("ctrlLogin$UserName")).GetAttribute("class");

System.InvalidOperationException: An unknown server-side error occurred while processing the command. Original error: unknown error: a.getAttributeNode is not a function (Session info: chrome=69.0.3497.100) (Driver info: chromedriver=2.44.609538 (b655c5a60b0b544917107a59d4153d4bf78e1b90),platform=Windows NT 10.0.17134 x86_64)

Part of Appium logs below:

[W3C (1ae0f4cd)] Driver proxy active, passing request on via HTTP proxy [JSONWP Proxy] Matched ‘/wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/timeouts’ to command name ‘timeouts’ [Protocol Converter] Will send the following request bodies to /timeouts: [{“type”:“implicit”,“ms”:20000}] [JSONWP Proxy] Proxying [POST /wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/timeouts] to [POST http://127.0.0.1:8000/wd/hub/session/85f3fd7612db735f7fc243113dbb6b4e/timeouts] with body: {“type”:“implicit”,“ms”:20000} [JSONWP Proxy] Got response with status 200: {“sessionId”:“85f3fd7612db735f7fc243113dbb6b4e”,“status”:0,“value”:null} [JSONWP Proxy] Replacing sessionId 85f3fd7612db735f7fc243113dbb6b4e with 1ae0f4cd-f3f5-4398-98e4-b13e63d29b94 [HTTP] <-- POST /wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/timeouts 200 3 ms - 76 [HTTP] [HTTP] --> POST /wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/element [HTTP] {“using”:“css selector”,“value”:“#ctrlLogin\$UserName”} [W3C (1ae0f4cd)] Driver proxy active, passing request on via HTTP proxy [JSONWP Proxy] Matched ‘/wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/element’ to command name ‘findElement’ [JSONWP Proxy] Proxying [POST /wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/element] to [POST http://127.0.0.1:8000/wd/hub/session/85f3fd7612db735f7fc243113dbb6b4e/element] with body: {“using”:“css selector”,“value”:“#ctrlLogin\$UserName”} [JSONWP Proxy] Got response with status 200: {“sessionId”:“85f3fd7612db735f7fc243113dbb6b4e”,“status”:0,“value”:{“ELEMENT”:“0.2803925612846576-1”}} [JSONWP Proxy] Replacing sessionId 85f3fd7612db735f7fc243113dbb6b4e with 1ae0f4cd-f3f5-4398-98e4-b13e63d29b94 [HTTP] <-- POST /wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/element 200 29 ms - 106 [HTTP] [HTTP] --> POST /wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/execute/sync [HTTP] {“script”:"return (function(){return function(){var aa="function"==typeof Object.defineProperties?Object.defineProperty:function(a,c,b){if(b.get||b.set)throw new TypeError("ES3 does not support getters and setters.");a!=Array.prototype&&a!=Object.prototype&&(a[c]=b.value)},ba="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global?global:this;\nfunction e(a,c){if©{for(var b=ba,d=a.split("."),f=0;fa||1342177279>>=1)b+=b;return d}});e("Math.sign",function(a){return a?a:function(a){a=Number(a);return!a||isNaN(a)?a:0 [W3C (1ae0f4cd)] Driver proxy active, passing request on via HTTP proxy [JSONWP Proxy] Matched ‘/wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/execute/sync’ to command name ‘execute’ [Protocol Converter] Rewrote the original URL ‘/wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/execute/sync’ to ‘/wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/execute’ for MJSONWP protocol [JSONWP Proxy] Proxying [POST /wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/execute] to [POST http://127.0.0.1:8000/wd/hub/session/85f3fd7612db735f7fc243113dbb6b4e/execute] with body: {“script”:"return (function(){return function(){var aa="function"==typeof Object.defineProperties?Object.defineProperty:function(a,c,b){if(b.get||b.set)throw new TypeError("ES3 does not support getters and setters.");a!=Array.prototype&&a!=Object.prototype&&(a[c]=b.value)},ba="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global?global:this;\nfunction e(a,c){if©{for(var b=ba,d=a.split("."),f=0;fa||1342177279>>=1)b+=b;return d}});e("Math.sign",function(a){return a?a:function(a){a=Number(a);return!a||isNaN(a)?a:0 [JSONWP Proxy] Got response with status 200: {“sessionId”:“85f3fd7612db735f7fc243113dbb6b4e”,“status”:13,“value”:{“message”:“unknown error: a.getAttributeNode is not a function\n (Session info: chrome=69.0.3497.100)\n (Driver info: chromedriver=2.44.609538 (b655c5a60b0b544917107a59d4153d4bf78e1b90),platform=Windows NT 10.0.17134 x86_64)”}} [JSONWP Proxy] Got an unexpected response: {“sessionId”:“85f3fd7612db735f7fc243113dbb6b4e”,“status”:13,“value”:{“message”:“unknown error: a.getAttributeNode is not a function\n (Session info: chrome=69.0.3497.100)\n (Driver info: chromedriver=2.44.609538 (b655c5a60b0b544917107a59d4153d4bf78e1b90),platform=Windows NT 10.0.17134 x86_64)”}} [W3C (1ae0f4cd)] Encountered internal error running command: ProxyRequestError: Could not proxy command to remote server. Original error: The request to /wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/execute has failed [W3C (1ae0f4cd)] at JWProxy.proxy (C:\Users\Dmitry_Leontiev\AppData\Local\Programs\Appium\resources\app\node_modules\appium-base-driver\lib\jsonwp-proxy\proxy.js:180:13) [MJSONWP] Matched JSONWP error code 13 to UnknownError [HTTP] <-- POST /wd/hub/session/1ae0f4cd-f3f5-4398-98e4-b13e63d29b94/execute/sync 500 26 ms - 1213

Can you give more details about that please? Sorry, but I did not understand: do you mean that both atoms, which selenium-java send, are specific to browser?

Long story short Selenium devs are trying to patch W3C requirements on the client level, which is, probably, ok for browsers, but does not work for mobile at all. Aa you can see above the client just calls /execute API without invoking the original endpoint.

I’ll be happy to use your client for mobiles. But it is impossible in my case because when I put appium java-client into class-path it replaces the original org.openqa.selenium.WebDriver with appium’s custom implementation. But it is not compatible with original: return type for findElement(s) is changed. Because some of libraries which I use were compiled with original interface, I have the errors error: name clash: findElement(By) in ChainSearchContext and findElement(By) in WebElement have the same erasure, yet neither overrides the other error: Item is not abstract and does not override abstract method <T>findElement(By) in WebElement Also want to note that with new module subsystem in java such trick with class substitution will not work.

I also don’t really like this workaround, but there is no other way for us. We have a bunch of pull requests to selenium, which are waiting in the queue for more that one year, so we must keep our workarounds to make the lib working.

@kool79

Do we have some option to force appium to use JsonWire protocol to have workaround

Yes, add forceMjsonwp: true to your desired capabilities