org.openqa.selenium.interactions.Actions Maven / Gradle / Ivy
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.openqa.selenium.interactions;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.internal.Locatable;
/**
* The user-facing API for emulating complex user gestures. Use this class rather than using the
* Keyboard or Mouse directly.
*
* Implements the builder pattern: Builds a CompositeAction containing all actions specified by the
* method calls.
*/
public class Actions {
protected WebDriver driver;
protected Mouse mouse;
protected Keyboard keyboard;
protected CompositeAction action;
/**
* Default constructor - uses the default keyboard, mouse implemented by the driver.
* @param driver the driver providing the implementations to use.
*/
public Actions(WebDriver driver) {
this.driver = driver;
this.mouse = ((HasInputDevices) driver).getMouse();
this.keyboard = ((HasInputDevices) driver).getKeyboard();
resetCompositeAction();
}
/**
* A constructor that should only be used when the keyboard or mouse were extended to provide
* additional functionality (for example, dragging-and-dropping from the desktop).
* @param keyboard the {@link Keyboard} implementation to delegate to.
* @param mouse the {@link Mouse} implementation to delegate to.
*/
public Actions(Keyboard keyboard, Mouse mouse) {
this.mouse = mouse;
this.keyboard = keyboard;
resetCompositeAction();
}
/**
* Only used by the TouchActions class.
* @param keyboard implementation to delegate to.
*/
public Actions(Keyboard keyboard) {
this.keyboard = keyboard;
resetCompositeAction();
}
private void resetCompositeAction() {
action = new CompositeAction(driver);
}
/**
* Performs a modifier key press. Does not release the modifier key - subsequent interactions
* may assume it's kept pressed.
* Note that the modifier key is never released implicitly - either
* keyUp(theKey) or sendKeys(Keys.NULL)
* must be called to release the modifier.
* @param theKey Either {@link Keys#SHIFT}, {@link Keys#ALT} or {@link Keys#CONTROL}. If the
* provided key is none of those, {@link IllegalArgumentException} is thrown.
* @return A self reference.
*/
public Actions keyDown(Keys theKey) {
return this.keyDown(null, theKey);
}
/**
* Performs a modifier key press after focusing on an element. Equivalent to:
* Actions.click(element).sendKeys(theKey);
* @see #keyDown(org.openqa.selenium.Keys)
*
* @param theKey Either {@link Keys#SHIFT}, {@link Keys#ALT} or {@link Keys#CONTROL}. If the
* provided key is none of those, {@link IllegalArgumentException} is thrown.
* @param element WebElement to perform the action
* @return A self reference.
*/
public Actions keyDown(WebElement element, Keys theKey) {
action.addAction(new KeyDownAction(keyboard, mouse, (Locatable) element, theKey));
return this;
}
/**
* Performs a modifier key release. Releasing a non-depressed modifier key will yield undefined
* behaviour.
*
* @param theKey Either {@link Keys#SHIFT}, {@link Keys#ALT} or {@link Keys#CONTROL}.
* @return A self reference.
*/
public Actions keyUp(Keys theKey) {
return this.keyUp(null, theKey);
}
/**
* Performs a modifier key release after focusing on an element. Equivalent to:
* Actions.click(element).sendKeys(theKey);
* @see #keyUp(org.openqa.selenium.Keys) on behaviour regarding non-depressed modifier keys.
*
* @param theKey Either {@link Keys#SHIFT}, {@link Keys#ALT} or {@link Keys#CONTROL}.
* @param element WebElement to perform the action on
* @return A self reference.
*/
public Actions keyUp(WebElement element, Keys theKey) {
action.addAction(new KeyUpAction(keyboard, mouse, (Locatable) element, theKey));
return this;
}
/**
* Sends keys to the active element. This differs from calling
* {@link WebElement#sendKeys(CharSequence...)} on the active element in two ways:
*
* - The modifier keys included in this call are not released.
* - There is no attempt to re-focus the element - so sendKeys(Keys.TAB) for switching
* elements should work.
*
*
* @see WebElement#sendKeys(CharSequence...)
*
* @param keysToSend The keys.
* @return A self reference.
*/
public Actions sendKeys(CharSequence... keysToSend) {
return this.sendKeys(null, keysToSend);
}
/**
* Equivalent to calling:
* Actions.click(element).sendKeys(keysToSend).
* This method is different from {@link org.openqa.selenium.WebElement#sendKeys(CharSequence...)} - see
* {@link Actions#sendKeys(CharSequence...)} for details how.
*
* @see #sendKeys(java.lang.CharSequence[])
*
* @param element element to focus on.
* @param keysToSend The keys.
* @return A self reference.
*/
public Actions sendKeys(WebElement element, CharSequence... keysToSend) {
action.addAction(new SendKeysAction(keyboard, mouse, (Locatable) element, keysToSend));
return this;
}
/**
* Clicks (without releasing) in the middle of the given element. This is equivalent to:
* Actions.moveToElement(onElement).clickAndHold()
*
* @param onElement Element to move to and click.
* @return A self reference.
*/
public Actions clickAndHold(WebElement onElement) {
action.addAction(new ClickAndHoldAction(mouse, (Locatable) onElement));
return this;
}
/**
* Clicks (without releasing) at the current mouse location.
* @return A self reference.
*/
public Actions clickAndHold() {
return this.clickAndHold(null);
}
/**
* Releases the depressed left mouse button, in the middle of the given element.
* This is equivalent to:
* Actions.moveToElement(onElement).release()
*
* Invoking this action without invoking {@link #clickAndHold()} first will result in
* undefined behaviour.
*
* @param onElement Element to release the mouse button above.
* @return A self reference.
*/
public Actions release(WebElement onElement) {
action.addAction(new ButtonReleaseAction(mouse, (Locatable) onElement));
return this;
}
/**
* Releases the depressed left mouse button at the current mouse location.
* @see #release(org.openqa.selenium.WebElement)
* @return A self reference.
*/
public Actions release() {
return this.release(null);
}
/**
* Clicks in the middle of the given element. Equivalent to:
* Actions.moveToElement(onElement).click()
*
* @param onElement Element to click.
* @return A self reference.
*/
public Actions click(WebElement onElement) {
action.addAction(new ClickAction(mouse, (Locatable) onElement));
return this;
}
/**
* Clicks at the current mouse location. Useful when combined with
* {@link #moveToElement(org.openqa.selenium.WebElement, int, int)} or
* {@link #moveByOffset(int, int)}.
* @return A self reference.
*/
public Actions click() {
return this.click(null);
}
/**
* Performs a double-click at middle of the given element. Equivalent to:
* Actions.moveToElement(element).doubleClick()
*
* @param onElement Element to move to.
* @return A self reference.
*/
public Actions doubleClick(WebElement onElement) {
action.addAction(new DoubleClickAction(mouse, (Locatable) onElement));
return this;
}
/**
* Performs a double-click at the current mouse location.
* @return A self reference.
*/
public Actions doubleClick() {
return this.doubleClick(null);
}
/**
* Moves the mouse to the middle of the element. The element is scrolled into view and its
* location is calculated using getBoundingClientRect.
* @param toElement element to move to.
* @return A self reference.
*/
public Actions moveToElement(WebElement toElement) {
action.addAction(new MoveMouseAction(mouse, (Locatable) toElement));
return this;
}
/**
* Moves the mouse to an offset from the top-left corner of the element.
* The element is scrolled into view and its location is calculated using getBoundingClientRect.
* @param toElement element to move to.
* @param xOffset Offset from the top-left corner. A negative value means coordinates left from
* the element.
* @param yOffset Offset from the top-left corner. A negative value means coordinates above
* the element.
* @return A self reference.
*/
public Actions moveToElement(WebElement toElement, int xOffset, int yOffset) {
action.addAction(new MoveToOffsetAction(mouse, (Locatable) toElement, xOffset, yOffset));
return this;
}
/**
* Moves the mouse from its current position (or 0,0) by the given offset. If the coordinates
* provided are outside the viewport (the mouse will end up outside the browser window) then
* the viewport is scrolled to match.
* @param xOffset horizontal offset. A negative value means moving the mouse left.
* @param yOffset vertical offset. A negative value means moving the mouse up.
* @return A self reference.
* @throws MoveTargetOutOfBoundsException if the provided offset is outside the document's
* boundaries.
*/
public Actions moveByOffset(int xOffset, int yOffset) {
action.addAction(new MoveToOffsetAction(mouse, null, xOffset, yOffset));
return this;
}
/**
* Performs a context-click at middle of the given element. First performs a mouseMove
* to the location of the element.
*
* @param onElement Element to move to.
* @return A self reference.
*/
public Actions contextClick(WebElement onElement) {
action.addAction(new ContextClickAction(mouse, (Locatable) onElement));
return this;
}
/**
* Performs a context-click at the current mouse location.
* @return A self reference.
*/
public Actions contextClick() {
return this.contextClick(null);
}
/**
* A convenience method that performs click-and-hold at the location of the source element,
* moves to the location of the target element, then releases the mouse.
*
* @param source element to emulate button down at.
* @param target element to move to and release the mouse at.
* @return A self reference.
*/
public Actions dragAndDrop(WebElement source, WebElement target) {
action.addAction(new ClickAndHoldAction(mouse, (Locatable) source));
action.addAction(new MoveMouseAction(mouse, (Locatable) target));
action.addAction(new ButtonReleaseAction(mouse, (Locatable) target));
return this;
}
/**
* A convenience method that performs click-and-hold at the location of the source element,
* moves by a given offset, then releases the mouse.
*
* @param source element to emulate button down at.
* @param xOffset horizontal move offset.
* @param yOffset vertical move offset.
* @return A self reference.
*/
public Actions dragAndDropBy(WebElement source, int xOffset, int yOffset) {
action.addAction(new ClickAndHoldAction(mouse, (Locatable) source));
action.addAction(new MoveToOffsetAction(mouse, null, xOffset, yOffset));
action.addAction(new ButtonReleaseAction(mouse, null));
return this;
}
/**
* Performs a pause.
*
* @param pause pause duration, in milliseconds.
* @return A self reference.
*
* @deprecated 'Pause' is considered to be a bad design practice.
*/
@Deprecated
public Actions pause(long pause) {
action.addAction(new PauseAction(pause));
return this;
}
/**
* Generates a composite action containing all actions so far, ready to be performed (and
* resets the internal builder state, so subsequent calls to build() will contain fresh
* sequences).
*
* @return the composite action
*/
public Action build() {
CompositeAction toReturn = action;
resetCompositeAction();
return toReturn;
}
/**
* A convenience method for performing the actions without calling build() first.
*/
public void perform() {
build().perform();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy