You need to take care of a couple of things:
- Now that Chrome supports shadow root via the driver, shadowRootJS calls are returned per the spec with a shadow root element key (shadow-6066-11e4-a52e-4f735466cecf). selenium4 has a newShadowRootclass to support this, but it didn't include the translation code that we earlier did when execute script calls return elements. This has been fixed and will be available in Selenium v4.1. The only difference is that you'll need to cast toShadowRootinstead ofWebElement.
- The actual state is that the return value of that JavaScript changed in v96 of ChromeDriver in order to be w3c compliant. Selenium 3.141.59 can not parse this new return value. You can use getShadowRoot()in Selenium 4, or you'll be able to get aShadowRootinstance returned from the JS in Selenium 4.1.
Implementation
From the documentation
package org.openqa.selenium.remote;
import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WrapsDriver;
import org.openqa.selenium.internal.Require;
import java.util.List;
import java.util.Map;
import static java.util.Collections.singletonMap;
import static org.openqa.selenium.remote.Dialect.W3C;
import static org.openqa.selenium.remote.DriverCommand.FIND_ELEMENTS_FROM_SHADOW_ROOT;
import static org.openqa.selenium.remote.DriverCommand.FIND_ELEMENT_FROM_SHADOW_ROOT;
// Note: we want people to code against the SearchContext API, so we keep this class package private
class ShadowRoot implements SearchContext, WrapsDriver {
  private final RemoteWebDriver parent;
  private final String id;
  ShadowRoot(RemoteWebDriver parent, String id) {
    this.parent = Require.nonNull("Owning remote webdriver", parent);
    this.id = Require.nonNull("Shadow root ID", id);
  }
  @Override
  public List<WebElement> findElements(By by) {
    return parent.findElements(
      this,
      (using, value) -> FIND_ELEMENTS_FROM_SHADOW_ROOT(id, using, String.valueOf(value)),
      by);
  }
  @Override
  public WebElement findElement(By by) {
    return parent.findElement(
      this,
      (using, value) -> FIND_ELEMENT_FROM_SHADOW_ROOT(id, using, String.valueOf(value)),
      by);
  }
  @Override
  public WebDriver getWrappedDriver() {
    return parent;
  }
  public String getId() {
    return this.id;
  }
  private Map<String, Object> toJson() {
    return singletonMap(W3C.getShadowRootElementKey(), id);
  }
}
Example Code:
WebElement shadowHost = seleniumWebDriver.findElement(By.cssSelector("#shadowrootcontainer"));
JavascriptExecutor javascriptExecutor = (JavascriptExecutor) seleniumWebDriver;
SearchContext shadowRoot = (SearchContext) javascriptExecutor.executeScript("return arguments[0].shadowRoot", shadowHost);
WebElement shadowContent = shadowRoot.findElement(By.cssSelector("#shadowcontentcss"));
This Usecase
Your modified code block will be:
WebElement shadowDomHostElement = uiDriver.webDr.findElement(By.cssSelector("authoring-ui[ng-version='12.0.1']"));
JavascriptExecutor execute = (JavascriptExecutor)uiDriver.webDr;
SearchContext shadowRoot = (SearchContext) execute.executeScript("return arguments[0].shadowRoot", shadowDomHostElement);
WebElement executeshadow = shadowRoot.webDr.findElement(By.cssSelector("authoring-ui[ng-version='12.0.1']"));
TL; DR
Some helpful discussions: