1

Courtesy of this answer I've got this bit of Selenium working:

import contextlib
from selenium import webdriver

with contextlib.closing(webdriver.Chrome()) as driver:
    driver.get("http://www.bing.com/images")
    driver.find_element_by_id("sbi_t").click()
    element = driver.find_element_by_id("sbi_file_upload")
    element.send_keys("//Loch Ness Monster.jpg")

However, when I switch from webdriver.Chrome() to webdriver.Firefox(), I start getting selenium.common.exceptions.ElementNotVisibleException: Message: Element is not currently visible and so may not be interacted with. My guess is that the error is related to the magic that Selenium performs to work with operating system file upload selector dialogs. I would think that's probably also why my attempts to wait until the element becomes visible aren't working: the "magic" does not involve the element ever becoming visible. Here's what I tried:

# https://stackoverflow.com/a/15142611/2829764, found via https://stackoverflow.com/q/6101461/2829764
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
...
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.ID, "sbi_file_upload")))

I'm using Firefox 36.0.1, Selenium 2.45.0, and Python 2.7.9. Incidentally, Selenium had stopped working with Firefox when I updated Firefox to 36.0.1 but I updated my Selenium today and the particular problem I was having went away.

Community
  • 1
  • 1
kuzzooroo
  • 6,788
  • 11
  • 46
  • 84

4 Answers4

2

The element you are sending keys to has an opacity value set to 0:

<input id="sbi_file_upload" name="imageBinary" type="file" accept="image/*" style="opacity: 0;">

And Firefox (correctly) thinks the element is invisible:

>>> from selenium import webdriver
>>> driver = webdriver.Firefox()
>>> driver.get("http://www.bing.com/images")
>>> driver.find_element_by_id("sbi_t").click()
>>> element = driver.find_element_by_id("sbi_file_upload")
>>> element.is_displayed()
False

Here are the relevant issues that actually are the reason for the behavior we see:


The solution here would be to make the input visible so that we can send the keys to it. I've found a rather weird way to make the input visible - it involves sending an empty file value first, going back and making the input visible through execute_script(). Hope, you'll make it work without an extra back() step:

>>> driver = webdriver.Firefox()
>>> driver.get('http://www.bing.com/images')
>>> driver.maximize_window()
>>> 
>>> driver.find_element_by_id("sbi_t").click()
>>> 
>>> button = driver.find_element_by_id('sbi_gh')
>>> driver.execute_script('arguments[0].style.display = "block";', button)
>>> button.click()  # submitting the form, empty file
>>> 
>>> driver.back()
>>> driver.find_element_by_id("sbi_t").click()
>>> 
>>> file_input = driver.find_element_by_id('sbi_file_upload')
>>> file_input.is_displayed()
False
>>> 
>>> driver.execute_script('arguments[0].style = ""; arguments[0].style.display = "block"; arguments[0].style.visibility = "visible";', file_input)
>>> 
>>> file_input.is_displayed()
True

And now you can send keys to file input - tested, works for me.

alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • @kuzzooroo could you also check with selenium 2.44 and firefox 34.0.5? – alecxe Mar 08 '15 at 03:19
  • @kuzzooroo we should have figured that before - this is a security feature - we cannot set the value of a file input like this, see http://stackoverflow.com/questions/1696877/how-to-set-a-value-to-a-file-input-in-html. I guess our only option right now is to make the input visible so that we can send keys to it via `send_keys()`.. – alecxe Mar 08 '15 at 03:25
  • @kuzzooroo or, yes, try with downgrading selenium and firefox as noted in previous comments. I don't like this option, but we would have at least an option if it works. – alecxe Mar 08 '15 at 03:26
  • @kuzzooroo sorry, this somehow worked for me once :) There was probably smth else I did manually in the browser, investigating.. – alecxe Mar 08 '15 at 03:58
  • @kuzzooroo please see the update - this is working for me, hope it would for you also. And hope that you'll find a way to simplify the approach. But, at least, we have a solution here. – alecxe Mar 08 '15 at 04:55
  • @alexce, I found that I had to make a few tweaks to get the code working consistently on my machine. For now I've pasted the result in as an answer below. – kuzzooroo Mar 08 '15 at 05:44
  • @kuzzooroo great, thanks for sharing! It was an interesting challenge – alecxe Mar 08 '15 at 05:48
2

Lightly modified version of @alexce's answer. It's the only thing I've found that works consistently on my machine.

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

driver = webdriver.Firefox()
driver.get('http://www.bing.com/images')

WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.ID, "sbi_t")))
driver.find_element_by_id("sbi_t").click()

try:
    WebDriverWait(driver, 1).until(EC.visibility_of_element_located((By.ID, "sbi_file_upload")))
    raise Exception("This never seems to happen")
except selenium.common.exceptions.TimeoutException:
    pass

button = driver.find_element_by_id('sbi_gh')
driver.execute_script('arguments[0].style.display = "block";', button)
button.click()  # submitting the form, empty file
driver.back()

WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.ID, "sbi_t")))
driver.find_element_by_id("sbi_t").click()
file_input = driver.find_element_by_id('sbi_file_upload')
driver.execute_script('arguments[0].style = ""; arguments[0].style.display = "block"; arguments[0].style.visibility = "visible";', file_input)
file_input.send_keys("//Loch Ness Monster.jpg")
kuzzooroo
  • 6,788
  • 11
  • 46
  • 84
2

The solution 'make the element visible in firefox ' was great for me

driver.execute_script('arguments[0].style = ""; 
arguments[0].style.display = "block"; 
arguments[0].style.visibility = "visible";', file_input)
gil
  • 21
  • 2
0

Try This , If is_displayed() method gives an exception

from selenium import  webdriver

def is_Displayed(class_name):
    ele=driver.execute_script("return document.getElementsByClassName('"+class_name+"')[0].style.visibility = 'visible';")
    if ele=="visible":
        return True
    else:
        return False

def test_check_element():
    global driver
    driver=webdriver.Safari()//e.g Firefox() , Chrome()
    driver.maximize_window()
    driver.implicitly_wait(30)
    driver.get("url")
    submitBtn=driver.find_element_by_xpath("//button[@title='Submit']").get_attribute("class")


    if is_Displayed(submitBtn)== True:
        print "Displayed "
    else:
        print "Not Displayed"
Naveen Kumar R B
  • 6,248
  • 5
  • 32
  • 65