Подтвердить что ты не робот

Размещение Selenium WebDriver и HTML Window с помощью Java

Я использую Selenium WebDriver в сочетании с java.awt.Robot, чтобы лучше имитировать взаимодействие пользователя с нашим веб-приложением. Да, я знаю, что это, вероятно, не нужно, но клиенты, которых я обслуживаю, требуют этого.

В настоящее время все работает очень хорошо, однако у меня есть небольшая ошибка, поскольку я не могу найти хороший способ получить элементы веб-элементов на экране. Такие вещи, как строка заголовка, панель меню, панель навигации и т.д., Все нажимают содержимое вниз на физическом экране (откуда робот получает свои координаты), но не влияют на то, где Selenium сообщает об этом элементе.

Когда я вызываю: element.getLocation(); в Selenium WebElement, он всегда дает мне свое местоположение относительно области визуализации содержимого HTML, а не самого окна браузера.

Лучшая иллюстрация: driver.findElement(By.tagName("body")).getLocation(); всегда возвращает 0,0, независимо от фактического местоположения окна на экране.

Сейчас я взламываю его, добавляя вертикальное и горизонтальное смещение после максимизации окна, но это не то же самое между разными браузерами (например, верхние украшения IE занимают больше места, чем Firefox), и могут быть разными для каждого пользователя, если у них есть панели инструментов закладки, строки поиска и т.д. добавлены.

Да, я знаю, что могу работать в полноэкранном режиме, но я бы предпочел, если это вообще возможно.

Есть ли способ использовать WebDriver для надежного физического размещения элементов на экране?

4b9b3361

Ответ 1

Я считаю, что нет способа получить реальное экранное расположение элементов на странице.

Я также думаю, что полноэкранный режим - лучший выбор.

Тем не менее, я написал класс RobotCalibration, который может обнаружить реальные смещения вашего текущего браузера. Он открывает специально созданную страницу и использует класс Robot, чтобы щелкнуть по ней. Алгоритм начинается в центре браузера, а затем использует bisecting для поиска верхнего левого угла окна просмотра браузера.

Протестировано на 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>

Класс 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;
    }

}

Использование образца:

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

Не стесняйтесь задавать любые вопросы, если что-то неясно.

Ответ 2

Похоже, у селена есть способ получить позицию элемента относительно вашего окна браузера. В одном из моих тестов я пытался проверить, что страница привязана к определенной позиции, и решил, что лучший способ сделать это - получить позицию элемента относительно окна. Это можно сделать с помощью методов 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; 
    }
}

Единственное предостережение метода inViewPort() заключается в том, что если вы попытаетесь получить относительное местоположение элемента, который в настоящее время не находится в режиме просмотра страницы, метод будет прокручивать страницу, чтобы элемент находится в поле зрения, а затем дает вам относительное положение. Смысл, скажем, если вы попытаетесь получить относительное положение элемента, которое находится выше вашего просмотра страницы браузера, оно не даст вам отрицательную координату y, а скорее прокрутит ее до этого элемента и сделает координату y нулевой.

Надеюсь, это поможет, я новичок в Selenium и Java, поэтому, если в моем коде есть ошибки, прошу простить.

Ответ 3

Простой способ, чем ответ Slanec, получить относительное абсолютное смещение.

Сначала вам нужна пустая страница с javascript прикрепленным клиентом-клиентом в окне, чтобы получить координаты и сохранить их в глобальной переменной:

window.coordinates = [];
window.attachEvent('click', function() {
     window.coordinates = [event.pageX, event.pageY];
});

Затем вы нажимаете и получаете относительную позицию по нажатию JavascriptExecutor:

// browser center
Dimension size = driver.manage().window().getSize();
Point point = driver.manage().window().getPosition()
    .translate(size.width / 2, size.height / 2);

// Click through robot
click(point.x, point.y);
Thread.sleep(500);

// read coordinates
List<Object> coordinates = (List<Object>) ((JavascriptExecutor) driver)
    .executeScript("return window.coordinates;");
if (coordinates.size() != 2)
     throw new IllegalStateException("Javascript did not receive the click");

// point contains screen coordinates of upper left page point
point.translate(-((Integer)coordinates.get(0)),
                -((Integer)coordinates.get(1)));

Ответ 4

Текущий Selenium не реализует API, чтобы получить абсолютное местоположение веб-элемента. Но SAFS внедрил одну версию, чтобы получить абсолютное расположение веб-элемента.

Мысль ниже:

  • Получить расположение элемента относительный к кадру. Потому что на одной веб-странице браузера может быть много кадров. Кроме того, кадр может быть имплантирован в другой кадр. Таким образом, лучше использовать класс с родительским фреймом для рекурсивного поиска в самом внешнем расположении кадра.

`

class FrameElement {
    FrameElement parent;
    Point location;

    FrameElement(FrameElement parent, WebElement frame) throws ... {
        if(parent != null) {
            this.parent = parent;
            location = frame.getLocation().moveBy(parent.getLocation().x, parent.getLocation().y);
        } else {
            location = frame.getLocation();
        }
    }

    public Point getLocation() {return location;} 
}

Point p = webelement.getLocation();
  1. Добавить расположение фрейма относительно клиентской области браузера (панель инструментов исключить часть, меню и т.д.).

  2. Добавьте клиентскую область браузера относительно окна браузера.

  3. Добавить расположение окна браузера относительно экрана.