Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1946 deep shadow selectors support #1947

Merged
merged 2 commits into from Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/main/java/com/codeborne/selenide/Selectors.java
Expand Up @@ -2,6 +2,7 @@

import com.codeborne.selenide.selector.ByAttribute;
import com.codeborne.selenide.selector.ByShadow;
import com.codeborne.selenide.selector.ByDeepShadow;
import com.codeborne.selenide.selector.ByTagAndText;
import com.codeborne.selenide.selector.ByText;
import com.codeborne.selenide.selector.ByTextCaseInsensitive;
Expand Down Expand Up @@ -147,6 +148,16 @@ public static By shadowCss(String target, String shadowHost, String... innerShad
return ByShadow.cssSelector(target, shadowHost, innerShadowHosts);
}

/**
* @see ByDeepShadow#cssSelector(java.lang.String)
* @since v6.8.0
*/
@CheckReturnValue
@Nonnull
public static By shadowDeepCss(String target) {
BorisOsipov marked this conversation as resolved.
Show resolved Hide resolved
return ByDeepShadow.cssSelector(target);
}

/**
* Synonym for #byAttribute
*/
Expand Down
72 changes: 72 additions & 0 deletions src/main/java/com/codeborne/selenide/selector/ByDeepShadow.java
@@ -0,0 +1,72 @@
package com.codeborne.selenide.selector;

import com.codeborne.selenide.impl.Cleanup;
import com.codeborne.selenide.impl.JavaScript;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptException;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;

import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import java.io.Serializable;
import java.util.List;

@ParametersAreNonnullByDefault
public class ByDeepShadow {
private static final JavaScript jsSource = new JavaScript("query-selector-shadow-dom.js");

/***
* Find target elements. It pierces Shadow DOM roots without knowing the path through nested shadow roots.
* <p>
* <br/> For example: #shadow-host #inner-shadow-host target-element
* @param target CSS expression of target element
* @return A By which locates elements by CSS inside DOM with shadow-roots.
*/
@CheckReturnValue
@Nonnull
public static By cssSelector(String target) {
return new ByDeepShadowCss(target);
}

@ParametersAreNonnullByDefault
public static class ByDeepShadowCss extends By implements Serializable {
private final String target;

ByDeepShadowCss(String target) {
this.target = target;
}

@Override
@CheckReturnValue
@Nonnull
public WebElement findElement(SearchContext context) {
List<WebElement> found = findElements(context);
if (found.isEmpty()) {
throw new NoSuchElementException("Cannot locate an element in shadow dom " + this);
}
return found.get(0);
}

@Override
@CheckReturnValue
@Nonnull
public List<WebElement> findElements(SearchContext context) {
try {
return jsSource.execute(context, target);
}
catch (JavascriptException e) {
throw new NoSuchElementException(Cleanup.of.webdriverExceptionMessage(e));
}
}

@Override
@CheckReturnValue
@Nonnull
public String toString() {
return "By.shadowDeepCss: " + target;
}
}
}