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

4 Reasons Everyone is Wrong About Blockchain: Your Guide to ... You know a technology has officially jumped the shark when iced tea companies decide they want in on the action. In case you missed that one, Long Isl...
3Pillar Recognized as a Leading Experience Designer by Forre... Fairfax-based product development company named to its second Forrester report in 2018 FAIRFAX, VA (June 18) - Today, 3Pillar Global, a global cust...
3 Cloud Optimization Projects That Will Pay for Themselves i... AWS introduced 1,430 new features and tools in 2017, including 497 in the 4th quarter alone. This means that it can be a challenge for even the mos...
The Connection Between Innovation & Story On this episode of The Innovation Engine, we'll be looking at the connection between story and innovation. Among the topics we'll cover are why story ...
Go Native (App) or Go Home, and Other Key Takeaways from App... I just returned from my first WWDC. I feel like I learned more in a week at Apple’s annual developer’s conference than I have in years of actually dev...