Mer*_*mis 12 java selenium selenium-webdriver
我正在将Selenium WebDriver与java.awt.Robot结合使用,以更好地模拟用户与Web应用程序的交互.是的,我知道这可能是不必要的,但我服务的客户要求它.
目前事情进展顺利,但我有一个小问题,我似乎找不到一个好的方法来获取屏幕位置的网页元素.标题栏,菜单栏,导航栏等内容都会将内容向下推到物理屏幕上(Robot从中获取坐标),但对Selenium报告元素的位置没有影响.
当我调用:element.getLocation();在Selenium WebElement上时,它总是给我相对于HTML内容呈现窗格的位置,而不是浏览器窗口本身.
更好的例证是:driver.findElement(By.tagName("body")).getLocation();无论窗口的实际屏幕位置如何,始终返回0,0.
现在我通过在最大化窗口后添加垂直和水平偏移来攻击它,但是这些在不同的浏览器之间是不一样的(例如,IE的顶部装饰占据了比Firefox更多的空间),并且对于每个用户可能是不同的如果他们有书签工具栏,搜索栏等添加.
是的,我知道我可以在全屏模式下运行,但是如果可能的话,我宁愿不这样做.
有没有办法使用WebDriver以可靠的方式获取元素的物理屏幕位置?
我相信没有办法获得页面上元素的真实屏幕位置.
我也认为全屏模式是你最好的选择.
也就是说,我写了一个RobotCalibration可以检测当前浏览器真实偏移量的类.它会打开一个特制的页面,并使用Robot该类点击它.算法从浏览器的中心开始,然后使用二等分来查找浏览器视口的左上角.
在IE8和FF18上测试过.适用于最大化和窗口化的浏览器.已知问题:如果您启用了顶部书签工具栏,则可能会点击某些书签,从而重定向.它可以很容易地处理,但如果你需要的话,我把它留给你了:).
测试页面:
<!DOCTYPE html>
<html lang="en" onclick="document.getElementById('counter').value++">
<head>
<meta charset="utf-8" />
<title>Calibration Test</title>
</head>
<body>
<img height="1" width="1" style="position: absolute; left: 0; top: 0;"
onclick="document.getElementById('done').value = 'yep'" />
<input type="text" id="counter" value="0" />
<input type="text" id="done" value="nope" />
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
该RobotCalibration班.它有点长,所以我建议你把它复制到你最喜欢的IDE中并在那里探索它:
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.nio.file.Paths;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class RobotCalibration {
public static Point calibrate(WebDriver driver) {
return new RobotCalibration(driver).calibrate();
}
/** Time for which to wait for the page response. */
private static final long TIMEOUT = 1000;
private final WebDriver driver;
private final Robot r;
private final Point browserCenter;
private int leftX;
private int rightX;
private int midX;
private int topY;
private int bottomY;
private int midY;
private RobotCalibration(WebDriver driver) {
this.driver = driver;
try {
driver.manage().window().getSize();
} catch (UnsupportedOperationException headlessBrowserException) {
throw new IllegalArgumentException("Calibrating a headless browser makes no sense.", headlessBrowserException);
}
try {
this.r = new Robot();
} catch (AWTException headlessEnvironmentException) {
throw new IllegalStateException("Robot won't work on headless environments.", headlessEnvironmentException);
}
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
org.openqa.selenium.Dimension browserSize = driver.manage().window().getSize();
org.openqa.selenium.Point browserPos = driver.manage().window().getPosition();
// a maximized browser returns negative position
// a maximized browser returns size larger than actual screen size
// you can't click outside the screen
leftX = Math.max(0, browserPos.x);
rightX = Math.min(leftX + browserSize.width, screenSize.width - 1);
midX = (leftX + rightX) /2;
topY = Math.max(0, browserPos.y);
bottomY = Math.min(topY + browserSize.height, screenSize.height - 1);
midY = (topY + bottomY) /2;
browserCenter = new Point(midX, midY);
}
private Point calibrate() {
driver.get(Paths.get("files/RobotCalibration.html").toUri().toString());
// find left border
while (leftX < rightX) {
click(midX, midY);
if (clickWasSuccessful()) {
rightX = midX;
} else {
leftX = midX + 1;
// close any menu we could have opened
click(browserCenter.x, browserCenter.y);
}
midX = (leftX + rightX) /2;
}
// find top border
while (topY < bottomY) {
click(midX, midY);
if (clickWasSuccessful()) {
bottomY = midY;
} else {
topY = midY + 1;
// close any menu we could have opened
click(browserCenter.x, browserCenter.y);
}
midY = (topY + bottomY) /2;
}
if (!isCalibrated()) {
throw new IllegalStateException("Couldn't calibrate the Robot.");
}
return new Point(midX, midY);
}
/** clicks on the specified location */
private void click(int x, int y) {
r.mouseMove(x, y);
r.mousePress(InputEvent.BUTTON1_DOWN_MASK);
r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
// for some reason, my IE8 can't properly register clicks that are close
// to each other faster than click every half a second
if (driver instanceof InternetExplorerDriver) {
sleep(500);
}
}
private static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException ignored) {
// nothing to do
}
}
private int counter = 0;
/** @return whether the click on a page was successful */
private boolean clickWasSuccessful() {
counter++;
long targetTime = System.currentTimeMillis() + TIMEOUT;
while (System.currentTimeMillis() < targetTime) {
int pageCounter = Integer.parseInt(driver.findElement(By.id("counter")).getAttribute("value"));
if (counter == pageCounter) {
return true;
}
}
return false;
}
/** @return whether the top left corner has already been clicked at */
private boolean isCalibrated() {
long targetTime = System.currentTimeMillis() + TIMEOUT;
while (System.currentTimeMillis() < targetTime) {
if (driver.findElement(By.id("done")).getAttribute("value").equals("yep")) {
return true;
}
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
样品用法:
WebDriver driver = new InternetExplorerDriver();
Point p = RobotCalibration.calibrate(driver);
System.out.println("Left offset: " + p.x + ", top offset: " + p.y);
driver.quit();
Run Code Online (Sandbox Code Playgroud)
如果不清楚,请随时提出任何问题.
小智 5
看起来selenium现在可以相对于浏览器窗口获取元素位置.在我的一个测试中,我试图验证页面是否锚定到某个位置,并认为执行此操作的最佳方法是获取相对于窗口的元素位置.这可以使用getCoordinates().inViewPort()方法完成.
以下是获取WebElement相对位置的示例代码:
import org.openqa.selenium.By;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.internal.Locatable;
public class RelativeElementLocation {
private static Point locationPoint;
private static Locatable elementLocation;
WebDriver driver = new FirefoxDriver();
WebElement element;
public Point location() throws Throwable {
driver.get("Insert your URL here");
element = driver.findElement(By.id("Insert id/css/xpath/ here"));
elementLocation = (Locatable) element;
locationPoint = elementLocation.getCoordinates().inViewPort();
System.out.println(locationPoint);
return locationPoint;
}
}
Run Code Online (Sandbox Code Playgroud)
对inViewPort()方法的唯一警告是,如果你试图获取当前不在页面视图中的元素的相对元素位置,该方法将滚动页面,以便元素在视图中,然后给你相对位置.意思是,如果你试图得到一个元素的相对位置在浏览器页面视图之上,它不会给你一个负y坐标,而是向上滚动到那个元素并使y坐标为零.
希望这有帮助,我是Selenium和Java的新手,所以如果我的代码中有任何错误,请原谅我.