diff --git a/xwiki-platform-core/xwiki-platform-appwithinminutes/xwiki-platform-appwithinminutes-test/xwiki-platform-appwithinminutes-test-pageobjects/src/main/java/org/xwiki/appwithinminutes/test/po/StaticListItemsEditor.java b/xwiki-platform-core/xwiki-platform-appwithinminutes/xwiki-platform-appwithinminutes-test/xwiki-platform-appwithinminutes-test-pageobjects/src/main/java/org/xwiki/appwithinminutes/test/po/StaticListItemsEditor.java index 66b12a187a583b79fd22f037a4bbef7b92e0ebc1..00d3d0c3e3a2ccc807904176ce91b00d4ec853bd 100644 --- a/xwiki-platform-core/xwiki-platform-appwithinminutes/xwiki-platform-appwithinminutes-test/xwiki-platform-appwithinminutes-test-pageobjects/src/main/java/org/xwiki/appwithinminutes/test/po/StaticListItemsEditor.java +++ b/xwiki-platform-core/xwiki-platform-appwithinminutes/xwiki-platform-appwithinminutes-test/xwiki-platform-appwithinminutes-test-pageobjects/src/main/java/org/xwiki/appwithinminutes/test/po/StaticListItemsEditor.java @@ -22,8 +22,8 @@ import org.openqa.selenium.By; import org.openqa.selenium.Keys; import org.openqa.selenium.WebElement; -import org.openqa.selenium.interactions.Actions; import org.xwiki.test.ui.po.BaseElement; +import org.xwiki.test.ui.po.SortableElement; /** * Represents the static list items editor present on the configuration pane of a static list field. @@ -53,6 +53,8 @@ public class StaticListItemsEditor extends BaseElement */ private WebElement addButton; + private final SortableElement sortable; + /** * Creates a new instance. * @@ -62,6 +64,8 @@ public StaticListItemsEditor(WebElement container) { this.container = container; + this.sortable = new SortableElement(container); + By xpath = By.xpath(".//*[@class = 'xHint' and . = 'ID']/following-sibling::input[@type = 'text']"); valueInput = getDriver().findElementWithoutWaiting(container, xpath); @@ -134,16 +138,7 @@ public void setLabel(String value, String newLabel) */ public void moveBefore(String valueToMove, String beforeValue) { - WebElement itemToMove = getItem(valueToMove); - WebElement itemBefore = getItem(beforeValue); - - Actions actions = getDriver().createActions().clickAndHold(itemToMove); - - // We move the item from the center, so we need to ensure that we actually move it with an offset of half its - // width to be sure it's before the other item element. - int offsetX = - (itemToMove.getSize().getWidth() / 2); - int offsetY = 2; - getDriver().moveToTopLeftCornerOfTargetWithOffset(itemBefore, offsetX, offsetY, actions).release().perform(); + this.sortable.moveBefore(getSelectorForItem(valueToMove), getSelectorForItem(beforeValue)); } /** @@ -152,8 +147,12 @@ public void moveBefore(String valueToMove, String beforeValue) */ public WebElement getItem(String valueOrLabel) { - By xpath = By.xpath("ul/li/*[@title = '" + valueOrLabel + "' or . = '" + valueOrLabel + "']"); - return getDriver().findElementWithoutWaiting(container, xpath); + return getDriver().findElementWithoutWaiting(this.container, getSelectorForItem(valueOrLabel)); + } + + private By getSelectorForItem(String valueOrLabel) + { + return By.xpath("ul/li/*[@title = '" + valueOrLabel + "' or . = '" + valueOrLabel + "']"); } /** diff --git a/xwiki-platform-core/xwiki-platform-panels/xwiki-platform-panels-test/xwiki-platform-panels-test-pageobjects/src/main/java/org/xwiki/panels/test/po/ApplicationsPanelAdministrationPage.java b/xwiki-platform-core/xwiki-platform-panels/xwiki-platform-panels-test/xwiki-platform-panels-test-pageobjects/src/main/java/org/xwiki/panels/test/po/ApplicationsPanelAdministrationPage.java index 0312cf375a07776a797bd66473a6461793c9ec8e..4e6de555aec4e344ac3714845781e7b0ccf49ab9 100644 --- a/xwiki-platform-core/xwiki-platform-panels/xwiki-platform-panels-test/xwiki-platform-panels-test-pageobjects/src/main/java/org/xwiki/panels/test/po/ApplicationsPanelAdministrationPage.java +++ b/xwiki-platform-core/xwiki-platform-panels/xwiki-platform-panels-test/xwiki-platform-panels-test-pageobjects/src/main/java/org/xwiki/panels/test/po/ApplicationsPanelAdministrationPage.java @@ -23,13 +23,10 @@ import java.util.List; import org.openqa.selenium.By; -import org.openqa.selenium.Point; -import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; -import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.ui.ExpectedCondition; import org.xwiki.administration.test.po.AdministrationPage; +import org.xwiki.test.ui.po.SortableElement; import org.xwiki.test.ui.po.ViewPage; import static org.junit.Assert.assertTrue; @@ -56,6 +53,8 @@ public class ApplicationsPanelAdministrationPage extends ViewPage @FindBy(id = "bt-save") private WebElement saveButton; + private final SortableElement sortableDisplayedPanels = new SortableElement(this.displayedPanels); + public static ApplicationsPanelAdministrationPage gotoPage() { AdministrationPage administrationPage = AdministrationPage.gotoPage(); @@ -116,40 +115,7 @@ public void moveAppBefore(String appName, String appBeforeName) return; } - WebElement app = displayedPanels.findElement(By.linkText(appName)); - WebElement appBefore = displayedPanels.findElement(By.linkText(appBeforeName)); - Point target = appBefore.getLocation(); - Point source = app.getLocation(); - - // The drag & drop of the "sortable" plugin of "jquery-ui" is very sensitive so we need to script the - // moves of the mouse precisely if we don't want to have flickers. - Actions actions = new Actions(getDriver().getWrappedDriver()); - // First we hold the app - actions.clickAndHold(app); - // Then we move into the position of the targeted app so jquery-ui can register we want to take its place. - actions.moveByOffset(target.getX() - source.getX(), target.getY() - source.getY()); - // Now we do a little move on top left so jquery-ui understand we want to be *before* the other app and - // put a blank place instead of the other app. - actions.moveByOffset(-5, -5); - // Do it - actions.perform(); - - // Before releasing the click, check that jquery-ui has moved the other app to let the place free. - getDriver().waitUntilCondition(new ExpectedCondition<Object>() - { - @Override - public Object apply(WebDriver webDriver) - { - Point newTarget = appBefore.getLocation(); - Point newSource = app.getLocation(); - return newTarget.getX() > newSource.getX() + 5 || newTarget.getY() > newSource.getY() + 5; - } - }); - - // Now we can release the selection - actions = new Actions(getDriver().getWrappedDriver()); - actions.release(); - actions.perform(); + this.sortableDisplayedPanels.moveBefore(By.linkText(appName), By.linkText(appBeforeName)); } public void revert() diff --git a/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/SortableElement.java b/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/SortableElement.java new file mode 100644 index 0000000000000000000000000000000000000000..8ceb8c610d67a3ab9bef119408d4ed295aee2fe8 --- /dev/null +++ b/xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-ui/src/main/java/org/xwiki/test/ui/po/SortableElement.java @@ -0,0 +1,89 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.xwiki.test.ui.po; + +import org.openqa.selenium.By; +import org.openqa.selenium.Point; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.support.ui.ExpectedCondition; + +/** + * Represents a sortable element that is using, e.g., the "sortable" plugin of "jquery-ui". + * + * @version $Id$ + * @since 15.6RC1 + * @since 15.5.1 + * @since 14.10.15 + */ +public class SortableElement extends BaseElement +{ + private final WebElement container; + + /** + * Creates a new instance. + * + * @param container the element that wraps the sortable elements + */ + public SortableElement(WebElement container) + { + super(); + + this.container = container; + } + + /** + * Move a given element before another one. + * + * @param toMove the selector for the element to move inside the sortable + * @param before the selector for the element before which the element to move should be moved + */ + public void moveBefore(By toMove, By before) + { + WebElement elementToMove = this.container.findElement(toMove); + WebElement elementBefore = this.container.findElement(before); + Point target = elementBefore.getLocation(); + Point source = elementToMove.getLocation(); + + // The drag & drop of the "sortable" plugin of "jquery-ui" is very sensitive so we need to script the + // moves of the mouse precisely if we don't want to have flickers. + + // First, we click and hold the item we want to move. + Actions actions = getDriver().createActions().clickAndHold(elementToMove); + // Then we move into the position of the targeted item so jquery-ui can register we want to take its place. + actions.moveByOffset(target.getX() - source.getX(), target.getY() - source.getY()); + // Now we do a little move on top left so jquery-ui understand we want to be *before* the other item and + // put a blank place instead of the other app. + actions.moveByOffset(-4, -4); + actions.perform(); + + // Before releasing the click, check that jquery-ui has moved the other item to let the place free. + getDriver().waitUntilCondition((ExpectedCondition<Object>) webDriver -> { + Point newTarget = elementBefore.getLocation(); + Point newSource = elementToMove.getLocation(); + return newTarget.getX() > newSource.getX() + 5 || newTarget.getY() > newSource.getY() + 5; + }); + + // Now we can release the selection + actions = new Actions(getDriver().getWrappedDriver()); + actions.release(); + actions.perform(); + } +}