Skip to content

Commit

Permalink
selenide#2288 Wait until element becomes enabled before click
Browse files Browse the repository at this point in the history
  • Loading branch information
Au6ojlut committed May 20, 2023
1 parent 9de5827 commit 81ffd42
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 2 deletions.
23 changes: 22 additions & 1 deletion src/main/java/com/codeborne/selenide/SelenideElement.java
Original file line number Diff line number Diff line change
Expand Up @@ -1249,13 +1249,21 @@ public interface SelenideElement extends WebElement, WrapsDriver, WrapsElement,
SelenideElement cached();

/**
* Click the element using {@link ClickOptions}: {@code $("#username").click(ClickOptions.usingJavaScript())}<p>
* Click the element using {@link ClickOptions}:
*
* <pre>
* {@code $("#username").click(ClickOptions.usingJavaScript())}
* </pre>
*
* You can specify a relative offset from the center of the element inside ClickOptions:
* e.g. <pre>
* {@code $("#username").click(usingJavaScript().offset(123, 222))}
* </pre>
*
* Before clicking, waits until element gets interactable and enabled.
* <br>
*
* @return this element
* @see com.codeborne.selenide.commands.Click
*/
SelenideElement click(ClickOptions clickOption);
Expand All @@ -1268,6 +1276,10 @@ public interface SelenideElement extends WebElement, WrapsDriver, WrapsElement,
* But it uses JavaScript method to click if {@code com.codeborne.selenide.Configuration#clickViaJs} is defined.
* It may be helpful for testing in Internet Explorer where native click doesn't always work correctly.
*
* <br><br>
* Before clicking, waits until element gets interactable and enabled.
* <br>
*
* @see com.codeborne.selenide.commands.Click
*/
@Override
Expand All @@ -1286,6 +1298,10 @@ public interface SelenideElement extends WebElement, WrapsDriver, WrapsElement,
/**
* Double-click the element
*
* <br><br>
* Before clicking, waits until element gets interactable and enabled.
* <br>
*
* @return this element
* @see com.codeborne.selenide.commands.DoubleClick
*/
Expand All @@ -1301,6 +1317,11 @@ public interface SelenideElement extends WebElement, WrapsDriver, WrapsElement,
* e.g. {@code $("#username").doubleClick(usingJavaScript().offset(123, 222))}
* </p>
*
* <br>
* Before clicking, waits until element gets interactable and enabled.
* <br>
*
* @return this element
* @see com.codeborne.selenide.commands.DoubleClick
* @since 6.13.0
*/
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/codeborne/selenide/commands/Click.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ else if (args.length == 1) {
@Nonnull
@CheckReturnValue
protected WebElement findElement(WebElementSource locator) {
return locator.findAndAssertElementIsInteractable();
return locator.findAndAssertElementIsClickable();
}

protected void click(Driver driver, WebElement element) {
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/codeborne/selenide/impl/WebElementSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.codeborne.selenide.Condition;
import com.codeborne.selenide.Driver;
import com.codeborne.selenide.SelenideElement;
import com.codeborne.selenide.conditions.And;
import com.codeborne.selenide.ex.ElementNotFound;
import com.codeborne.selenide.ex.ElementShould;
import com.codeborne.selenide.ex.ElementShouldNot;
Expand All @@ -21,9 +22,11 @@

import static com.codeborne.selenide.CheckResult.Verdict.ACCEPT;
import static com.codeborne.selenide.Condition.editable;
import static com.codeborne.selenide.Condition.enabled;
import static com.codeborne.selenide.Condition.interactable;
import static com.codeborne.selenide.Condition.not;
import static com.codeborne.selenide.impl.Alias.NONE;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;

Expand Down Expand Up @@ -158,6 +161,18 @@ public WebElement findAndAssertElementIsInteractable() {
return requireNonNull(checkConditionAndReturnElement("be ", interactable, false));
}

/**
* Asserts that returned element is enabled and can be interacted with.
*
* @return element or throws ElementShould/ElementShouldNot exceptions
* @since 6.15.0
*/
@Nonnull
@CheckReturnValue
public WebElement findAndAssertElementIsClickable() {
return requireNonNull(checkConditionAndReturnElement("be ", new And("clickable", asList(interactable, enabled)), false));
}

/**
* Asserts that returned element is editable.
* @return element or throws ElementShould/ElementShouldNot exceptions
Expand Down
16 changes: 16 additions & 0 deletions src/test/resources/page_with_disabled_button_click.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Position click test</title>
<meta charset="UTF-8">
</head>
<body>
<div id="page">THIS IS A TEST</div>
<form>
<label> Name:
<input value="name" type="text"/>
</label>
<button id="submit" type="submit" disabled="disabled">SUBMIT</button>
</form>
</body>
</html>
26 changes: 26 additions & 0 deletions statics/src/test/java/integration/ClickDisabledButtonTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package integration;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static com.codeborne.selenide.Selenide.$;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

final class ClickDisabledButtonTest extends IntegrationTest {
@BeforeEach
void openTestPage() {
openFile("page_with_disabled_button_click.html");
}

@Test
void failToClickIfButtonIsDisabled() {
assertThatThrownBy(() -> $("#submit").click())
.hasMessageStartingWith("Element should be clickable: interactable and enabled {#submit}");
}

@Test
void failToDoubleClickIfButtonIsDisabled() {
assertThatThrownBy(() -> $("#submit").doubleClick())
.hasMessageStartingWith("Element should be clickable: interactable and enabled {#submit}");
}
}

0 comments on commit 81ffd42

Please sign in to comment.