Skip to content

Commit

Permalink
Add document and change the syntax on the steps for Drag and Drop
Browse files Browse the repository at this point in the history
  • Loading branch information
Khodyka Liubov authored and Khodyka Liubov committed Nov 24, 2023
1 parent 4618e8a commit 2807d98
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 22 deletions.
67 changes: 67 additions & 0 deletions docs/modules/plugins/pages/plugin-web-app.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,73 @@ When I select element located `$locator` and upload file `$filePath`
When I select element located by `id(uploadfile)` and upload file `/folder/file_for_upload.png`
----

=== Drag and drop steps

This set of steps facilitates the dragging and dropping of elements on a web page.
Desired position relative to the target element (TOP, BOTTOM, LEFT, RIGHT, CENTER, LEFT_TOP, RIGHT_TOP, LEFT_BOTTOM, RIGHT_BOTTOM).

==== The drag and drop using mouse

This step for a drag-and-drop operation for specified elements.

[source,gherkin]
----
When I drag element located by `$draggable` and drop it at $location of element located by `$target`
----

* $draggable: - The <<_locator,locator>> to identify the element to be dragged
* $location: - Action to select the position state of the element (TOP, BOTTOM, LEFT, RIGHT, CENTER, LEFT_TOP, RIGHT_TOP, LEFT_BOTTOM, RIGHT_BOTTOM).
* $target: - The <<_locator,locator>> to identify the target element.

.Dragging the image on the page
[source,gherkin]
----
When I drag element located by `$draggable` and drop it at $location of element located by `$target`
----

==== The drag and drop operation simulation

This step simulated a drag-and-drop operation for specified elements,
replicating the behavior without actual user interaction.

[source,gherkin]
----
When I simulate drag of element located by `$draggable` and drop at element located by `$target`
----

* $draggable: - The <<_locator,locator>> to identify the element to be dragged
* $target: - The <<_locator,locator>> to identify the target element.

.Simulation of dragging an image onto the page

[source,gherkin]
----
When I simulate drag of element located by `$draggable` and drop at element located by `$target`
----

=== Hover mouse over the element

Moves a mouse cursor on the element.

[source,gherkin]
----
When I hover mouse over element located by `$locator`
----

_Deprecated syntax (will be removed in VIVIDUS 0.7.0)_:
[source,gherkin]
----
When I hover mouse over element located `$locator`
----

* `$locator` - The <<_locator,locator>> to an element to hover.

.Step example
[source,gherkin]
----
When I hover mouse over element located by `id(hoverme)`
----

=== Check each element has a specific number of children elements

Checks that each element specified by the locator contains an exact number of visible child elements specified by another locator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
package org.vividus.steps.ui.web;

import java.time.Duration;
import java.util.Optional;
import java.util.function.BiConsumer;

