0

I'm trying to make a Selenium test script that checks if a bootstrap validation popover appears when submitting a form containing a bad value.

My script below returns this error:

org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"#amount"}

Relevant code:

WebDriver driver = new ChromeDriver()
WebElement field = driver.findElement(By.id("amount"));  //errors here every execution
Boolean is_valid = (Boolean)WebUI.executeScript("return arguments[0].checkValidity();", field);

if (!is_valid) {
     //intentionally fail test
}

When I inspect the form field, I see the id equals amount, so why am I unable to find this element in Selenium?

enter image description here

Here's my full script:

WebUI.openBrowser('')

WebUI.navigateToUrl('Foo')

WebUI.setText(findTestObject('Object Repository/Page_bar/input_concat(Recipient, , s email address)_email'), 'fakepersonaluser1@example.com')

WebUI.setText(findTestObject('Object Repository/Page_bar/input_Amount (USD)_amount'), '10001')

WebUI.click(findTestObject('Object Repository/Page_bar/button_Send Payment'))

 
WebDriver driver = new ChromeDriver() WebElement field =
driver.findElement(By.id("amount")); Boolean is_valid =
(Boolean)WebUI.executeScript("return arguments[0].checkValidity();", field);

if (!is_valid) { //intentionally fail test }

WebUI.closeBrowser()

Full HTML:

<body cz-shortcut-listen="true">
    <div id="__nuxt"><!----><div id="__layout"><div data-v-f1473ce4=""><header data-v-7ea66436="" data-v-f1473ce4="" class="sr-header"><div data-v-7ea66436="" class="custom-container"><div data-v-7ea66436="" class="header-wrap"><div data-v-7ea66436="" class="row"><div data-v-7ea66436="" class="col-6"><div data-v-7ea66436="" class="header-left d-flex align-items-center"><span data-v-7ea66436="" class="d-block d-md-none mobile-menu-trigger"><i data-v-7ea66436="" class="fa-solid fa-bars"></i></span> <a data-v-7ea66436="" href="/" class="nuxt-link-active"><img data-v-7ea66436="" src="/images/logo-icon.png" alt="" class="sr-logo"></a> <div data-v-7ea66436="" class="user-portal d-none d-md-block"><ul data-v-7ea66436="" class="sr-nav nav"><li data-v-7ea66436=""><a data-v-7ea66436="" href="/" class="active nuxt-link-active">Dashboard</a></li></ul></div></div></div> <div data-v-7ea66436="" class="col-6"><div data-v-7ea66436="" class="sr-user-profile position-relative d-flex justify-content-end align-items-center h-100"><span data-v-7ea66436="" class="position-relative notification-icon"><!----> <img data-v-7ea66436="" src="/images/bxs-bell.svg" alt=""></span> <ul data-v-7ea66436="" class="snapr-notification"><li data-v-7ea66436="" class="d-flex align-items-center justify-content-between"><p data-v-7ea66436="">You have no unseen notifications</p></li></ul> <div data-v-7ea66436="" class="sr-profile clearfix"><img data-v-7ea66436="" src="https://storage.googleapis.com/snapr-dev.appspot.com/images/aXmr0zJOqqhOTBpPenxgerP3CNH3.jfif" alt="" class="avatar"> <a data-v-7ea66436="" href="/" class="d-none d-md-inline-block nuxt-link-active">Mark</a> <ul data-v-7ea66436="" class="sr__profile-links"><li data-v-7ea66436=""><a data-v-7ea66436="" href="/profile" class="">Settings</a></li> <li data-v-7ea66436=""><a data-v-7ea66436="" href="javascript:void(0)">Logout</a></li></ul></div></div></div></div></div></div></header> <main data-v-f1473ce4="" class="sr__main-body"><div data-v-f1473ce4="" class="custom-container"><h2 data-v-f1473ce4="" class="text-white mb-1">Welcome, Test Biz</h2> <p data-v-f1473ce4="" class="mb-4 mb-md-0">SnapRefund is fast, simple, and secure</p> <div data-v-f1473ce4="" class="body-wrapper clearfix"><div data-v-f00dedfc="" data-v-f1473ce4="" class="d-flex flex-wrap sr__profile-tabs mb-xl-5 justify-content-center"><a data-v-f00dedfc="" href="javascript:void(0)" class="closePosition closeBtn"><i data-v-f00dedfc="" class="fa fa-close fa-2x" aria-hidden="true"></i></a> <a data-v-f00dedfc="" href="/send-payment" aria-current="page" class="sr__tab nuxt-link-exact-active nuxt-link-active"><div data-v-f00dedfc="" class="d-flex align-items-center"><span data-v-f00dedfc="" class="icon-box"><img data-v-f00dedfc="" src="/images/ionic-ios-send.svg" alt=""></span> <span data-v-f00dedfc="" class="sr__tab-title">Send <br data-v-f00dedfc=""> Payment</span></div></a> <a data-v-f00dedfc="" href="/pending-payment" class="sr__tab"><div data-v-f00dedfc="" class="d-flex align-items-center"><span data-v-f00dedfc="" class="icon-box"><img data-v-f00dedfc="" src="/images/open-reload.svg" alt=""></span> <span data-v-f00dedfc="" class="sr__tab-title">Pending <br data-v-f00dedfc="">Payments</span></div></a> <a data-v-f00dedfc="" href="/transactions" class="sr__tab"><div data-v-f00dedfc="" class="d-flex align-items-center"><span data-v-f00dedfc="" class="icon-box"><img data-v-f00dedfc="" src="/images/ionic-ios-paper.svg" alt=""></span> <span data-v-f00dedfc="" class="sr__tab-title">Transaction <br data-v-f00dedfc="">History</span></div></a> <a data-v-f00dedfc="" href="/bank-card" class="sr__tab"><div data-v-f00dedfc="" class="d-flex align-items-center"><span data-v-f00dedfc="" class="icon-box"><img data-v-f00dedfc="" src="/images/ionic-ios-card.svg" alt=""></span> <span data-v-f00dedfc="" class="sr__tab-title">Banks &amp;<br data-v-f00dedfc="">Cards</span></div></a> <a data-v-f00dedfc="" href="/my-wallet" class="sr__tab"><div data-v-f00dedfc="" class="d-flex align-items-center"><span data-v-f00dedfc="" class="icon-box"><img data-v-f00dedfc="" src="/images/ionic-ios-wallet.svg" alt=""></span> <span data-v-f00dedfc="" class="sr__tab-title">Wallet</span></div></a> <a data-v-f00dedfc="" href="/my-preference" class="sr__tab"><div data-v-f00dedfc="" class="d-flex align-items-center"><span data-v-f00dedfc="" class="icon-box"><img data-v-f00dedfc="" src="/images/ionic-ios-settings.svg" alt=""></span> <span data-v-f00dedfc="" class="sr__tab-title">Preferences</span></div></a></div> <div data-v-f1473ce4="" class="body-content"><div data-v-f1473ce4="" class="row"><div data-v-f896e768="" data-v-f1473ce4="" class="col-xl-6 offset-xl-3 px-xl-5"><div data-v-f896e768="" class="sr__send-payment-card sr__card"><h2 data-v-f896e768="" class="text-white text-center">Send a Payment</h2> <p data-v-f896e768="" class="text-center mb-5">Fast. Simple. Secure.</p> <form data-v-f896e768=""><div data-v-f896e768="" class="mb-4"><label data-v-f896e768="" for="email" class="d-block">Recipient's email address</label> <input data-v-f896e768="" type="text" id="email" placeholder="recipient@example.com" name="email" required="required" class="d-block w-100"></div> <div data-v-f896e768="" class="mb-5"><label data-v-f896e768="" for="amount" class="d-block">Amount (USD)</label> <div data-v-f896e768="" class="position-relative adjust-dollar-sign"><input data-v-f896e768="" type="number" id="amount" placeholder="0.00" step=".01" min="0" max="10000" name="amount" required="required" class="d-block w-100"> <i data-v-f896e768="" class="fa-solid fa-dollar-sign"></i></div></div> <div data-v-f896e768="" class="d-flex justify-content-center"><button data-v-f896e768="" type="submit" class="sr__button me-3">Send Payment</button></div></form></div></div></div></div></div></div></main></div></div></div><script>window.__NUXT__=function(t){return{staticAssetsBase:"/_nuxt/static/1645950364",layout:"default",error:t,state:t,serverRendered:!1,routePath:"/",config:{_app:{basePath:"/",assetsPath:"/_nuxt/",cdnURL:t}}}}(null)</script><script src="/_nuxt/aee8d4c.js" defer=""></script><script src="/_nuxt/31db832.js" defer=""></script><script src="/_nuxt/b069f1c.js" defer=""></script><script src="/_nuxt/b379d09.js" defer=""></script>
  

<div id="ryq5aiihF" role="status" aria-live="polite" aria-atomic="false" class="toasted-container top-right fit-to-screen"></div></body>

Related Question: How to get the text from the HTML5 input field error message in Selenium?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Cody
  • 1,801
  • 3
  • 28
  • 53
  • What website url is this? I am assuming it looks for the element prior to it popping up. – Arundeep Chohan Feb 27 '22 at 04:16
  • it is created dynamically and added to dom content later. therefore you have to request popover with timeout or equivalent something – gokhancevik Feb 27 '22 at 08:36
  • Does this answer your question? [How to handle HTML constraint validation pop-up using Selenium?](https://stackoverflow.com/questions/55223934/how-to-handle-html-constraint-validation-pop-up-using-selenium) – TylerH Nov 23 '22 at 14:30

2 Answers2

1

The popover is the HTML5 Constraint validation message which is the outcome of Constraint API's element.setCustomValidity() method.

To retrieve the text Value must be less than or equal to 10000. you need to induce WebDriverWait for the elementToBeClickable() and you can use either of the locator strategies:

  • Using cssSelector:

    WebElement amount = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("input#amount[name='amount']")));
    System.out.println(amount.getAttribute("validationMessage"));
    
  • Using xpath:

    WebElement amount = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//input[@id='amount' and @name='amount']")));
    System.out.println(amount.getAttribute("validationMessage"));
    

