2

I am trying to find the element of the field First Name on the page https://whitelabel.sandbox.array.io/signup?platform=v3. I tried searching by id, classname, name, cssSelector, etc. but none works. I even added waiter to ensure it is loaded well before I try to find the element. Same issue happens for all fields in the page. So, the issue is not unique to this field.

Tried this in Chrome and Firefox on Mac. The same code works well to find the username field in gmail.com page.

driver.get("https://whitelabel.sandbox.array.io/signup?platform=v3");
driver.manage().window().maximize();
WebDriverWait wait = new WebDriverWait(driver, java.time.Duration.ofSeconds(10));
WebElement selectFirstName = driver.findElement(By.name("firstName"));
//assertNotNull(driver.findElement(By.name("firstName")));
//assertNotNull(driver.findElement(By.xpath("//input[@name='firstName']")));
//driver.findElement(By.cssSelector("input[name='firstName']")).sendKeys("Thomas");
//driver.findElement(By.name("firstName")).sendKeys("Thomas");
//driver.findElement(By.xpath("//input[@name='firstName']")).sendKeys("Thomas");
//page.locator("[name='firstName']").type("Thomas");
//driver.findElement(By.cssSelector("input[name='firstName']")).sendKeys("Thomas");
//driver.locator("[name='firstName']").type("Thomas");

Error that I get is:

Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"*[name='firstName']"} (Session info: chrome=103.0.5060.134)

Does anyone know what I need to do differently to be able to get the webElement?

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • These are `` fields with `name` attributes. `By.NAME` is exactly the right way to find them. – Tim Roberts Jul 28 '22 at 21:36
  • Element is in shaddowRoot, which you can access using something like `public WebElement expandRootElement(WebElement element) { WebElement ele = (WebElement) ((JavascriptExecutor)driver) .executeScript("return arguments[0].shadowRoot", element); return ele; }` – Barry the Platipus Jul 28 '22 at 21:55

1 Answers1

0

The First Name field within the website https://whitelabel.sandbox.array.io/signup?platform=v3 is within a #shadow-root (open)

shadowRootOpen


ShadowRoot in

As per the test implementation in ShadowRoot.java:

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);
  }
}

@titusfortner explains the same in their comment as:

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 a ShadowRoot instance returned from the JS in Selenium 4.1.

And I stand corrected, you need to cast to SearchContext interface.


Solution

To send a character sequence within the First Name you can use the following Locator Strategy:

  • Code Block:

    driver.get("https://whitelabel.sandbox.array.io/signup?platform=v3");
    WebElement element = new WebDriverWait(driver, Duration.ofSeconds(10), Duration.ofSeconds(10)).until(ExpectedConditions.visibilityOfElementLocated(By.tagName("array-account-enroll")));
    SearchContext context = element.getShadowRoot();
    WebElement firstName = context.findElement(By.cssSelector("input[name='firstName'][placeholder='Enter first name']"));
    firstName.sendKeys("Supramanian");
    
  • Browser snapshot:

firstName

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352