使用Java的Selenium WebDriver和HTML Window位置 [英] Selenium WebDriver and HTML Window location by using Java

查看:96
本文介绍了使用Java的Selenium WebDriver和HTML Window位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将Selenium WebDriver与java.awt.Robot结合使用,以更好地模拟用户与我们的Web应用程序的交互。是的,我知道这可能是不必要的,但我服务的客户要求它。



目前事情进展顺利,但我有一个小问题,我似乎无法找到一个好的方法来获取屏幕位置的网页元素。标题栏,菜单栏,导航栏等所有内容都会将内容推到物理屏幕上(Robot从中获取坐标),但对Selenium报告元素的位置没有影响。



当我在Selenium WebElement上调用: element.getLocation(); 时,它总是给我它相对的位置到HTML内容呈现窗格,而不是浏览器窗口本身。



更好的例子是: driver.findElement(By.tagName(body) ))。getLocation(); 总是返回0,0,无论窗口的实际屏幕位置如何。



现在我正在黑客攻击它通过在最大化窗口之后添加垂直和水平偏移,但是这些在不同浏览器之间是不同的(例如,IE的顶部装饰占据了比Firefox更多的空间),并且如果他们具有书签工具则可能对于每个用户可以是不同的添加了条形图,搜索条等。



是的,我知道我可以在全屏模式下运行,但如果可能的话,我宁愿不这样做。



有没有办法使用WebDriver以可靠的方式获取元素的物理屏幕位置?

解决方案

我相信没有办法获得页面上元素的真实屏幕位置。



我也认为全屏模式是你最好的选择。



那就是说,我写了一个 RobotCalibration 类,它可以检测当前浏览器的实际偏移量。它会打开一个特制的页面,并使用 Robot 类来单击它。该算法从浏览器的中心开始,然后使用二等分来查找浏览器视口的左上角。



在IE8和FF18上测试。适用于最大化和窗口化的浏览器。已知问题:如果您启用了顶部书签工具栏,则可能会点击某些书签,从而重定向。它可以很容易地处理,但是如果你需要的话,我会把它留给你:)。



测试页面:

 <!DOCTYPE html> 
< html lang =enonclick =document.getElementById('counter')。value ++>
< head>
< meta charset =utf-8/>
< title>校准测试< / title>
< / head>
< body>
< img height =1width =1style =position:absolute; left:0; top:0;
onclick =document.getElementById('done')。value ='yep'/>
< input type =textid =countervalue =0/>
< input type =textid =donevalue =nope/>
< / body>
< / html>

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();
}

/ **等待页面响应的时间。 * /
私有静态最终长TIMEOUT = 1000;

私人最终的WebDriver驱动程序;
私人最终机器人r;

私人终点Point browserCenter;
private int leftX;
private int rightX;
private int midX;
private int topY;
private int bottomY;
private int midY;

私有RobotCalibration(WebDriver驱动程序){
this.driver = driver;
try {
driver.manage()。window()。getSize();
} catch(UnsupportedOperationException headlessBrowserException){
抛出新的IllegalArgumentException(校准无头浏览器毫无意义。,headlessBrowserException);
}

试试{
this.r = new Robot();
} catch(AWTException headlessEnvironmentException){
抛出新的IllegalStateException(机器人无法在无头环境中工作。,headlessEnvironmentException);
}

Dimension screenSize = Toolkit.getDefaultToolkit()。getScreenSize();
org.openqa.selenium.Dimension browserSize = driver.manage()。window()。getSize();
org.openqa.selenium.Point browserPos = driver.manage()。window()。getPosition();

//最大化浏览器返回负位置
//最大化浏览器返回大小大于实际屏幕大小
//你不能在屏幕外点击
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());

//找到左边框
而(leftX< rightX){
点击(midX,midY);
if(clickWasSuccessful()){
rightX = midX;
}其他{
leftX = midX + 1;
//关闭我们可以打开的任何菜单
click(browserCenter.x,browserCenter.y);
}
midX =(leftX + rightX)/ 2;
}

