We already have seen automating a custom control – JQuery Slider – in this article. I would request you to read that article first, if you have not already. We are going to see how to automate JQuery Sortable Elements in this post.
Goal:
To model a wrapper element for these sortable items. So that user can move items by index or item name.
JQuery Sortable Element:
It is basically a list of WebElements for which you can re-arrange the order by using drag and drop. Our aim here is to make an element move to a new position by the index or the text. Since we are going to find an element by text, I use a map and store the elements reference.
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.PageFactory;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
public class SortableElement {
private static final int OFFSET = 5;
@FindBy(css = ".ui-sortable-handle")
private List<WebElement> sortableHandles;
private Map<String, WebElement> map;
private Actions action;
public SortableElement(final WebDriver driver){
this.action = new Actions(driver);
PageFactory.initElements(driver, this);
}
public List<String> getItems() {
return this.sortableHandles.stream()
.map(WebElement::getText)
.map(String::trim)
.collect(Collectors.toList());
}
public void reorder(int from, int to) {
this.reorder(sortableHandles.get(from),
sortableHandles.get(to));
}
public void reorder(String from, String to) {
if (Objects.isNull(map)) {
map = sortableHandles.stream()
.collect(Collectors.toMap(
ele -> ele.getText(), //key
ele -> ele //value
));
}
this.reorder(map.get(from), map.get(to));
}
private void reorder(WebElement source, WebElement target) {
this.action.clickAndHold(source)
.dragAndDropBy(target, OFFSET, OFFSET)
.build()
.perform();
}
}
Page Object:
Our aim contains the sortable element and exposes via getter method to the test class.
import org.openqa.selenium.WebDriver;
public class SortablePage {
private final WebDriver driver;
private SortableElement sortable;
public SortablePage(final WebDriver driver){
this.driver = driver;
}
public void goTo() {
driver.get("https://jqueryui.com/sortable/");
this.driver.switchTo().frame(0);
this.sortable = new SortableElement(driver);
}
public SortableElement getSortables() {
return sortable;
}
}
Test:
Lets test our SortableElement model using below test class. As our SortableElement could rearrange the order of the items either by text or index, I have 2 different test methods with corresponding data providers.
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.util.Arrays;
import java.util.List;
public class SortableTest {
private WebDriver driver;
private SortablePage sortablePage;
@BeforeTest
public void setupDriver() {
this.driver = new ChromeDriver();
this.sortablePage = new SortablePage(driver);
}
@Test(dataProvider = "number-inputs")
public void intMove(int fromIndex, int toIndex, List<String> expectedOrder) {
sortablePage.goTo();
sortablePage.getSortables().reorder(fromIndex, toIndex);
Assert.assertEquals(expectedOrder, sortablePage.getSortables().getItems());
}
@Test(dataProvider = "string-inputs")
public void stringMove(String fromItem, String toItem, List<String> expectedOrder) {
sortablePage.goTo();
sortablePage.getSortables().reorder(fromItem, toItem);
Assert.assertEquals(expectedOrder, sortablePage.getSortables().getItems());
}
@DataProvider(name = "number-inputs")
public static Object[][] getNumberInputs() {
return new Object[][]
{
{
0,
2,
Arrays.asList("Item 2", "Item 3", "Item 1", "Item 4", "Item 5", "Item 6", "Item 7")
},
{
1,
3,
Arrays.asList("Item 1", "Item 3", "Item 4", "Item 2", "Item 5", "Item 6", "Item 7")
}
};
}
@DataProvider(name = "string-inputs")
public static Object[][] getStringInputs() {
return new Object[][]
{
{
"Item 3",
"Item 4",
Arrays.asList("Item 1", "Item 2", "Item 4", "Item 3", "Item 5", "Item 6", "Item 7")
},
{
"Item 1",
"Item 7",
Arrays.asList("Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 1")
}
};
}
}
Demo:
Summary:
By simply adding an abstraction layer, we control a complex element like a simple WebElement. Now if the behavior changes / a new feature has to be added, modifying Sortable element class will do the trick for us.
Happy Testing & Subscribe 🙂
Thanks for such a great Article. It’s worth to read!! Very clear and neat one. Your article is short and detailed. i will refer and share your links.