15

The goal of my test is to assert that a popup does not appear after certain actions. Previously to test if the popup exist, I have used exception handling.

try:

    self.driver.find_element_by_id("fancybox-close").click()

except Exception ('ElementNotVisibleException'):

    print "No popup"

This works fine for the test: to assert if the popup exists.

But as soon as I change the goal to: assert if the popup does not exist, the exception handling solution becomes very expensive (exception handling takes a lot of time in Python) and a test that would execute in 3 seconds now takes up to a minute.

Is there a way around this? Is there a quicker way to check if an element does not exist using the webdriver Python binding?

5
  • How many times would you estimate that code fragment is executed over the course of your one-minute test?
    – user246
    Jul 17, 2012 at 14:20
  • It is just executed once, but it just stalls on the "except" part for 90% of the 1 minute. Jul 17, 2012 at 19:42
  • 1
    That sounds suspicious. On modern hardware, I would expect "slow" exception handling to mean additional microseconds, or perhaps even additional milliseconds, but certainly not 54 seconds.
    – user246
    Jul 17, 2012 at 22:57
  • I should probably use a profiler to get the exact time spent in that try/catch block . But from past test results, the test where no exception was raised ran within 4 - 8 secs while the one where it was raised ran for about a minute or just over. There were no other changes in the code. Jul 17, 2012 at 23:23
  • @user246 furthermore python exceptions are extremely fast. They are implemented in C. An exception is thrown every time when iterating an object is exhausted! Exceptions are slow in C++ and probably Java but certainly not in python!
    – Vorac
    May 23, 2022 at 23:00

9 Answers 9

9

I haven't used the Python bindings, but as far as I know they should be equivalent to the Java ones.

If I were you I would try to find the Python equivalents of findElements() and isDisplayed() that are available in the Java bindings.

For example, I would do something similar to this:

