Series Navigation
→ Part 12: Screenshots, File Downloads and Test Evidence
The Actions Builder Pattern
Actions builds a chain of interactions and executes them together with .perform():
import org.openqa.selenium.interactions.Actions;
Actions actions = new Actions(driver);
// Build and execute a chain
actions.moveToElement(menuItem) // hover
.click() // click
.perform(); // execute the chain
Mouse Hover — Opening Dropdown Menus
Actions actions = new Actions(driver);
// Hover over an element (triggers CSS :hover)
WebElement navMenu = driver.findElement(By.id("navMenu"));
actions.moveToElement(navMenu).perform();
// Wait for dropdown to appear
WebDriverWait wait = new WebDriverWait(driver, 5);
WebElement dropdown = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".dropdown-menu"))
);
// Click the dropdown item
WebElement menuItem = driver.findElement(By.linkText("Profile Settings"));
actions.moveToElement(menuItem).click().perform();
Hover with Offset
// Hover at a specific x,y offset from element's top-left corner
actions.moveToElement(element, 50, 20).perform();
// Hover at absolute page coordinate
actions.moveByOffset(500, 300).perform();
Right-Click (Context Menu)
WebElement rightClickArea = driver.findElement(By.id("rightClickDiv"));
actions.contextClick(rightClickArea).perform();
// The browser context menu appears — interact with it
// (Note: browser's native context menu can't be interacted with via Selenium
// For app-specific context menus, find the menu elements after right-click)
WebElement menuOption = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".context-menu-item"))
);
menuOption.click();
Double-Click
WebElement editableCell = driver.findElement(By.cssSelector("td.editable"));
actions.doubleClick(editableCell).perform();
// Verify cell entered edit mode
WebElement cellInput = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.cssSelector("td.editable input"))
);
cellInput.clear();
cellInput.sendKeys("New value");
cellInput.sendKeys(Keys.ENTER);
Click and Hold
// Click and hold (don't release)
WebElement slider = driver.findElement(By.id("slider-handle"));
actions.clickAndHold(slider).perform();
// Move while holding (drag)
actions.moveByOffset(100, 0).perform(); // move 100px right
// Release
actions.release().perform();
// Or do it all in one chain:
actions.clickAndHold(slider)
.moveByOffset(100, 0)
.release()
.perform();
Drag and Drop
WebElement source = driver.findElement(By.id("draggable"));
WebElement target = driver.findElement(By.id("droppable"));
// Method 1: dragAndDrop
actions.dragAndDrop(source, target).perform();
// Method 2: manual click-hold-move-release (more reliable in some browsers)
actions.clickAndHold(source)
.moveToElement(target)
.release(target)
.perform();
// Method 3: drag by offset in pixels
actions.dragAndDropBy(source, 200, 0).perform(); // drag 200px right
Drag and Drop with JavaScript (More Reliable)
Some drag-and-drop libraries intercept mouse events and don't respond to Selenium's Actions. Use JavaScript simulation:
// Inject a drag-and-drop simulation script
String dragDropScript = """
function simulateDragDrop(sourceNode, destinationNode) {
var EVENT_TYPES = {
DRAG_END: 'dragend',
DRAG_START: 'dragstart',
DROP: 'drop'
};
function createCustomEvent(type) {
var event = new CustomEvent(type, { bubbles: true, cancelable: true });
event.dataTransfer = { data: {}, setData: function(k,v){this.data[k]=v;},
getData: function(k){return this.data[k];} };
return event;
}
sourceNode.dispatchEvent(createCustomEvent(EVENT_TYPES.DRAG_START));
destinationNode.dispatchEvent(createCustomEvent(EVENT_TYPES.DROP));
sourceNode.dispatchEvent(createCustomEvent(EVENT_TYPES.DRAG_END));
}
simulateDragDrop(arguments[0], arguments[1]);
""";
WebElement source = driver.findElement(By.id("draggable"));
WebElement target = driver.findElement(By.id("droppable"));
((JavascriptExecutor) driver).executeScript(dragDropScript, source, target);
Keyboard Shortcuts with Actions
Actions actions = new Actions(driver);
// Ctrl+A (select all)
actions.keyDown(Keys.CONTROL)
.sendKeys("a")
.keyUp(Keys.CONTROL)
.perform();
// Ctrl+C (copy)
actions.keyDown(Keys.CONTROL)
.sendKeys("c")
.keyUp(Keys.CONTROL)
.perform();
// Ctrl+V (paste)
WebElement targetField = driver.findElement(By.id("pasteTarget"));
actions.click(targetField)
.keyDown(Keys.CONTROL)
.sendKeys("v")
.keyUp(Keys.CONTROL)
.perform();
// Ctrl+Shift+I (DevTools — don't actually do this in tests)
actions.keyDown(Keys.CONTROL)
.keyDown(Keys.SHIFT)
.sendKeys("i")
.keyUp(Keys.SHIFT)
.keyUp(Keys.CONTROL)
.perform();
// Select text with Shift+End
WebElement input = driver.findElement(By.id("textField"));
input.click();
actions.keyDown(Keys.SHIFT)
.sendKeys(Keys.END) // select to end of line
.keyUp(Keys.SHIFT)
.perform();
Complex Real-World Example: Resizable Column
@Test
public void testResizableTableColumn() {
WebDriver driver = getDriver();
driver.get("https://jqueryui.com/resizable/");
// Switch to iframe (jQuery UI demos use iframes)
driver.switchTo().frame(driver.findElement(By.cssSelector(".demo-frame")));
WebElement resizable = driver.findElement(By.id("resizable"));
// Get original size
Dimension originalSize = resizable.getSize();
System.out.println("Original: " + originalSize.width + "x" + originalSize.height);
// Find the resize handle (bottom-right corner)
WebElement handle = driver.findElement(By.cssSelector("#resizable .ui-resizable-se"));
// Drag the handle to resize
Actions actions = new Actions(driver);
actions.clickAndHold(handle)
.moveByOffset(100, 50) // expand 100px right, 50px down
.release()
.perform();
// Verify new size
Dimension newSize = resizable.getSize();
System.out.println("New size: " + newSize.width + "x" + newSize.height);
Assert.assertTrue(newSize.width > originalSize.width, "Width should increase");
}
What's Next
In Part 12 we capture screenshots, record test evidence, handle file downloads, and build a complete reporting utility that attaches screenshots to failed test reports.
Discussion
Loading...Leave a Comment
All comments are reviewed before appearing. No links please.