How to handle HTML constraint validation pop-up using Selenium?
Asked Answered
M

3

3

Screenshot of a form with a "Please fill out this field" dialog validation message appearing below the 'Email or Username' field

After click on the "LOG IN" button, a "Please fill out this field." pop-up message appears.

I want to get the text of this pop-up message by using Selenium. Is it even possible?

Here is the HTML of the 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">

When the pop-up message appears, an "event" indication in the browser DevTools inspector is shown near the email field HTML:

screenshot of HTML inspector view with the 'event' badge appended to the end

Mcminn answered 18/3, 2019 at 14:42 Comment(4)
Hi @Wonderio619, which programming language using for scripting? And what you are trying to do exactly? Why to want to handle that message?Theobald
Hi @Theobald CSE, I'm using Java. And I need to handle that message for automation testing purpose.Mcminn
which application is that? And you inspect the so called pop-up in devtools?Eolanda
Might be, not possible to handle that message because that is not populating from DOM and now way to inspect that. If your scenario is for checking that field is empty or not? then you can validate it by using the placeholder of that field.Theobald
D
3

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.
      
Disbelief answered 19/3, 2019 at 6:54 Comment(0)
C
1

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.

Chamaeleon answered 18/3, 2019 at 14:48 Comment(6)
Asynarok, I edited question with "email field" html and some other details.Mcminn
Thanks, although that only rules out the usage of a title attribute. Do you have the url to this login page, or is it only something on your local host? It will be MUCH easier to debug this if I can see it myself. If it is only local, run this $("div:contains('Please fill out this field')"); assuming you have JQuery to find the element that actually represents the div with the help text.Chamaeleon
I edited my message above. I strongly recommend you ask the developers of this page what they did to make this tooltip appear, as there is no logical way I can see to access the tooltip text via javascript (or Selenium).Chamaeleon
Oh, interesting. Unfortunately, most likely I will not be able to access that type of information, but I will update my question if I can.Mcminn
Asynarok, one more question, instead of getting text from pop-up, can I just somehow check that this pop-up message appears after click on log in button via Selenium ?Mcminn
Good question. Unfortunately, because of the syntactic sugar that is making this appear, I would not know how to even detect that the tooltip appears programmatically. It would definitely be possible using image recognition, for sure. But that should be a last resort. I will put a second edit to the above post for using a simple image recognition system. Use that ONLY if you cannot contact the developers and get information on this AND someone else does not answer this question with a better answer than mine. :)Chamaeleon
P
1

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.

Palfrey answered 19/3, 2019 at 6:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.