// ...
myElementList = driver.findElements(By.Id("fancybox-close"))
if (myElementList.isEmpty()) {
    // The element doesn't exist. findElements, in plural, returns a list of the matching elements, or an empty list if no one is found
else {
    // We know it exists, now we need to know if it's displayed (visible) or not
    if (myElementList[0].isDisplayed()) {
        // This means the element is visible
    else {
        // ...
    }

}

Hope it helps

11
  • Ignacio, this is a great idea. python bindings have a find_elements() and is_displayed(). I am however having trouble with checking if the list is empty or not. I get an error message saying "built in function id is not JSON serializable. Will have to look in it. But otherwise this is a great idea. Thanks! Jul 17, 2012 at 19:39
  • 1
    isEmpty() is a Java method for lists. In Python, I think you should check the length of the list (len(driver.find_elements(...)) == 0)? I cannot check this for myself right now. Jul 17, 2012 at 19:43
  • In python to check if the list is empty you just have to do if not a : where a =[] is a list. That is what i am doing. if not self.driver.find_elements(By.id("fancybox-close")) : Jul 17, 2012 at 19:53
  • And it doesn't work? Jul 17, 2012 at 19:56
  • 1
    Cool. Now you should look for an equivalent of isDisplayed() (if an element is not displayed it will throw the exception you were using when clicked) for Python as I said in the answer :) Jul 17, 2012 at 20:18
7

The test is slow, not due to slow exception handling, but because driver waits for elements that are are not found. In this case, the driver waits for the pop-up—maybe it will appear.

Try to use self.driver.implicitly_wait(0).

This will tell the driver not to wait if it cannot find some elements.

2

You can potentially speed it up using various ways:

  • Implicit wait
    This is mentioned by tstempko. However, implicit wait has a drawback. This makes the driver to not wait for all UI elements when it is set to '0'. In your case, it is not ideal. There might a time that you really have to wait for a UI element to show up, and then your test will break for no valid reason.

  • Explicit wait
    You can set up an explicit wait just for this call. This allows a more robust way of waiting for the UI element to show up.

  • JavaScript executor
    For me, there are some web elements which are just too 'unreliable' to detect all the time. I will use the JavaScript executor like this:

     String cmd = "$('#header-username').click()";
     ((JavascriptExecutor)driver).executeScript(cmd);
    

The good thing about JavaScriptExcutor is that as long as the JavaScript code is loaded, you can execute it. The browser does not need to wait for the element to be rendered. The downside of this is that it does not mimic the user's behavior. I use this only to get through to the next test area that I am interested in.

On a side note, rather than the try-except method you have, you might want to try to code it this way:

wait = new WebDriverWait(driver, TIMEOUT);
e = wait.until(ExpectedConditions.visibilityOf(oldPasswordField))
e.click()

Unfortunately, my code is in Java. I think there is a similar method in Python equivalent.

2

Here's another example much like the one from Ignacio, but in C#:

    //Displayed
    public static bool IsElementDisplayed(this IWebDriver driver, By element)
    {
        if (driver.FindElements(element).Count > 0)
        {
            if (driver.FindElement(element).Displayed)
                return true;
            else
                return false;
        }
        else
        {
            return false;
        }
    }

    //Enabled
    public static bool IsElementEnabled(this IWebDriver driver, By element)
    {
        if (driver.FindElements(element).Count > 0)
        {
            if (driver.FindElement(element).Enabled)
                return true;
            else
                return false;
        }
        else
        {
            return false;
        }
    }
0
1

In Python, to assert that something is visible, use:

element.is_displayed()

is_displayed() will wait until the element is visible or it will time out.

If you want to assert that an element is not visible, use:

element.is_not_displayed()

If the element is not displayed, it will return True immediately.

0

A safe way I have used over the last few months has been extracting the closest element node and verifying it as an XML

WebElement element = driver.findElement(By.css("some path to a div"));
String documentNode = ((JavascriptExecutor) driver).executeScript("return arguments[0].outerHTML;", element);

That will return the Text. (Here is a sample of what you will get as output.)

"<div><div>some test</div></div> \n \n \n"

Trim it, then I have converted it to a document and safely xpath or parse the nodes manually. That's it. This has been way faster and no chance of stale state. No more waiting indefinitely.

Hope this helps.

0

I know this an old post, but there is something better you can do with Python to test an element does not exist.

from selenium.common.exceptions import NoSuchElementException

with self.assertRaises(NoSuchElementException):
    driver.find_element_by_id(element_id)

If you want to check that you cannot see the element, use(as mentioned above)

self.assertFalse(element.is_displayed())
0

Using webdriver find_element_xxx() will raise exception in my code and take us the waiting time of implicit/explicit webdriver wait.

I will go for DOM element check

webdriver.execute_script("return document.querySelector('your css class')")

p.s.

Also found similar discussion on our famous sister site stackoverflow here


For full check for visibility+existence

    # check NOT visible the :aftermeet and :viewintro
    #                   !                .      .                       !       !offsetWidth to check visible in pure js ref. https://stackoverflow.com/a/20281623/248616
    css='yourcss'; e=wd.execute_script(f"return document.querySelector('{css}').offsetWidth > 0") ; assert not e

    # check NOT exists :viewintro
    css='yourcss'; e=wd.execute_script(f"return document.querySelector('{css}')") ; assert not e
0

I have a better solution which won't waste your precious execution time and will fail/pass immediately.

The below implementation changes the implicit default wait for any element to 0 (which is reversed back once our check is completed).

We then try to perform some operation and check if we get NoSuchElementException and, depending on whether the exception occurs, it sets the flag value. The function at the end asserts the flag 'elmDoesNotExists'.

Enter image description here

In case if anyone is wondering what the @This annotation is , I am using a very cool plugin called manifold.ext.rt.api which allows to extend an existing API with more functionality without going through the traditional route of inheritance.

Enter image description here

For example, as you may notice, I have some user-defined functions directly invoked on the actual Selenium APIs (WebDriver and WebElement), thus making them very intuitive to use and also making tests more readable because of less boilerplate code.

I have explained in detail how to integrate this in your test framework in my LinkedIn article "Java - Metaprogramming - Ability to add new functionality to existing API".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.