As it is a <label> element as an alternative you can also try the following locator strategies:

  • Using cssSelector:

    WebElement amount = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("label[for='amount']")));
    System.out.println(amount.getAttribute("validationMessage"));
    
  • Using xpath:

    WebElement amount = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//label[@for='amount']")));
    System.out.println(amount.getAttribute("validationMessage"));
    

Instead you can also try for the visibilityOfElementLocated() as follows:

  • Using cssSelector:

    WebElement amount = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("label[for='amount']")));
    System.out.println(amount.getAttribute("validationMessage"));
    
  • Using xpath:

    WebElement amount = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//label[@for='amount']")));
    System.out.println(amount.getAttribute("validationMessage"));
    

References

You can find a couple of relevant detailed discussion in:

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • Hm this is a good approach it seems, but the 20s timeout is being hit and i'm seeing the error `Expected condition failed: waiting for element to be clickable: By.cssSelector: input#amount[name='amount'] (tried for 20 second(s) with 500 milliseconds interval)`. Should we be waiting for the amount field to be clickable rather than wait for the popover? I need to check if the validation message is displayed at all but this code would print the value of the message. What would be the correct way to validate whether or not the message is present? `WebUI.verifyTextPresent(amount, false)` ? – Cody Feb 27 '22 at 19:32
  • How about the _xpath_? Are you able to send any text within the _Amount_ field? – undetected Selenium Feb 27 '22 at 19:35
  • Yes, I can send text to the amount field fine with my script in Katalon using `WebUI.setText(findTestObject('Object Repository/Page_SnapRefund/input_Amount (USD)_amount'), '10001')`. The problem i'm having is I can't programmattically verify the popover is displaying after the text has been entered. I tried with Xpath instead of CSS and got a similar error that the element can't be found: `no such element: Unable to locate element: {"method":"xpath","selector":"//input[@id='amount' and @name='amount']"}` – Cody Feb 27 '22 at 21:10
  • Did you apply the wait? – undetected Selenium Feb 27 '22 at 21:12
  • Yes I did. Why should we wait for the element to be clickable? When my script runs the element is clickable (the amount field) and we enter the text fine. The bootstrap popover is then displayed and I am unable to detect the text. The normal way of doing this in katalon would be `WebUI.verifytextpresent(popoverMessage), but that doesn't seem to have visibility into the popover. Instead i've tried the solutions on both answers here but I get `element not found` errors – Cody Feb 27 '22 at 21:18
  • Can't comment about Katalon specific behavior but as per the initial version of your question using [Selenium](https://stackoverflow.com/a/54482491/7429447) this is the ideal and proven approach. – undetected Selenium Feb 27 '22 at 21:21
  • Got it, so why is the element not found? – Cody Feb 27 '22 at 21:37
  • Can't comment further without seeing the HTML DOM. – undetected Selenium Feb 27 '22 at 21:38
  • I've added the HTML to my question above – Cody Feb 27 '22 at 21:49
  • 1
    Checkout the answer update and let me know the status. – undetected Selenium Feb 27 '22 at 22:01
  • Getting a timeout error instead of element not found with both the new css and xpath approaches: `Expected condition failed: waiting for element to be clickable: By.cssSelector: label[for='amount'] (tried for 20 second(s) with 500 milliseconds interval)` – Cody Feb 27 '22 at 22:21
  • Checkout the answer update and let me know the status. – undetected Selenium Feb 27 '22 at 22:42
  • Similar to the previous error: `Expected condition failed: waiting for visibility of element located by By.cssSelector: label[for='amount']` – Cody Feb 27 '22 at 23:19
0

According to the code you presenting in the question you are trying to access a web element before even opening the web page you are trying to work on.
In case you just omitted driver.get(the_page_url) and the code filling and submitting the form the error here may be caused by several causes:

  1. You are missing a delay. You can not locate the pop-up immediately after clicking the submit button, it takes some short time for pop-up to appear. The preferred approach here is to use Expected Conditions explicit waits, something like this:
WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement field = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("amount")));
  1. The elements you are trying to access are inside an iframe.
    In this case you will have to switch into that iframe first in order to access elements inside it, as following:
driver.switchTo().frame(driver.findElement(By.id(the_iframe_id)));

and then continue with

WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement field = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("amount")));

To give you better answer we have to see the page you are working on, to see all your actual code and to debug what actually happens there.

Prophet
  • 32,350
  • 22
  • 54
  • 79
  • I did indeed omit the part of the script where I open the browser and fill a value into the `amount` field. I'm just using a bootstrap form as the screenshot shows, I don't think that involves an iFrame (i could be wrong). The field (amount) is an `` that is likely shadowed by the parent `
    `, but since it doesn't have an id how can I switch into it? I tried using the full xpath for the amount field I pulled from the inspector, but it isnt found`WebUI.mouseOver(TestObjectHelper.getTestObjectWithXpath("/html/body/div[1]/div/div/header/div/div/div/div[2]/div/div")) `
    – Cody Feb 27 '22 at 18:53
  • In selenium you need to switch into iframes and shadow DOMs only. I'm afraid we need more details here to help you. – Prophet Feb 27 '22 at 20:09
  • Got it. What details should I provide? My entire page html? – Cody Feb 27 '22 at 21:05
  • Preferably the link, if not possible - the entire page HTML if possible and all your code if possible – Prophet Feb 27 '22 at 21:25
  • I can give you the link, but you'll have to go through a sign up process in our sandbox to reach the page in question. Would you prefer that or the whole page html? – Cody Feb 27 '22 at 21:37
  • I really appreciate your trust to me, but now it's almost 24:00 at night here and tomorrow I will be really busy, so I'm not sure I will have a time to help here. I'm sorry – Prophet Feb 27 '22 at 21:47
  • 1
    No worries. I added the html to my question if you're interested later. All good, thank you for your suggestions! – Cody Feb 27 '22 at 21:49