How to handle html5 constraint validation pop-up using Selenium?
The picture says it all. After click on "LOG IN" button, "Please fill out this field." pop-up message appears. It looks like some javascript thing. I want to get text of this pop-up message by using Selenium. Is it even possible ? Here is the html of email input field:
<input autocorrect="none" autocapitalize="none" spellcheck="false" autofocus="autofocus" class="cell small-21 form-text required" data-drupal-selector="edit-name" aria-describedby="edit-name--description" type="text" id="edit-name" name="name" value="" size="60" maxlength="60" required="required" aria-required="true" placeholder="Email or Username">
P.S. When pop-up message appears, then "event" indication in browser dev-tools shown near email field html.
Solution 1:
The popup which you are referring is the outcome of Constraint API's element.setCustomValidity()
method.
Note: HTML5 Constraint validation doesn't remove the need for validation on the server side. Even though far fewer invalid form requests are to be expected, invalid ones can still be sent by non-compliant browsers (for instance, browsers without HTML5 and without JavaScript) or by bad guys trying to trick your web application. Therefore, like with HTML4, you need to also validate input constraints on the server side, in a way that is consistent with what is done on the client side.
Solution
To retrieve the text which results out from the element.setCustomValidity()
method, you can use either of the following Locator Strategies:
-
Using Python, Mozilla and CssSelector:
-
Code Block:
from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By driver = webdriver.Firefox(executable_path=r'C:\Utility\BrowserDrivers\geckodriver.exe') driver.get("https://accounts.us1.advisor.ws/user/login") email_username = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input.cell.small-21.form-text.required#edit-name[name='name']"))) print(email_username.get_attribute("validationMessage"))
-
Console Output:
Please fill out this field.
-
-
Using Java, Chrome and Xpath:
-
Code Block:
import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; public class validationmessage { public static void main(String[] args) { System.setProperty("webdriver.chrome.driver", "C:\\Utility\\BrowserDrivers\\chromedriver.exe"); ChromeOptions options = new ChromeOptions(); options.addArguments("start-maximized"); options.addArguments("disable-infobars"); options.addArguments("--disable-extensions"); WebDriver driver = new ChromeDriver(options); driver.get("https://accounts.us1.advisor.ws/user/login"); WebElement email_username = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//input[@class='cell small-21 form-text required' and @id='edit-name'][@name='name']"))); System.out.println(email_username.getAttribute("validationMessage")); } }
-
Console Output:
Please fill out this field.
-
Solution 2:
Without seeing the html, I cannot tell you with full confidence.
However, it should be extremely easy (edit: famous last words). That is one of two things:
1) The title attribute of the input field. Hovering over something, or (if designed to) putting focus onto an element with a title attribute shows that title text in a box like this. Although the box has certainly been stylized.
2) This is a custom div/other html that is hooked up to an event that involves the "focus" event of that input field.
Both require different ways to get the text. Because they are different, I need to know the html involved. Please open your browser's Developer Tools, and inspect the email field. Then, copy the html around this element, including whatever holds the tool tip text shown above.
Once you paste that html, the answer is going to be simple.
Edit: I am absolutely stumped. I reviewed the html, scoured the event list and javascript files. There is NO reference to the text shown in that tooltip.
Additionally, it renders as a "title" attribute-based tool tip. It is not a div. Yet the title does not simply exist in the DOM for the element. I do not know what magic the developers did for this page to make all of this happen. I am a web developer as well as an automation engineer, and this is beyond me. It may just not be something I've encountered before, or I may just be missing something that would make me feel stupid once I saw it, too.
Because of this, I strongly recommend you ask the developers of this page directly what they did to make this title appear as it does (without existing in the html, and no references in the javascript anywhere).
Edit #2: Here is the last-resort image recognition I mentioned. It uses AForge, which is easy to pull in as a dll. If using Visual Studio, you can grab it as a nuget package.
using AForge.Imaging;
using System.Drawing;
using System.IO;
using OpenQA.Selenium;
public static class AssertImages
{
//97.5% match expected. 100% is too strict, and practicly impossible. The lower the value you provide, the more possibly it is for a false match.
//Never go below 75%. False matches above 75% are generally only possible if the baseline image is very generic, such as a basic shape or colored item.
public const float BASE_EXPECTED_MATCH_PERCENT = 0.975f;
/// <summary>
/// Determines if a provided baseline image exists within a screenshot of the current browser window .
/// </summary>
/// <param name="relativePathToBaseline"> Pass the relative url to the baseline image we are searching for.</param>
/// <param name="matchExpected">Optional parameter that modifies the expected percent match. Use this when a baseline image may be stretched, different colored, or otherwise slightly modified from provided baseline.</param>
/// <returns></returns>
public static bool DoesScreenshotContain(string relativePathToBaseline, float matchExpected = BASE_EXPECTED_MATCH_PERCENT)
{
//Save screenhot as source image in jpeg format. Then, read jpeg as bitmap.
Screenshot ss = ((ITakesScreenshot)BaseTest.Driver).GetScreenshot();
string tempFile = Path.Combine(Path.GetTempPath(), "temp_screenshot.jpg");
ss.SaveAsFile(tempFile, ScreenshotImageFormat.Jpeg);
Bitmap sourceImage = new Bitmap(new MemoryStream(File.ReadAllBytes(tempFile)));
Bitmap template = new Bitmap(Path.Combine(Reporting.BaseDirectory, "Suite", "ImageRecognition", "Baselines", relativePathToBaseline));
//Find baseline in template image.
ExhaustiveTemplateMatching tm = new ExhaustiveTemplateMatching(BASE_EXPECTED_MATCH_PERCENT);
return tm.ProcessImage(sourceImage, template).Length > 0;
}
}
Then, take a picture of the text inside the tooltip to use as a baseline. As mentioned below, I am extremely hesitant to use this as a final solution. The far superior option is finding a way to do it with Selenium or direct javascript, either via someone with a better answer than me, or with help from the developers who made this code. That being said, if you need something that works right now, this should give you some instant gratification until a better solution is identified.
Solution 3:
I have also encountered this type of page previously and i had a discussion with the UI developers at that time. The errors which are displayed on the UI is the native browser support and every browser would by default show this error message if the field is left blank.
This was introduced in HTML5 and if there is an attribute required="required"
in the html structure of the element then the browser will by default show the error message which you are getting. So if you also check your element, required="required"
is present in your element's html as well.
Generally, websites do not use this feature because they use their customised error messages on the page but in your case its being used. Therefore, it is not possible to detect this error message using selenium as the error message is not present on the UI or anywhere in the code. So, either you ask your developers to change the implementation or you need to skip these validations from your test suite.