//找到上边框
而(topY< bottomY){
click(midX,midY);
if(clickWasSuccessful()){
bottomY = midY;
}其他{
topY = midY + 1;
//关闭我们可以打开的任何菜单
click(browserCenter.x,browserCenter.y);
}
midY =(topY + bottomY)/ 2;
}

if(!isCalibrated()){
抛出新的IllegalStateException(无法校准机器人。);
}
返回新点(midX,midY);
}

/ **点击指定位置* /
private void click(int x,int y){
r.mouseMove(x,y) ;
r.mousePress(InputEvent.BUTTON1_DOWN_MASK);
r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);

//由于某种原因,我的IE8无法正确地注册彼此接近
//的点击次数比点击每半秒
更快(如果是InternetExplorerDriver的驱动程序实例) ){
sleep(500);
}
}

private static void sleep(int millis){
try {
Thread.sleep(millis);
} catch(忽略InterruptedException){
//无所事事
}
}

private int counter = 0;
/ ** @return点击页面是否成功* ​​/
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;
}
}
返回false;
}

/ ** @return左上角是否已被点击* /
private boolean isCalibrated(){
long targetTime = System.currentTimeMillis ()+ TIMEOUT;
while(System.currentTimeMillis()< targetTime){
if(driver.findElement(By.id(done))。getAttribute(value)。equals(yep)) {
返回true;
}
}
返回false;
}

}

样本用法:

  WebDriver driver = new InternetExplorerDriver(); 
Point p = RobotCalibration.calibrate(driver);
System.out.println(左偏移:+ p.x +,顶部偏移:+ p.y);
driver.quit();

如果不清楚,请随时提出任何问题。


I am using Selenium WebDriver in conjunction with java.awt.Robot to better simulate user interaction with our web application. Yes, I know it's probably unnecessary, but the customers I serve demand it.

Currently things are working pretty well, however I have a minor snag in that I can't seem to find a good way to get the web elements' on screen position. Things like the title bar, menu bar, navigation bar, etc all push the content down on the physical screen (which Robot gets its coordinates from), but has no impact on where Selenium reports the element is.

When I call: element.getLocation(); on a Selenium WebElement, it always gives me its location relative to the HTML content render pane, not the browser window itself.

A better illustration is: driver.findElement(By.tagName("body")).getLocation(); always returns 0,0, regardless of the window's actual on-screen location.

Right now I am hacking it by adding a vertical and horizontal offset after maximizing the window, but these aren't the same between different browsers (IE's top decorations take up more room then Firefox's, for example), and may be different for each user if they have bookmark tool bars, search bars, etc added in.

Yes, I know I could run in full screen mode, but I'd rather not, if at all possible.

Is there a way to use WebDriver to get the physical on-screen location of elements in a reliable manner?

解决方案

I believe there's no way to get the real on-screen location of the elements on the page.

I also think the fullscreen mode is your best bet.

That said, I wrote a RobotCalibration class that can detect the real offsets of your current browser. It opens a specially crafted page and uses the Robot class to click on it. The algorithm starts in the center of the browser and then uses bisecting to find the top left corner of the browser viewport.

Tested on IE8 and FF18. Works for both maximized and windowed browsers. Known issue: If you have a top Bookmarks Toolbar enabled, it may click on some of the bookmarks and therefore redirect. It can be handled pretty easily, but I left it up to you if you needed that :).

The testing page:

<!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>

The RobotCalibration class. It's a little bit long, so I suggest you to copypaste it into your favourite IDE and explore it there:

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;
    }

}

Sample usage:

WebDriver driver = new InternetExplorerDriver();
Point p = RobotCalibration.calibrate(driver);
System.out.println("Left offset: " + p.x + ", top offset: " + p.y);
driver.quit();

Feel free to ask any questions if something is unclear.

这篇关于使用Java的Selenium WebDriver和HTML Window位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