org.jboss.arquillian.ajocado.actions.Drag Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of graphene-selenium-impl Show documentation
Show all versions of graphene-selenium-impl Show documentation
Testing Ajax with flavour of sexy type-safe API
/**
* JBoss, Home of Professional Open Source
* Copyright 2011, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* 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.jboss.arquillian.ajocado.actions;
import static org.jboss.arquillian.ajocado.Graphene.waitGui;
import org.jboss.arquillian.ajocado.framework.GrapheneSelenium;
import org.jboss.arquillian.ajocado.framework.GrapheneSeleniumContext;
import org.jboss.arquillian.ajocado.geometry.Dimension;
import org.jboss.arquillian.ajocado.geometry.Point;
import org.jboss.arquillian.ajocado.locator.element.ElementLocator;
import org.jboss.arquillian.ajocado.waiting.Waiting;
/**
*
* Provides item dragging capability to Selenium tests.
*
*
*
* Methods can be call in following serie: start, mouseOut, move, enter, drop.
*
*
*
* If we are calling preceding phase (e.g. move, when drag was already called), IllegalStateException is thrown.
*
*
*
* If we are calling following phase (e.g. drop, when no action was called), all phases preceding requested phase will be done
* before requested phase can be done.
*
*
* @author Lukas Fryc
* @version $Revision$
*/
public class Drag {
/** The Constant NUMBER_OF_STEPS. */
private static final int NUMBER_OF_STEPS = 5;
/** The Constant FIRST_STEP. */
private static final int FIRST_STEP = 2;
/**
* Proxy to local selenium instance
*/
private GrapheneSelenium selenium = GrapheneSeleniumContext.getProxy();
/** The point. */
private Point currentDelta;
// specifies phase in which is dragging state
/** The current phase. */
private Phase currentPhase;
/** The item to drag. */
private ElementLocator> itemToDrag;
/** The drag indicator. */
private ElementLocator> dragIndicator;
/** The drop target. */
private ElementLocator> dropTarget;
private Point startMove;
private Point currentPosition;
private Point endPosition;
private Point overallMove;
private Point reposition = new Point(0, 0);
private Point movement = new Point(0, 0);
private int numberOfSteps = NUMBER_OF_STEPS;
/** The wait. */
private final Waiting> wait = waitGui.timeout(10);
/**
* Initiates Drag object, handled by given Selenium instance, instructing drag of itemToDrag to dropTarget object.
*
* @param itemToDrag item to drag
* @param dropTarget target of item dragging
*/
public Drag(ElementLocator> itemToDrag, ElementLocator> dropTarget) {
this.currentPhase = Phase.INITIAL;
this.itemToDrag = itemToDrag;
this.dropTarget = dropTarget;
setDropTarget(dropTarget);
}
public void setDropTarget(ElementLocator> dropTarget) {
switch (currentPhase) {
case INITIAL:
startMove = new Point(selenium.getElementWidth(itemToDrag) / 2, selenium.getElementHeight(itemToDrag) / 2);
currentPosition = getCenterOfElement(itemToDrag);
endPosition = getCenterOfElement(dropTarget);
overallMove = endPosition.substract(currentPosition);
return;
case DROP:
throw new IllegalStateException("draggable was already dropped");
case ENTER:
selenium.mouseOut(this.dropTarget);
break;
default:
}
if (Phase.MOUSE_OUT.before(currentPhase)) {
currentPhase = Phase.MOUSE_OUT;
}
endPosition = getCenterOfElement(dropTarget);
overallMove = endPosition.substract(currentPosition);
reposition = currentDelta.substract(startMove);
movement = new Point(0, 0);
this.dropTarget = dropTarget;
}
public void setDragIndicator(ElementLocator> dragIndicator) {
this.dragIndicator = dragIndicator;
}
public void setNumberOfSteps(int numberOfSteps) {
this.numberOfSteps = numberOfSteps;
}
/**
* Starts first phase of dragging.
*
* Simulate left mouse button pressing and small initial movement.
*/
public void start() {
processUntilPhase(Phase.START);
}
/**
* Starts second phase of dragging.
*
* If there is some unfinished preceding phases, it will be done before this phase.
*
* Simulate movement of mouse cursor out of the item that ve want to drag.
*/
public void mouseOut() {
processUntilPhase(Phase.MOUSE_OUT);
}
/**
* Starts third phase of dragging.
*
* If there is some unfinished preceding phases, it will be done before this phase.
*
* Simulate movement of mouse cursor near the target item.
*/
public void move() {
processUntilPhase(Phase.MOVE);
}
/**
* Starts fourth phase of dragging.
*
* If there is some unfinished preceding phases, it will be done before this phase.
*/
public void enter() {
processUntilPhase(Phase.ENTER);
}
/**
* Last phase of dragging.
*
* If there is some unfinished preceding phases, it will be done before this phase.
*
* Drop the item to target.
*/
public void drop() {
processUntilPhase(Phase.DROP);
}
/**
* Holds whole process of dragging serialized to one switch condition.
*
* If some phase is called by its number, it will be recognized, that is possible to process this step.
*
* Internally is used counter 'phase' which will be decreased when passed to a new phase. Switch condition breaks when will
* finished in requesting phase.
*/
private void processUntilPhase(Phase requestedPhase) {
if (requestedPhase.before(currentPhase)) {
throw new IllegalArgumentException("Requested phase (" + requestedPhase + ") is before current phase ("
+ currentPhase + ")");
}
while ((currentPhase.before(requestedPhase))) {
currentPhase = currentPhase.next();
executePhase(currentPhase);
}
}
/**
* Executes the instructions for given phase.
*
* @param phase the phase what should be executed
*/
private void executePhase(Phase phase) {
switch (phase) {
case START:
currentDelta = startMove.add(new Point((overallMove.getX() < 0) ? FIRST_STEP : -FIRST_STEP,
(overallMove.getY() < 0) ? FIRST_STEP : -FIRST_STEP));
selenium.mouseDownAt(itemToDrag, new Point(0, 0));
selenium.mouseMoveAt(itemToDrag, new Point(2, 2));
if (dragIndicator != null && selenium.isElementPresent(dragIndicator)) {
startMove = startMove.substract(getCentral(dragIndicator));
}
selenium.mouseMoveAt(itemToDrag, startMove);
break;
case MOUSE_OUT:
selenium.mouseOut(itemToDrag);
break;
case MOVE:
for (int i = 0; i < numberOfSteps; i++) {
Point oldMovement = movement;
movement = new Point(overallMove.getX() * i / numberOfSteps, overallMove.getY() * i / numberOfSteps);
Point movementDelta = movement.substract(oldMovement);
currentDelta = reposition.add(startMove).add(movement);
selenium.mouseMoveAt(itemToDrag, currentDelta);
currentPosition = currentPosition.add(movementDelta);
wait.waitForTimeout();
}
break;
case ENTER:
currentDelta = reposition.add(startMove).add(overallMove);
currentPosition = endPosition;
selenium.mouseMoveAt(itemToDrag, currentDelta);
selenium.mouseOverAt(dropTarget, currentDelta);
break;
case DROP:
selenium.mouseUp(dropTarget);
break;
default:
}
}
/**
* Enumeration of phases supported by this {@link Drag} object.
*/
public enum Phase {
INITIAL,
START,
MOUSE_OUT,
MOVE,
ENTER,
DROP;
/**
* Compares given phase to this phase.
*
* @param phase the phase
* @return true, if given phase is before this phase; else otherwise
*/
boolean before(Phase phase) {
return this.compareTo(phase) < 0;
}
/**
* Return next phase in order after this phase.
*
* @return the next phase in oder after this phase
*/
Phase next() {
boolean returnNextPhase = false;
for (Phase phase : Phase.values()) {
if (returnNextPhase) {
return phase;
}
if (this == phase) {
returnNextPhase = true;
}
}
return null;
}
}
private Point getCentral(ElementLocator> element) {
Dimension dimension = selenium.getElementDimension(element);
Point central = new Point(dimension.getWidth() / 2, dimension.getHeight() / 2);
return central;
}
private Point getCenterOfElement(ElementLocator> element) {
return selenium.getElementPosition(element).add(getCentral(element));
}
}