How to work around the non-visible element exception when using Selenium for Python

advertisements

I'm using Selenium to click a button on a website. The button is choosing a state. When the drop-down. The elements are not initially visible. You need to click on the "select" button and then a drop down appears.

The select element looks like this.

<select name="state" style="display: none;">
         <option value="0">select</option>
         <option value="1">Alabama</option>
         <option value="2">Alaska</option>
         <option value="3">Arizona</option>
         <option value="4">Arkansas</option>
         <option value="5">California</option>

I've tried it using:

driver.find_element_by_xpath("/html/body/div[1]/div[3]/form/div/div[9]/div[2]/div/div/div[1]").click()
driver.find_element_by_xpath(state_xpath).click()

The first statement clicks the select buttons so that options appear. The second statement chooses the option by clicking on it. This works fine for the first few options but when I need to choose an option that isn't visible it returns the ElementNotVisibleException

When I try to find it using the select class. It again returns ElementNotVisible. This may be because the display is set to none for this element so the code below doesn't work either.

select = Select(driver.find_element_by_name('state'))
select.select_by_value('2')

How do I work around this. Is there any way to scroll down the options so that more of them become visible.


In your case, I guess there are two solutions. Here are my Java methods, hopefully it may be similar in Python.

1) Make your webdriver wait until the element is visible (useful when "select" elements appear in fade-in).

This one may work but I do not recommend it because it's not dynamic:

Thread.sleep(2); // or whatever

Better use:

public void waitUntilElementDisplayed(By by){
    int timeOut = 10; // you can also define this time-out as a global variable as it may be useful in other methods
    boolean isExpectedElementDisplayed = driver.findElement(by).isDisplayed();
    int count= 0;
    while(!isExpectedElementDisplayed && (count< timeOut)) {
        isExpectedElementDisplayed = driver.findElement(by).isDisplayed();
        Thread.sleep(1);
        count++;
    }
}

2) Scroll down

A little bit :

public void tinyScroll() {
    JavascriptExecutor jse = (JavascriptExecutor) driver;
    jse.executeScript("window.scrollTo(0, 100);");
}

The hole page:

public void scrollToBottomOfPage() {
    JavascriptExecutor jse = (JavascriptExecutor) driver;
    jse.executeScript("window.scrollTo(0,Math.max(document.documentElement.scrollHeight,document.body.scrollHeight,document.documentElement.clientHeight));");
}

After that, if you still get the error, check that you xpath matches one and only one element (if not, Selenium will try to interact with the first occurrence, even if it's hidden, and you'll get an error). In your case I think it's fine because your xpath is very long and specific. But be careful, xpath like this are more fragile when devs refactor the front-end. When possible, it's safer to use html ids.