SeleniumHQ / selenium

A browser automation framework and ecosystem.
https://selenium.dev
Apache License 2.0
30.5k stars 8.15k forks source link

[šŸ› Bug]: (Java) S3-S4 W3C Mode Not Supported Using RemoteWebElement to getLocation and getSize #10698

Closed BJap closed 2 years ago

BJap commented 2 years ago

What happened?

When the user attempts to get a web element's location and size, the code will crash because the command is not supported in W3C mode.

This is due to the fact that unlike JWP, those commands are not supported, and W3C only allows getRect as per spec.

https://w3c.github.io/webdriver/#get-element-rect

Only JWP (not W3C) allows those two as supported commands:

https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidelementidlocation https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidelementidsize

The code in Selenium 3 should have checked for W3C mode like the Python implementation does, and choose accordingly. Selenium 4 is W3C mode purely and the code should have been migrated to support only that. It is currently still using JWP commands.

This means that the Python and Java implementations are not in sync, and the Java implementation is incorrect. The getLocation and getSize code for Selenium 4 could just use the getRect as a function in both implementations since that's all that's available, and wrap around it to extract the relevant data.

Java

Python

Screen Shot 2022-05-25 at 13 37 53
Screen Shot 2022-05-25 at 13 41 57

The solution for Selenium 4 Java (and similarly Python) can just be something like:

@Override
@SuppressWarnings({"unchecked"})
public Point getLocation() {
  Rectangle rect = getRect();
  return rect.getPoint();
}

@Override
@SuppressWarnings({"unchecked"})
public Dimension getSize() {
  Rectangle rect = getRect();
  return rect.getDimension();
}

@Override
@SuppressWarnings({"unchecked"})
public Rectangle getRect() {
  Response response = execute(DriverCommand.GET_ELEMENT_RECT(id));
  Map<String, Object> rawRect = (Map<String, Object>) response.getValue();
  int x = ((Number) rawRect.get("x")).intValue();
  int y = ((Number) rawRect.get("y")).intValue();
  int width = ((Number) rawRect.get("width")).intValue();
  int height = ((Number) rawRect.get("height")).intValue();
  return new Rectangle(x, y, height, width);
}

or for consistency, this:

@Override
@SuppressWarnings({"unchecked"})
public Point getLocation() {
  Response response = execute(DriverCommand.GET_ELEMENT_RECT(id));
  Map<String, Object> rawPoint = (Map<String, Object>) response.getValue();
  int x = ((Number) rawPoint.get("x")).intValue();
  int y = ((Number) rawPoint.get("y")).intValue();
  return new Point(x, y);
}

@Override
@SuppressWarnings({"unchecked"})
public Dimension getSize() {
  Response response = execute(DriverCommand.GET_ELEMENT_RECT(id));
  Map<String, Object> rawSize = (Map<String, Object>) response.getValue();
  int width = ((Number) rawSize.get("width")).intValue();
  int height = ((Number) rawSize.get("height")).intValue();
  return new Dimension(width, height);
}

@Override
@SuppressWarnings({"unchecked"})
public Rectangle getRect() {
  Response response = execute(DriverCommand.GET_ELEMENT_RECT(id));
  Map<String, Object> rawRect = (Map<String, Object>) response.getValue();
  int x = ((Number) rawRect.get("x")).intValue();
  int y = ((Number) rawRect.get("y")).intValue();
  int width = ((Number) rawRect.get("width")).intValue();
  int height = ((Number) rawRect.get("height")).intValue();
  return new Rectangle(x, y, height, width);
}

In Selenium 3 this was a parameterized choice of one or the other based on whether the test was run in JWP or W3C modes. in Selenium 4, those two functions are basically just helper/wrapper functions.

How can we reproduce the issue?

Visit a webpage (Selenium) or a WebView (Appium) in W3C mode, and attempt to get the size or location of a WebElement.

webElement.getLocation();

webElement.getSize();

The workaround is to use the API directly as the fix above would suggest and use:

webElement.getRect().getPoint();

webElement.getRect().getDimension();

The problem with this is that a lot of teams that are using this for their testing and want to migrate already have much of their code written in the former use case. It would ease the friction of migration and save lost hours of debugging time to correct the implementation and allow teams to use their code in its existing state without the workaround.

Relevant log output

Description: "Cannot call non W3C standard command while in W3C mode "

When using getLocation()

at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
at io.appium.java_client.remote.AppiumCommandExecutor.execute(AppiumCommandExecutor.java:250)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:41)
at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1)
at io.appium.java_client.android.AndroidDriver.execute(AndroidDriver.java:1)
at org.openqa.selenium.remote.RemoteWebElement.execute(RemoteWebElement.java:285)
at io.appium.java_client.DefaultGenericMobileElement.execute(DefaultGenericMobileElement.java:45)
at io.appium.java_client.MobileElement.execute(MobileElement.java:1)
at io.appium.java_client.android.AndroidElement.execute(AndroidElement.java:1)
at org.openqa.selenium.remote.RemoteWebElement.getLocation(RemoteWebElement.java:337)

--

When using getSize()

at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
at io.appium.java_client.remote.AppiumCommandExecutor.execute(AppiumCommandExecutor.java:250)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:41)
at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1)
at io.appium.java_client.android.AndroidDriver.execute(AndroidDriver.java:1)
at org.openqa.selenium.remote.RemoteWebElement.execute(RemoteWebElement.java:285)
at io.appium.java_client.DefaultGenericMobileElement.execute(DefaultGenericMobileElement.java:45)
at io.appium.java_client.MobileElement.execute(MobileElement.java:1)
at io.appium.java_client.android.AndroidElement.execute(AndroidElement.java:1)
at org.openqa.selenium.remote.RemoteWebElement.getSize(RemoteWebElement.java:346)

Operating System

Not Applicable but on macOS against Android and iOS

Selenium version

Java Selenium 3 and 4

What are the browser(s) and version(s) where you see this issue?

WebView

What are the browser driver(s) and version(s) where you see this issue?

Available on Request

Are you using Selenium Grid?

No

github-actions[bot] commented 2 years ago

@BJap, thank you for creating this issue. We will troubleshoot it as soon as we can.


Info for maintainers

Triage this issue by using labels.

If information is missing, add a helpful comment and then I-issue-template label.

If the issue is a question, add the I-question label.

If the issue is valid but there is no time to troubleshoot it, consider adding the help wanted label.

If the issue requires changes or fixes from an external project (e.g., ChromeDriver, GeckoDriver, MSEdgeDriver, W3C), add the applicable G-* label, and it will provide the correct link and auto-close the issue.

After troubleshooting the issue, please add the R-awaiting answer label.

Thank you!

diemol commented 2 years ago

That makes sense, thanks for raising this, @BJap. This should go together with #10374. Would you like to send a PR with that change you are proposing?

BJap commented 2 years ago

@diemol I checked with my team and I can do that. Let me go and open one now.

github-actions[bot] commented 2 years ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.