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

Add new locator type for Shadow Root elements #7905

Closed
wants to merge 7 commits into from

Conversation

Jiwari
Copy link
Contributor

@Jiwari Jiwari commented Dec 31, 2019

Description

Adds support to locate elements that have Shadow Roots.
Adds new annotation @FindShadowBy, which can be used to locate and elements that are inside a Shadow Root.
Adds a helper class ShadowElementFinder, which can be used to verify if an element has a Shadow Root attached to it.

Motivation and Context

Right now Selenium doesn't support PageObject annotations in elements that have Shadow Root.

The current approach:

@FindBy(css = "foo")
WebElement fieldWithShadowRoot;

public WebElement getSomeShadow() {
  JavascriptExecutor js = (JavascriptExecutor) driver;
  WebElement shadowElement = (WebElement) js.executeScript("arguments[0].shadowRoot", fieldWithShadowRoot);
  WebElement elementInsideShadowRoot = shadowElement.findElement(By.css("innerShadowSelector"));
  return elementInsideShadowRoot;
}

New implementation allows:

@FindShadowBy({@FindBy(css = "foo"),  @FindBy(css = "innerShadowSelector")})
WebElement element;

As in @FindBy, it also allows to retrieve lists:

@FindShadowBy({@FindBy(css = "foo"),  @FindBy(css = "innerShadowSelector")})
List<WebElement> element;

If nested Shadow Roots are present, the same will work, the only thing that needs to be provided is the selector for each Shadow Root in the correct order that they are nested:

<div id="shadow1">
  #shadow-root
    <div id="shadow2">
      #shadow-root
        <div id="insideShadow2">
        </div>
    </div>
</div>
@FindShadowBy({@FindBy(css = "#shadow1"),  
    @FindBy(css = "#shadow2"), 
    @FindBy(css= "#insideShadow2")})
WebElement element;

Notes

The elements returned by the last @FindBy won't have their shadow roots extracted automatically, this is to allow the user to use methods such as getAttribute, which would throw an error if inside the shadow root. If the user wants to extract it, ShadowElementFinder can be used to do so.
This also means that providing just one locator to@FindShadowBy will yield the same result as using @FindBy, which is not a concern.

Once inside a Shadow Root, it's not possible to use xpath selector.
I didn't add any validations to FindShadowBy as this could limit the usage of the chain selectors, and Selenium already throws an exception if the user tries to use an invalid selector type.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • I have read the contributing document.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@Jiwari Jiwari force-pushed the ShadowElementFinder branch 6 times, most recently from 4426fff to 0bd7885 Compare January 8, 2020 16:34
@Jiwari Jiwari force-pushed the ShadowElementFinder branch 2 times, most recently from 7284bb5 to b9f198e Compare January 13, 2020 15:46
@CLAassistant
Copy link

CLA assistant check
All committers have signed the CLA.

import static org.openqa.selenium.testing.drivers.Browser.MARIONETTE;

/**
* Shadow Root is not supported by Firefox.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shadow-DOM is supported in Firefox https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot#Browser_compatibility

But calling "element.shadowRoot" will return the map of different attributes, so you cannot cast it to WebElement but must directly search inside it by "shadowRoot.querySelector()"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, and it's possible.
But to get the selector out of By, I would have to use a toString() and remove the prefix By.cssSelector: manually, which may cause issues later if toString() is changed to something else.
A better option would be to add a method to By class to get only the selector.
I will make some changes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dstekanov Please take a look on the new implementation.

@Jiwari Jiwari force-pushed the ShadowElementFinder branch 2 times, most recently from ddf95ac to 3c616af Compare March 9, 2020 16:08
@dstekanov
Copy link

Hi @Jiwari,
there is an original issue for WebDriver standard. You can have a look at this issue 1320. I am not a decision-maker, but I am afraid that your changes might not be approved by the owners.

@diemol diemol closed this Jul 12, 2020
@diemol diemol reopened this Jul 12, 2020
@diemol diemol changed the base branch from master to trunk July 12, 2020 19:53
@diemol diemol added the C-java label Mar 29, 2021
@diemol
Copy link
Member

diemol commented May 9, 2021

Closing this to consolidate on #5869

@diemol diemol closed this May 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants