How to Get Fewer False Positives Using Wrappers for Selenium Calls

Many times we believe that we are completing some actions on a webpage, when in reality nothing has happened on the page and we simply didn’t notice it. We believe that we’ve clicked a button, but in reality the button is not clickable. We believe that some text has been entered into an input field, when that field doesn’t actually allow all of the characters that we have sent to it.

To ensure that these events don’t happen, we can easily create wrappers around the Selenium cells, which will create a better interaction with the DOM.

One of the best features in Selenium is Expected Conditions, which, when used with WebDriverWait, can create explicit waits that wait for different states of an element.

Below is an outline of how to create some wrappers over our most used Selenium calls using Expected Conditions. For future calls, we will be using the following imports and variables. These examples are given in Python, but similar calls are available in other programming languages as well.

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

IMPLICIT_WAIT = 10
selector = (By.ID, 'element_id')
text = 'some text'

Below is a simple example of how WebDriverWait and Expected Conditions work:

wait = WebDriverWait(driver, IMPLICIT_WAIT)
element = wait.until(
    EC.visibility_of_element_located(
selector
)

WebDriverWait continually calls Expected Conditions every 500 milliseconds to check that the value is “true” until the condition is met or the time allotted has passed. If the condition is met in the IMPLICIT_WAIT time that has been given, then the found element is return. If not, the TimeoutException is raised.

Now it’s time to use this information in our tests.

The first example is our own click wrapper, which waits for the element to be clickable before clicking on it.

def click(selector):
    element = WebDriverWait(driver, IMPLICIT_WAIT).until(
        EC.element_to_be_clickable(
            selector
        )
    )
    element.click()

The EC.element_to_be_clickable() method returns the element if the element is clickable. If the element is unable to be located, or the element is not enabled in the given IMPLICIT_WAIT, then a TimeoutException will be raised. This way, we’re sure that the button or link we’re trying to click is actually there and clickable, instead of an empty space on the page.

Another commonly used example is the send_keys method. When using Selenium, a good method is finding the element, clicking on it, and then sending the text to it. Though this is good, we can improve upon it by going a bit further.

def enter_text(selector, text):
    element = WebDriverWait(driver, IMPLICIT_WAIT).until(
        EC.visibility_of_element_located(selector)
    )
    element.click()
    element.clear()
    element.send_keys(text)
    WebDriverWait(driver, IMPLICIT_WAIT).until(
        EC.text_to_be_present_in_element(selector, text)
    )

By doing this, we are initially ensuring that the element we’re interacting with is available. After this, we follow the usual steps of clicking the element, clearing the text from it so we know exactly what text we’re entering into that input field, entering the actual text we need, and finally checking that the entered text is present in our input field.

However, if we do not want to go through these steps all of the time, we can easily add flags to our method and remove some steps from the process.

def enter_text(selector, text, clear=True, verify=False):
    element = WebDriverWait(driver, IMPLICIT_WAIT).until(
        EC.visibility_of_element_located(selector)
    )
    element.click()
    if clear:
        element.clear()
    element.send_keys(text)
    if verify:
        WebDriverWait(driver, IMPLICIT_WAIT).until(
            EC.text_to_be_present_in_element(selector, text)
        )

Below is the final example used for handling alerts.

def accept_alert(accept=True):
    alert = WebDriverWait(
        driver, IMPLICIT_WAIT).until(
        EC.alert_is_present()
    )
    if accept:
        alert.accept()
    else:
        alert.dismiss()

Once we input this, we then wait for the alert to be present and then either accept or dismiss it. Just like before, if the webdriver doesn’t find the alert in the IMPLICIT_WAIT time that has been given, then a TimeoutException will be raised.

These wrappers are good practice when using Selenium and can be used for almost all interactions with the DOM. With them, you can reduce the number of false positives generated and create far better waits than when using time-based wrappers.

Additional information on this can be found here.

Cosmin Traistaru

Cosmin Traistaru

Quality Assurance Engineer

Cosmin Traistaru has been working as a Quality Assurance Engineer at the 3Pillar Global Timisoara location for over a year. He has experience with automated testing of web applications using Selenium and Python, as well as with designing test automation frameworks from scratch.

Leave a Reply

Related Posts

The Art of Building Rapid (and Valuable) Proofs of Concept Clients and stakeholders want results. They want assurances that their investment is well spent and they're building the right product. The software d...
Are You Doing Stuff or Creating Value? You can put a bunch of stickies on the wall, create tons of JIRA tickets, and commit lots of code, but are you creating value? Is the work your produc...
Costovation – Giving Your Customers Exactly What They ... On this episode of The Innovation Engine podcast, we delve into “cost-ovation,” or innovation that gives your customers exactly what they want – and n...
AI & Machine Learning Will See You Now, and Other Takea... A 3Pillar team and I spent a few days in Santa Clara recently for the 12th annual Health 2.0 Conference. As usual, we spent some time after the confer...
DevSecOps – The Latest Trends in Application Security ... I spent a very rewarding couple of days at DevSecCon in Boston recently. The conference focused on DevSecOps, which is a catch-all phrase for addressi...