Skip to content

Commit

Permalink
DoubleClick with custom options
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadowNinja authored and asolntsev committed Apr 4, 2023
1 parent 06b25a6 commit fe3e395
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 8 deletions.
14 changes: 14 additions & 0 deletions src/main/java/com/codeborne/selenide/SelenideElement.java
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,20 @@ public interface SelenideElement extends WebElement, WrapsDriver, WrapsElement,
@CanIgnoreReturnValue
SelenideElement doubleClick();

/**
* Double-click the element using {@link ClickOptions}: {@code $("#username").doubleClick(ClickOptions.usingJavaScript())}
*
* <p>
* You can specify a relative offset from the center of the element inside ClickOptions:
* e.g. {@code $("#username").doubleClick(usingJavaScript().offset(123, 222))}
* </p>
*
* @see com.codeborne.selenide.commands.DoubleClick
*/
@Nonnull
@CanIgnoreReturnValue
SelenideElement doubleClick(ClickOptions clickOption);

/**
* Emulate "mouseOver" event. In other words, move mouse cursor over this element (without clicking it).
*
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/codeborne/selenide/commands/Click.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ protected void click(Driver driver, WebElement element) {
clickViaJS(driver, element, 0, 0);
}
else {
defaultClick(element);
defaultClick(element, driver);
}
}

Expand Down Expand Up @@ -93,7 +93,7 @@ private void doClick(Driver driver, WebElement webElement, ClickOptions clickOpt
}
}

protected void defaultClick(WebElement element) {
protected void defaultClick(WebElement element, Driver driver) {
element.click();
}

Expand Down
27 changes: 23 additions & 4 deletions src/main/java/com/codeborne/selenide/commands/DoubleClick.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,38 @@
package com.codeborne.selenide.commands;

import com.codeborne.selenide.Command;
import com.codeborne.selenide.Driver;
import com.codeborne.selenide.SelenideElement;
import com.codeborne.selenide.impl.JavaScript;
import com.codeborne.selenide.impl.WebElementSource;
import org.openqa.selenium.WebElement;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;

@ParametersAreNonnullByDefault
public class DoubleClick implements Command<SelenideElement> {
public class DoubleClick extends Click {

private final JavaScript jsSource = new JavaScript("dblclick.js");

@Override
@Nonnull
public SelenideElement execute(SelenideElement proxy, WebElementSource locator, @Nullable Object[] args) {
locator.driver().actions().doubleClick(locator.findAndAssertElementIsInteractable()).perform();
return proxy;
return super.execute(proxy, locator, args);
}

@Override
protected void clickViaJS(Driver driver, WebElement element, int offsetX, int offsetY) {
jsSource.execute(driver, element, offsetX, offsetY);
}

@Override
protected void defaultClick(WebElement element, Driver driver) {
driver.actions().doubleClick(element).build().perform();
}

@Override
protected void defaultClick(Driver driver, WebElement element, int offsetX, int offsetY) {
driver.actions().moveByOffset(offsetX, offsetY).doubleClick(element).build().perform();
}
}
25 changes: 25 additions & 0 deletions src/main/resources/dblclick.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
(function (element, offsetX, offsetY) {
const rect = element.getBoundingClientRect();

function mouseEvent() {
if (typeof (Event) === 'function') {
return new MouseEvent('dblclick', {
'view': window,
'bubbles': true,
'cancelable': true,
'clientX': rect.left + rect.width / 2 + offsetX,
'clientY': rect.top + rect.height / 2 + offsetY
});
}
else {
const event = document.createEvent('MouseEvent');
event.initEvent('dblclick', true, true);
event.type = 'dblclick'
event.view = window;
event.clientX = rect.left + rect.width / 2 + offsetX
event.clientY = rect.top + rect.height / 2 + offsetY
return event;
}
}
element.dispatchEvent(mouseEvent());
})(arguments[0], arguments[1], arguments[2]);
42 changes: 40 additions & 2 deletions src/test/java/integration/DoubleClickTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package integration;

import com.codeborne.selenide.ClickOptions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static com.codeborne.selenide.Condition.disabled;
Expand All @@ -8,10 +10,14 @@
import static com.codeborne.selenide.Condition.value;

final class DoubleClickTest extends ITest {
@Test
void userCanDoubleClickOnElement() {

@BeforeEach
public void prepare() {
openFile("page_with_double_clickable_button.html");
}

@Test
void userCanDoubleClickOnElement() {
withLongTimeout(() -> {
$("#double-clickable-button")
.shouldHave(value("double click me"))
Expand All @@ -25,4 +31,36 @@ void userCanDoubleClickOnElement() {
$("h2").shouldHave(text("Double click worked"));
});
}

@Test
void userCanDoubleClickOnElementWithJs() {
withLongTimeout(() -> {
$("#double-clickable-button")
.shouldHave(value("double click me"))
.shouldBe(enabled);

$("#double-clickable-button")
.doubleClick(ClickOptions.usingJavaScript())
.shouldHave(value("do not click me anymore"))
.shouldBe(disabled);

$("h2").shouldHave(text("Double click worked"));
});
}

@Test
void userCanDoubleClickOnElementWithDefaultClickOption() {
withLongTimeout(() -> {
$("#double-clickable-button")
.shouldHave(value("double click me"))
.shouldBe(enabled);

$("#double-clickable-button")
.doubleClick(ClickOptions.usingDefaultMethod())
.shouldHave(value("do not click me anymore"))
.shouldBe(disabled);

$("h2").shouldHave(text("Double click worked"));
});
}
}

0 comments on commit fe3e395

Please sign in to comment.