/* ************************************************************************ qxwebdriver-java http://github.com/qooxdoo/qxwebdriver-java Copyright: 2012-2013 1&1 Internet AG, Germany, http://www.1und1.de License: LGPL: http://www.gnu.org/licenses/lgpl.html EPL: http://www.eclipse.org/org/documents/epl-v10.php See the license.txt file in the project's top-level directory for details. Authors: * Daniel Wagner (danielwagner) ************************************************************************ */ package org.oneandone.qxwebdriver.ui.core; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.oneandone.qxwebdriver.QxWebDriver; import org.oneandone.qxwebdriver.interactions.Actions; import org.oneandone.qxwebdriver.resources.JavaScriptRunner; import org.oneandone.qxwebdriver.ui.Widget; import org.openqa.selenium.By; import org.openqa.selenium.Dimension; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.Point; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.HasInputDevices; import org.openqa.selenium.interactions.Mouse; import org.openqa.selenium.interactions.internal.Coordinates; import org.openqa.selenium.internal.Locatable; import org.openqa.selenium.support.ui.ExpectedCondition; import org.openqa.selenium.support.ui.WebDriverWait; public class WidgetImpl implements org.oneandone.qxwebdriver.ui.Widget { public WidgetImpl(WebElement element, QxWebDriver webDriver) { driver = webDriver; jsExecutor = driver.jsExecutor; jsRunner = driver.jsRunner; contentElement = (WebElement) jsRunner.runScript("getContentElement", element); } private String qxHash = null; private String classname = null; protected WebElement contentElement; protected QxWebDriver driver; protected JavascriptExecutor jsExecutor; protected JavaScriptRunner jsRunner; public String getQxHash() { if (qxHash == null) { qxHash = (String) jsRunner.runScript("getObjectHash", contentElement); } return qxHash; } public String getClassname() { if (classname == null) { classname = (String) jsRunner.runScript("getClassname", contentElement); } return classname; } public WebElement getContentElement() { return contentElement; } public void dragToWidget(Widget target) { Actions actions = new Actions(driver.getWebDriver()); actions.dragAndDrop(getContentElement(), target.getContentElement()); actions.perform(); } public void dragOver(Widget target) throws InterruptedException { Mouse mouse = ((HasInputDevices)driver.getWebDriver()).getMouse(); Locatable root = (Locatable) driver.findElement(By.tagName("body")); //cast WebElement to Locatable Locatable sourceL = (Locatable)contentElement; Locatable targetL = (Locatable)target.getContentElement(); Coordinates coord = root.getCoordinates(); mouse.mouseDown(sourceL.getCoordinates()); //get source position (center,center) int sourceX = sourceL.getCoordinates().onPage().x + ((int) contentElement.getSize().width /2); int sourceY = sourceL.getCoordinates().onPage().y + ((int) contentElement.getSize().height /2); // get target position (center, center) int targetX = targetL.getCoordinates().onPage().x + ((int) target.getContentElement().getSize().width /2); int targetY = targetL.getCoordinates().onPage().y + ((int) target.getContentElement().getSize().height /2); //compute deltas between source and target position //delta must be positive, however //also we have to define the direction int deltaX; int directionX=1; //move direction is right int deltaY; int directionY=1; //move direction is bottom deltaX = targetX-sourceX; if (deltaX < 0){ deltaX *= -1; directionX=-1; // move direction is left } deltaY = targetY-sourceY; if(deltaY <0){ deltaY *= -1; directionY=-1; // move direction is top } //define base delta, which must be the higher one int baseDelta = deltaX; if (deltaY > deltaX) { baseDelta = deltaY; } // iterate base delta, set mouse cursor in relation to delta x & delta y int x = 0; int y = 0; for (int i = 1; i <= baseDelta; i+=4) { if(i> baseDelta){ i = baseDelta; } x = (int) sourceX + (deltaX * i / baseDelta * directionX); y = (int) sourceY + (deltaY * i / baseDelta * directionY); mouse.mouseMove(coord, x, y); //System.out.println(x +", "+ y); Thread.sleep(1); } // source has the same coordinates as target if(sourceX == targetX && sourceY == targetY){ mouse.mouseMove(targetL.getCoordinates(),x++,y); Thread.sleep(20); } } public void drop(Widget target) throws InterruptedException { Mouse mouse = ((HasInputDevices)driver.getWebDriver()).getMouse(); dragOver(target); Locatable targetL=(Locatable)target.getContentElement(); mouse.mouseUp(targetL.getCoordinates()); } public void click() { Actions actions = new Actions(driver.getWebDriver()); actions.moveToElement(getContentElement()); actions.click(); actions.perform(); } public void sendKeys(CharSequence keysToSend) { contentElement.sendKeys(keysToSend); } public Widget waitForChildControl(String childControlId, Integer timeout) { WebDriverWait wait = new WebDriverWait(driver, timeout, 250); return wait.until(childControlIsVisible(childControlId)); } /** * A condition that waits until a child control has been rendered, then * returns it. */ public ExpectedCondition<org.oneandone.qxwebdriver.ui.Widget> childControlIsVisible(final String childControlId) { return new ExpectedCondition<org.oneandone.qxwebdriver.ui.Widget>() { @Override public org.oneandone.qxwebdriver.ui.Widget apply(WebDriver webDriver) { org.oneandone.qxwebdriver.ui.Widget childControl = getChildControl(childControlId); if (childControl != null && childControl.isDisplayed()) { return childControl; } return null; } @Override public String toString() { return "Child control is visible."; } }; } public org.oneandone.qxwebdriver.ui.Widget getChildControl(String childControlId) { Object result = jsRunner.runScript("getChildControl", contentElement, childControlId); WebElement element = (WebElement) result; if (element == null) { return null; } return driver.getWidgetForElement(element); } public Boolean hasChildControl(String childControlId) { Object result = jsRunner.runScript("hasChildControl", contentElement, childControlId); return (Boolean) result; } public org.oneandone.qxwebdriver.ui.Widget getLayoutParent() { Object result = jsRunner.runScript("getLayoutParent", contentElement); WebElement element = (WebElement) result; if (element == null) { return null; } return driver.getWidgetForElement(element); } public Object executeJavascript(String script) { return jsExecutor.executeScript(script, contentElement); } public String getPropertyValueAsJson(String propertyName) { Object result = jsRunner.runScript("getPropertyValueAsJson", contentElement, propertyName); return (String) result; } public Object getPropertyValue(String propertyName) { Object result = jsRunner.runScript("getPropertyValue", contentElement, propertyName); return result; } private WebElement getElementFromProperty(String propertyName) { Object result = jsRunner.runScript("getElementFromProperty", contentElement, propertyName); return (WebElement) result; } /** * Returns a {@link WidgetImpl} representing the value of a widget property, * e.g. <a href="http://demo.qooxdoo.org/current/apiviewer/#qx.ui.form.MenuButton~menu!property">the * MenuButton's menu property</a> */ public Widget getWidgetFromProperty(String propertyName) { return driver.getWidgetForElement(getElementFromProperty(propertyName)); } /** * Returns a {@link WidgetImpl} representing the value of a widget property, * e.g. <a href="http://demo.qooxdoo.org/current/apiviewer/#qx.ui.form.MenuButton~menu!property">the * MenuButton's menu property</a> */ public List<Widget> getWidgetListFromProperty(String propertyName) { List<WebElement> elements = (List<WebElement>) jsRunner.runScript("getElementsFromProperty", contentElement, propertyName); List<Widget> widgets = new ArrayList<Widget>(); Iterator<WebElement> elemIter = elements.iterator(); while(elemIter.hasNext()) { WebElement element = elemIter.next(); Widget widget = driver.getWidgetForElement(element); widgets.add(widget); } return widgets; } private List<WebElement> getChildrenElements() { Object result = jsRunner.runScript("getChildrenElements", contentElement); List<WebElement> children = (List<WebElement>) result; return children; } public List<org.oneandone.qxwebdriver.ui.Widget> getChildren() { List<WebElement> childrenElements = getChildrenElements(); Iterator<WebElement> iter = childrenElements.iterator(); List<org.oneandone.qxwebdriver.ui.Widget> children = new ArrayList<org.oneandone.qxwebdriver.ui.Widget>(); while(iter.hasNext()) { WebElement child = iter.next(); children.add(driver.getWidgetForElement(child)); } return children; } /** * A condition that checks if an element is rendered. */ public ExpectedCondition<WebElement> isRendered(final WebElement contentElement, final By by) { return new ExpectedCondition<WebElement>() { @Override public WebElement apply(WebDriver driver) { return contentElement.findElement(by); } @Override public String toString() { return "element is rendered."; } }; } public WebElement findElement(org.openqa.selenium.By by) { WebDriverWait wait = new WebDriverWait(driver, 5); return wait.until(isRendered(contentElement, by)); } /** * Finds a widget relative to the current one by traversing the qooxdoo * widget hierarchy. */ public org.oneandone.qxwebdriver.ui.Widget findWidget(org.openqa.selenium.By by) { WebElement element = findElement(by); return driver.getWidgetForElement(element); } public String toString() { return "QxWidget " + getClassname() + "[" + getQxHash() + "]"; } /** * Not implemented for qooxdoo widgets. */ public void submit() { throw new RuntimeException("Not implemented for qooxdoo widgets."); } @Override public void sendKeys(CharSequence... keysToSend) { contentElement.sendKeys(keysToSend); } @Override public void clear() { contentElement.clear(); } @Override public String getTagName() { return contentElement.getTagName(); } @Override public String getAttribute(String name) { return contentElement.getAttribute(name); } @Override public boolean isSelected() { return contentElement.isSelected(); } @Override public boolean isEnabled() { return contentElement.isEnabled(); } @Override public String getText() { return contentElement.getText(); } @Override public List<WebElement> findElements(By by) { return contentElement.findElements(by); } /** * Determines if the widget is visible by querying the qooxdoo property * <a href="http://demo.qooxdoo.org/current/apiviewer/#qx.ui.core.Widget~isSeeable!method_public">seeable</a>. */ public boolean isDisplayed() { return (Boolean) executeJavascript("return qx.ui.core.Widget.getWidgetByElement(arguments[0]).isSeeable()"); } @Override public Point getLocation() { return contentElement.getLocation(); } @Override public Dimension getSize() { return contentElement.getSize(); } @Override public String getCssValue(String propertyName) { return contentElement.getCssValue(propertyName); } }