import org.apache.commons.lang3.ObjectUtils;
import org.jbehave.core.annotations.When;
import org.openqa.selenium.Point;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.vividus.annotation.Replacement;
import org.vividus.selenium.IWebDriverProvider;
import org.vividus.selenium.locator.Locator;
import org.vividus.steps.ui.validation.IBaseValidations;
Expand All @@ -34,6 +36,11 @@
@TakeScreenshotOnFailure
public class DragAndDropSteps
{
private static final int RIGHT_OFFSET = 10;
private static final int LEFT_OFFSET = -10;
private static final String DRAGGABLE_ELEMENT = "Draggable element";
private static final String TARGET_ELEMENT = "Target element";
private static final String SIMULATE_DRAG_AND_DROP_JS = "simulate-drag-and-drop.js";
private final IWebDriverProvider webDriverProvider;
private final WebJavascriptActions javascriptActions;
private final IBaseValidations baseValidations;
Expand All @@ -59,9 +66,47 @@ public DragAndDropSteps(IWebDriverProvider webDriverProvider, WebJavascriptActio
* @param location location relatively to the <b>target</b> element (<b>TOP</b>,<b>BOTTOM</b>,<b>LEFT</b>,
* <b>RIGHT</b>,<b>CENTER</b>,<b>LEFT_TOP</b>,<b>RIGHT_TOP</b>,<b>LEFT_BOTTOM</b>,<b>RIGHT_BOTTOM</b>)
* @param target target element
* @deprecated Use step:
* "When I drag element located by `$draggable` and drop it at $location of element located by `$target`" instead
*/
@Deprecated(since = "0.6.4", forRemoval = true)
@Replacement(versionToRemoveStep = "0.7.0", replacementFormatPattern =
"When I drag element located by `%1$s` and drop it at %2$s of element located by `%3$s`")
@When("I drag element located `$draggable` and drop it at $location of element located `$target`")
@SuppressWarnings("checkstyle:MagicNumber")
public void dragAndDropToTargetAtLocationDeprecated(Locator draggable, Location location, Locator target)
{
performDragAndDropDeprecated(draggable, target, (draggableElement, targetElement) ->
{
Point offsetPoint = location.getPoint(draggableElement.getRect(), targetElement.getRect());
new Actions(webDriverProvider.get())
.clickAndHold(draggableElement)
// Selenium bug: https://github.com/SeleniumHQ/selenium/issues/1365#issuecomment-547786925
.moveByOffset(RIGHT_OFFSET, 0)
.moveByOffset(LEFT_OFFSET, 0)
.moveByOffset(offsetPoint.getX(), offsetPoint.getY())
.release()
// Wait for DOM stabilization
.pause(Duration.ofSeconds(1))
.perform();
});
}

/**
* Drags the <b>draggable</b> element and moves it relatively to the <b>target</b> element in
* accordance to provided <b>location</b>.
* <br>
* <i>Example</i>
* <br>
* <code>When I drag element located by `By.xpath(//div[@class='draggable'])` and drop it at RIGHT_TOP of element
* located by `By.xpath(//div[@class='target'])`</code>
* If this step doesn't work, try to use step simulating drag&amp;drop
* @param draggable draggable element
* @param location location relatively to the <b>target</b> element (<b>TOP</b>,<b>BOTTOM</b>,<b>LEFT</b>,
* <b>RIGHT</b>,<b>CENTER</b>,<b>LEFT_TOP</b>,<b>RIGHT_TOP</b>,<b>LEFT_BOTTOM</b>,<b>RIGHT_BOTTOM</b>)
* @param target target element
*/
@When("I drag element located by `$draggable` and drop it at $location of element located by `$target`")
public void dragAndDropToTargetAtLocation(Locator draggable, Location location, Locator target)
{
performDragAndDrop(draggable, target, (draggableElement, targetElement) ->
Expand All @@ -70,8 +115,8 @@ public void dragAndDropToTargetAtLocation(Locator draggable, Location location,
new Actions(webDriverProvider.get())
.clickAndHold(draggableElement)
// Selenium bug: https://github.com/SeleniumHQ/selenium/issues/1365#issuecomment-547786925
.moveByOffset(10, 0)
.moveByOffset(-10, 0)
.moveByOffset(RIGHT_OFFSET, 0)
.moveByOffset(LEFT_OFFSET, 0)
.moveByOffset(offsetPoint.getX(), offsetPoint.getY())
.release()
// Wait for DOM stabilization
Expand Down Expand Up @@ -106,25 +151,79 @@ public void dragAndDropToTargetAtLocation(Locator draggable, Location location,
* </p>
* @param draggable draggable element
* @param target target element
* @deprecated Use step:
* "When I simulate drag of element located by `$draggable` and drop at element located by `$target`" instead
*/
@Deprecated(since = "0.6.4", forRemoval = true)
@Replacement(versionToRemoveStep = "0.7.0", replacementFormatPattern =
"When I simulate drag of element located by `%1$s` and drop at element located by `%2$s`")
@When("I simulate drag of element located `$draggable` and drop at element located `$target`")
public void simulateDragAndDropDeprecated(Locator draggable, Locator target)
{
performDragAndDropDeprecated(draggable, target, (draggableElement, targetElement) ->
// See gist for details: https://gist.github.com/valfirst/7f36c8755676cdf8943a8a8f08eab2e3
javascriptActions.executeScriptFromResource(getClass(),
SIMULATE_DRAG_AND_DROP_JS, draggableElement,
targetElement));
}

/**
* Simulates drag of the <b>draggable</b> element and its drop at the <b>target</b> element via JavaScript.
* <br>
* <i>Example</i>
* <br>
* <code>When I simulate drag of element located `By.xpath(//div[@class='draggable'])` and drop at element located
* `By.xpath(//div[@class='target'])`</code>
* <p>
* The reason of having this step is that Selenium WebDriver doesn't support HTML5 drag&amp;drop:
* </p>
* <ul>
* <li><a href="https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/3604">
* Issue 3604: HTML5 Drag and Drop with Selenium WebDriver
* </a>
* </li>
* <li><a href="https://github.com/SeleniumHQ/selenium/issues/1365">
* Issue 1365: Actions drag and drop method
* </a>
* </li>
* </ul>
* <p>
* As workaround for these issue the step simulates HTML5 drag&amp;drop via JavaScript. There is no difference in
* actual drag&amp;drop and its simulation via JavaScript from the functional side.
* </p>
* @param draggable draggable element
* @param target target element
*/
@When("I simulate drag of element located by `$draggable` and drop at element located by `$target`")
public void simulateDragAndDrop(Locator draggable, Locator target)
{
performDragAndDrop(draggable, target, (draggableElement, targetElement) ->
// See gist for details: https://gist.github.com/valfirst/7f36c8755676cdf8943a8a8f08eab2e3
javascriptActions.executeScriptFromResource(getClass(), "simulate-drag-and-drop.js", draggableElement,
javascriptActions.executeScriptFromResource(getClass(), SIMULATE_DRAG_AND_DROP_JS, draggableElement,
targetElement));
}

private void performDragAndDrop(Locator draggable, Locator target,
private void performDragAndDropDeprecated(Locator draggable, Locator target,
BiConsumer<WebElement, WebElement> dragAndDropExecutor)
{
WebElement draggableElement = baseValidations.assertIfElementExists("Draggable element", draggable);
WebElement targetElement = baseValidations.assertIfElementExists("Target element", target);
WebElement draggableElement = baseValidations.assertIfElementExists(DRAGGABLE_ELEMENT, draggable);
WebElement targetElement = baseValidations.assertIfElementExists(TARGET_ELEMENT, target);

if (ObjectUtils.allNotNull(draggableElement, targetElement))
{
dragAndDropExecutor.accept(draggableElement, targetElement);
}
}

private void performDragAndDrop(Locator draggable, Locator target,
BiConsumer<WebElement, WebElement> dragAndDropExecutor)
{
Optional<WebElement> draggableElement = baseValidations.assertElementExists(DRAGGABLE_ELEMENT, draggable);
Optional<WebElement> targetElement = baseValidations.assertElementExists(TARGET_ELEMENT, target);

if (draggableElement.isPresent() && targetElement.isPresent())
{
dragAndDropExecutor.accept(draggableElement.get(), targetElement.get());
}
}
}
Loading

0 comments on commit 2807d98

Please sign in to comment.