1

I have a simple HTML webpage that has text field (no IFrames that I can see) nested inside some divs and a </form>. I'm sure I am using the correct ID but when running the code in IntelliJ it keeps failing. This is the html of the element. This is the exception I get:

exception

org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//*[@id="loginLastName"]"}

And the HTML of the element (text field) I am trying to locate via selenium:

HTML:

<input type="text" maxlength="32" minlength="2" required="" id="loginLastName" class="grv-input " aria-describedby="loginLastNameAria" pattern="(([ \-.']*)?[A-Za-z]+([ \-.']*)?)*">

And in the java code, my browser is correctly loading to dummy sites like http://google.com but failing to grab the elementId off my site in question. I tried with ID and with XPATH (which I got from chrome browser):

Java

// get by ID
driver.findElement(By.id("loginLastName")).sendKeys("This is a test");

// get by XPATH
driver.findElement(By.xpath("//*[@id=\"loginLastName\"]")).sendKeys("dsdfdsfdsdsdsfdsgsdfgsdfdsg");

I also tried adding a delay to make sure the component had time to load, but nothing changes

WebDriverWait wait = new WebDriverWait(driver, 100);
element = wait.until(ExpectedConditions.elementToBeClickable(By.id("loginLastName")));

Does it matter this is nested in within two <divs> and a <form>? Do I have to iterate through those elements, to get down to this one or something? (seems overly complicated, though I haven't worked that much with selenium).

Let me know!

ennth
  • 1,698
  • 5
  • 31
  • 63
  • 1
    Can you share the full HTML of the page, or a link to it? The nested divs and form should not matter. – C. Peck May 28 '21 at 23:21
  • @C.Peck it was a variation of this page: https://www.capitalone.com/cars/login/ However, the one I Just linked you works. I'm wondering if it has to do with the way the HTML is defined for the webpage I posted about (legacy version). – ennth May 29 '21 at 00:29
  • Even when I copy the "Full xpath" from google chrome and use it in the Java code to find by xpath, it still doesn't work: org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"/html/body/div/div/div/div/div/div[2]/div/refi-common-login-form//form/refi-common-last-name//div/input"} (Session info: chrome=91.0.4472.77) – ennth May 29 '21 at 00:38
  • That is what comes out from the full xpath? There should not be the double slashes `//` in a full xpath. Anyway, without actually seeing the whole HTML of the page you are actually using, this will probably be impossible to diagnose. – C. Peck May 29 '21 at 02:22
  • There is no id `loginLastName` on the page you posted in the comment – vitaliis May 29 '21 at 02:45
  • Try css selector `#loginLastName` on the page you are looking at. If it works, I will post it as an answer. – vitaliis May 29 '21 at 02:55
  • @vitaliis the page I listed when an official page; not the one I'm using. I 'm using a similar page but its a development page. I need to post the actual HTML it looks like – ennth May 29 '21 at 03:33
  • @C.Peck sorry no, I copied that from my Java code, and as you know, slashes must be escaped in Java so that's why you saw the double slash there – ennth May 29 '21 at 03:35
  • @C.Peck this is the page https://autorefi.capitalone.com/login/ – ennth May 30 '21 at 18:13
  • @ennth upon seeing this page, I found the issue -- see my posted answer. – C. Peck May 30 '21 at 18:27

2 Answers2

3

OK, upon seeing your page I believe I know what the issue is. The "Last Name" field you are trying to identify resides within two nested shadow-root elements. Selenium won't look in the shadow root unless you identify it and tell it to look in there. Try using code like this:

JavascriptExecutor js;
WebElement shadowRootElement = js.executeScript('''return document.querySelector("refi-common-login-form").shadowRoot''');

WebElement shadowRootChild = js.executeScript('''return arguments[0].querySelector("refi-common-last-name").shadowRoot''', shadowRootElement);

shadowRootChild.findElement(By.id("loginLastName")).sendKeys("This is a test");
C. Peck
  • 3,641
  • 3
  • 19
  • 36
  • I tried this but couldn't get to work. I also tried something incredibly basic, like trying to simply get the by tag name and EVEN THAT FAILED (and its outside the shadow element) , i.e. WebElement root1 = driver.findElement(By.tagName("refi-common-login-form")); ...so now its looking to me like I can't even grab ANY elements off this using the selenium locator...whats going on here?? – ennth Jun 05 '21 at 04:27
  • When you say you couldn't get it to work, what exactly went wrong? Do you get some error? – C. Peck Jun 05 '21 at 04:28
  • I tried grabbing it (the normal DOM element that is the "host" of the first shadow element) by tagName (should be easiest option) , also xpath, and cssselector; neither worked. The exception message is: org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"refi\-common\-login\-form"} – ennth Jun 05 '21 at 04:36
  • Don't Identify it with the normal selenium functions; you tried using `WebElement shadowRootElement = js.executeScript('''return document.querySelector("refi-common-login-form").shadowRoot''');`? – C. Peck Jun 05 '21 at 04:43
  • I get the exception: org.openqa.selenium.JavascriptException: javascript error: Cannot read property 'shadowRoot' of null but I have to remote your triple quotations because that threw errors with Java compiler (IntelliJ) and did it like below: WebElement shadowRootElement = (WebElement) js.executeScript("return document.querySelector(\"refi-common-login-form\").shadowRoot"); – ennth Jun 05 '21 at 04:48
  • if `document.querySelector(\"refi-common-login-form\")` is null then maybe the page is not loaded. Try adding, say, a 5 second wait before you execute that javascript? – C. Peck Jun 05 '21 at 04:50
  • K ill try now appreciate your help thus far. – ennth Jun 05 '21 at 04:54
  • Thanks bro, you were spot on. The page was loading too fast, 5seconds wait seems to be optimal, as 4 causes it to fail on element exception. Thanks for the help. Hard-coding the wait time feels a bit ghetto though and not very reliable (i.e. what if page takes longer than 5sec to load on someone else computer? should there be a buffer or is there a better way to do it then hard-coding wait time?) Anyway, I'll give you vote best answer on both questions you helped me with. – ennth Jun 05 '21 at 05:11
  • "*Hard-coding the wait time feels a bit ghetto though and not very reliable*" Yes, very good observation. that was just to check if timing was the issue. You should be able to implement a dynamic wait, using `webDriverWait` to wait exactly as long as is needed for the `refi-common-login-form` element. If you have issues trying to do so, ask another question and I/another community member can likely help. – C. Peck Jun 05 '21 at 05:16
  • Thanks! I'll investigate! Thanks for all your help again @C.Peck! – ennth Jun 06 '21 at 02:34
0

Can you give a try with the below Xpaths

#Get Xpath with combination
//input[@type='text' and @id='loginLastName']

#Xpath assuming there are multiple elements (DOM  mentioning 1 of 2 elements)
(//input[@type='text' and @id='loginLastName'])[1]

#Get Xpath with another combination
//input[@type='text' and @aria-describedby='loginLastNameAria']

Addendum

List <WebElement> elementCheck = driver.findElements(By.xpath("<xpath of element>"))

if (elementCheck.size() == 0){

//Element not present when entered to the page
//Do something

}else {

//Do something

}
Adarsh Kumar GM
  • 164
  • 1
  • 4
  • 17
  • This is the page I'm trying to select the element on @Adarsh Kumar GM https://autorefi.capitalone.com/login/ – ennth May 30 '21 at 18:13
  • Hi ennth, I got your problem. The underlying element is under a shadow root and hence you are unable to interact with it. Please have a look at the link- https://stackoverflow.com/questions/56380091/how-to-interact-with-the-elements-within-shadow-root-open-while-clearing-brow This will answer you query on accessing it. There is another way instead of writing the JS executor, which you may find it here: https://stackoverflow.com/questions/55761810/how-to-automate-shadow-dom-elements-using-selenium (Check the answer by Garima) – Adarsh Kumar GM May 31 '21 at 09:11