45

I have a file field that has opacity: 0 and is overlaping a fake button. Its a common css technic to fake a sort of "Upload button" that displays consistently across different browsers.

Capybara doesn't allows me to call attach_file on that input. The error is Selenium::WebDriver::Error::ElementNotVisibleError: Element is not currently visible and so may not be interacted with.

Anybody knows any way to force capybara to interact with invisible elements?

The answer is still unanswered, but I've found a work around. Nothing intelligent, just make visible the element with a simple script

  page.execute_script %Q{
    $('#photos').css({opacity: 1, transform: 'none'});
  }

I post it for the record.

miguel.camba
  • 1,777
  • 1
  • 14
  • 19
  • It may be hard to do it. Try to start from JS [here](https://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions#Q:_Does_WebDriver_support_file_uploads?). But it may not work in all cases and browsers – Andrei Botalov Mar 25 '13 at 17:56
  • Looks like you are not using capybara-webkit (because of "Selenium::WebDriver::Error" in error message) so I removed capybara-webkit tag from your question – Andrei Botalov Mar 25 '13 at 17:58
  • It may already be answered here: http://stackoverflow.com/a/10805128/914986 – Hengjie May 05 '13 at 09:09
  • The work around works fine! Thanks – bott May 03 '18 at 11:56

7 Answers7

75

You can interact with hidden elements using the visible: false property in Capybara.

If you want to click on hidden element use:

find("#photos", visible: false).click

Don't use click_button('#photo') directly

Kris
  • 19,188
  • 9
  • 91
  • 111
Vijay Chouhan
  • 4,613
  • 5
  • 29
  • 35
  • @mc. On which element you'r clicking, paste the structure here – Vijay Chouhan Sep 22 '15 at 12:55
  • This may only work because the element has opacity: 0 not visibility: hidden (or similar). You can not click on hidden elements directly – bott May 03 '18 at 11:58
  • The answer from @Thomas Walpole (here: https://stackoverflow.com/a/44443849/2809881) is a much more useful and direct answer to the problem of attaching a file to an invisible file input. – Michael Smart Sep 06 '18 at 13:24
  • Also note that `find("#photos", visible: false)` will match **visible** #photos, too. If you want to match invisible elements only, you need `find("#photos", visible: :hidden)` as described by Thomas Walpole here https://stackoverflow.com/questions/53361214/capybara-with-rails-how-to-find-only-invisible-elements/53363238#53363238 – Jeni Nov 19 '18 at 21:30
19

The author of Capybara recommends setting Capybara.ignore_hidden_elements immediately prior to needing to see the invisible element, and resetting it afterwards:

Capybara.ignore_hidden_elements = false
click_button 'my invisible button'
Capybara.ignore_hidden_elements = true
user664833
  • 18,397
  • 19
  • 91
  • 140
  • 4
    When you read it, he only recommends this as a workaround to a particular issue. In general, it's not a good solution because particular tests shouldn't alter a global option like that. See http://makandracards.com/makandra/7617-change-how-capybara-sees-or-ignores-hidden-elements – Arcolye Jun 01 '15 at 01:43
8

In general interacting with non-visible elements should not be possible when using Capybara (you can find them using the visible: false/hidden option in most finders but not actually do anything to them). However, the file input is a special case because of how common it is to hide the element and, due to security restrictions, no other way to actually add a file by interacting with the pages visible elements. Because of this attach_file has a make_visible option which can be used to have Capybara make the element visible, attach the file, and then reset the CSS to the original setting.

attach_file('photos', file_path, make_visible: true)
Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78
1

Miquel, thanks for workaraund.

I have similar issue for interacting with hidden file input on C# binding for Selenium Webdriver 2.35 and Firefox 24. To make file selection working did similar trick:

((IJavaScriptExecutor)webdriver).ExecuteScript("$('#fileUploadInput').css({opacity: 1, transform: 'none'});");

IWebElement e = webdriver.FindElement(By.CssSelector("input#fileUploadInput")));

e.SendKeys("c:\\temp\\inputfile.txt");
New Alexandria
  • 6,951
  • 4
  • 57
  • 77
1

I ended up resolving it a different route.

execute_script() was giving me a hard time (it would freeze test execution on FireFox), so this is what I did:

I already had an appropriate javascript file. I appended the following

<% if ENV["RAILS_ENV"] == "test" %>
  $('#photos').show()
<% end %>

I also had to append .erb to my javascript file for proper Rails asset handling.

And in my test file, I was already setting ENV["RAILS_ENV"] = "test"

This way I could just dumb down the UI for test, and yet maintain the look and feel for production.

Jay
  • 368
  • 1
  • 3
  • 14
0

I've done it this way with elements that has the CSS style display:none; set:

page.execute_script("$('.all-hidden-elements').show();");
all('.all-hidden-elements').first.click
karlingen
  • 13,800
  • 5
  • 43
  • 74
0

If the hidden element is nested in a visible parent element (e.g. a hidden input inside a visible label), you can click on the parent instead. If you still want to find the input by ID, you can traverse to the parent like so:

find('#hidden_input').find(:xpath, '..').click
Kevin Qi
  • 3,220
  • 2
  • 22
  • 24