Is it possible to interact with hidden elements with capybara?
Asked Answered
P

7

46

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.

Percentile answered 25/3, 2013 at 15:25 Comment(4)
It may be hard to do it. Try to start from JS here. But it may not work in all cases and browsersKerekes
Looks like you are not using capybara-webkit (because of "Selenium::WebDriver::Error" in error message) so I removed capybara-webkit tag from your questionKerekes
It may already be answered here: https://mcmap.net/q/298677/-how-to-fill-hidden-field-with-capybaraBuster
The work around works fine! ThanksLouettalough
H
76

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

Hydrophane answered 22/7, 2013 at 13:19 Comment(4)
@mc. On which element you'r clicking, paste the structure hereHydrophane
This may only work because the element has opacity: 0 not visibility: hidden (or similar). You can not click on hidden elements directlyLouettalough
The answer from @Thomas Walpole (here: https://mcmap.net/q/363786/-is-it-possible-to-interact-with-hidden-elements-with-capybara) is a much more useful and direct answer to the problem of attaching a file to an invisible file input.Epizoon
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 #53361714Whistle
O
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
Offload answered 18/6, 2014 at 17:2 Comment(1)
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 makandracards.com/makandra/…Legislatorial
N
9

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)
Narcotism answered 8/6, 2017 at 19:14 Comment(0)
A
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");
Akene answered 18/10, 2013 at 15:13 Comment(1)
Oh. Alexander, are you the same guy from the Open Watcom usenet/newsgroup?Jonson
P
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.

Pyrometallurgy answered 30/4, 2014 at 20:13 Comment(0)
W
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
Wycoff answered 11/11, 2015 at 21:44 Comment(0)
D
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
Distort answered 22/1, 2016 at 21:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.