2013-02-01 42 views
12

Tôi đang sử dụng Selenium WebDriver kết hợp với java.awt.Robot để mô phỏng tốt hơn tương tác người dùng với ứng dụng web của chúng tôi. Vâng, tôi biết nó có lẽ không cần thiết, nhưng những khách hàng mà tôi phục vụ đòi hỏi nó.Vị trí Selenium WebDriver và HTML Window bằng cách sử dụng Java

Hiện tại mọi thứ đang hoạt động khá tốt, tuy nhiên tôi có một chút nhỏ trong đó tôi dường như không thể tìm được cách tốt để có được các yếu tố web 'trên vị trí màn hình. Những thứ như thanh tiêu đề, thanh menu, thanh điều hướng, vv đều đẩy nội dung xuống trên màn hình vật lý (mà Robot nhận tọa độ của nó từ), nhưng không ảnh hưởng đến nơi Selenium báo cáo phần tử đó.

Khi tôi gọi: element.getLocation(); trên Selenium WebElement, nó luôn mang lại cho tôi vị trí tương đối so với ngăn hiển thị nội dung HTML, chứ không phải chính cửa sổ trình duyệt.

Minh họa tốt hơn là: driver.findElement(By.tagName("body")).getLocation(); luôn trả về 0,0, bất kể vị trí thực tế trên màn hình của cửa sổ.

Hiện tại tôi đang hack nó bằng cách thêm một offset dọc và chiều ngang sau khi phóng to cửa sổ, nhưng không giống nhau giữa các trình duyệt khác nhau (ví dụ, trang trí hàng đầu của IE chiếm nhiều chỗ hơn). khác nhau cho mỗi người dùng nếu họ có thanh công cụ dấu trang, thanh tìm kiếm, v.v. được thêm vào.

Vâng, tôi biết tôi có thể chạy ở chế độ toàn màn hình, nhưng tôi không muốn, nếu có thể.

Có cách nào để sử dụng WebDriver để có được vị trí vật lý trên màn hình của các yếu tố một cách đáng tin cậy không?

+2

Bạn có thể quan tâm đến việc gắn dấu sao vấn đề này để thể hiện sự quan tâm đến nhóm Selenium: https://code.google.com/p/selenium/issues/detail?id=5267 – kem

Trả lời

6

Tôi tin rằng không có cách nào để có được vị trí trên màn hình thực của các yếu tố trên trang.

Tôi cũng nghĩ rằng chế độ toàn màn hình là đặt cược tốt nhất của bạn.

Điều đó nói rằng, tôi đã viết một lớp học RobotCalibration có thể phát hiện các bù lệch thực của trình duyệt hiện tại của bạn. Nó sẽ mở ra một trang đặc biệt crafted và sử dụng các lớp học Robot để bấm vào nó. Thuật toán bắt đầu ở giữa trình duyệt và sau đó sử dụng bisecting để tìm góc trên cùng bên trái của chế độ xem trình duyệt.

Đã kiểm tra trên IE8 và FF18. Làm việc cho cả hai trình duyệt tối đa và cửa sổ. Vấn đề đã biết: Nếu bạn đã bật Thanh công cụ Dấu trang hàng đầu, nó có thể nhấp vào một số dấu trang và do đó chuyển hướng. Nó có thể được xử lý khá dễ dàng, nhưng tôi để nó cho bạn nếu bạn cần :).

Các trang thử nghiệm:

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

Lớp RobotCalibration. Đó là một chút dài, vì vậy tôi đề nghị bạn copypaste nó vào IDE yêu thích của bạn và khám phá nó ở đó:

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

} 

sử dụng mẫu:

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

Hãy hỏi bất kỳ câu hỏi nếu có điều gì không rõ ràng.

+0

Tôi thực sự sẽ làm chính xác điều, chỉ hy vọng cho một giải pháp thanh lịch hơn. Cảm ơn! – Merkidemis

+0

@Merkidemis Vâng, tôi đã cố gắng một thời gian để tìm một giải pháp, bởi vì tôi cũng cần nó. Đã kết thúc với chế độ toàn màn hình chỉ làm phiền tôi vì [lỗi này] (http://code.google.com/p/selenium/issues/detail?id = 4067) làm cho ảnh chụp màn hình được chụp ở chế độ toàn màn hình không sử dụng được. –

+1

Tôi sẽ phải lưu các số bù khác nhau, vì ứng dụng web tôi đang thử nghiệm sẽ mở các cửa sổ mới mà không có thanh địa chỉ, chẳng hạn. Việc hiệu chuẩn được thực hiện vào đầu phiên (với thanh địa chỉ và thanh menu) sẽ vô dụng. – Merkidemis

4

Có cách đơn giản hơn Slanec answer để có được mức độ liên quan đến tỷ lệ chênh lệch tuyệt đối.

Trước tiên, bạn cần một trang trống với javascript attached click listener trên cửa sổ để có được tọa độ và lưu chúng vào một biến toàn cầu:

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

Sau đó, bạn nhấp chuột phải và có được vị trí nhấp chuột tương đối thông qua 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))); 
+1

Điều này thật tuyệt và tôi xấu hổ đến mức tôi không tự mình nghĩ ra! Tốt đẹp. –

0

Selen hiện tại không triển khai API để có được vị trí tuyệt đối của phần tử web. Nhưng SAFS đã triển khai một phiên bản để có được vị trí tuyệt đối của phần tử web.

Những suy nghĩ là dưới đây:

  1. Nhận vị trí của phần tử tương vào khung. Vì có thể có nhiều khung trong một trang web trình duyệt. Ngoài ra, khung có thể được cấy vào khung khác. Vì vậy, tốt hơn nên sử dụng một lớp với khung cha để tìm kiếm đệ quy đến vị trí khung bên ngoài nhất.

'

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. Thêm vị trí khung của, liên quan đến khu vực khách hàng duyệt (phần loại trừ thanh công cụ, menu, vv).

  2. Thêm khu vực khách của trình duyệt, liên quan đến cửa sổ trình duyệt.

  3. Thêm vị trí của cửa sổ trình duyệt, so với màn hình.

5

Dường như selen có cách để lấy vị trí phần tử tương đối so với cửa sổ trình duyệt của bạn ngay bây giờ. Trong một thử nghiệm của tôi, tôi đã cố gắng xác minh rằng một trang đã được neo vào một vị trí nhất định và đã tìm ra cách tốt nhất để làm điều này là lấy một vị trí phần tử liên quan đến cửa sổ. Điều này có thể được thực hiện bằng cách sử dụng phương thức get2ord().

Dưới đây là một số mẫu mã để có được vị trí tương đối của một 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; 
    } 
} 

Thông báo trước cho inViewPort() phương pháp là nếu bạn cố gắng để có được vị trí nguyên tố tương đối của một yếu tố đó hiện đang không ở chế độ xem trang, phương thức sẽ cuộn trang để phần tử ở chế độ xem và sau đó cung cấp cho bạn vị trí tương đối. Có nghĩa là, nếu bạn cố gắng lấy vị trí tương đối của phần tử ở trên chế độ xem trang trình duyệt của bạn, nó sẽ không cung cấp cho bạn toạ độ y âm, mà là cuộn lên phần tử đó và thực hiện toạ độ y bằng 0.

Hy vọng điều này sẽ giúp ích, tôi mới sử dụng Selenium và Java nên nếu có bất kỳ sai sót nào trong mã của tôi, hãy tha thứ cho tôi.

Các vấn đề liên quan