Capybara, capybara-webkit and custom file upload form
Asked Answered
G

5

15

I have created custom upload form using the following html stack:

<form>
  <label></label>
  <input type="file">
</form>

The file field is hidden via css with display: none property. So the file attach dialogue is being called by user when she clicks on label (which is custom styled).

In my feature test I can't attach a file since the input field is hidden. I've tried few possible solutions, but neither of them work:

find(:xpath, '//input', visible: false).set(some_file_path)

or

within('form') do                                                                                                                                                                       
  attach_file(:input, some_file_path, visible: false)                                                                                                                                          
end

And many others. All of the time I end up with Failed to click element at unknown position error. Once I remove the label overlapping the input field, make it visible and run my spec everything passes. So the issue here is the fact that:

  1. The input file field has display: none property (and by thus is can't be found)
  2. There is a label overlapping the hidden file field (probably)

Is there any way to make Capybara with Capybara-webkit driver handle this delicate situation in some sane way?

Grimaldo answered 28/6, 2013 at 9:21 Comment(6)
Can you show CSS/JS using which you style label so I can reproduce this issue?Aquiver
It really is nothing fancy, just regular stuff — jsfiddle.net/QUc4M/2 (btw it is a clean complete solution for custom file upload field :-)Grimaldo
AFAIK you can't attach file to invisible input in Selenium - see this section. I think you should make file input visible prior to attaching file to it.Aquiver
Well good thing is that I am not using Selenium.Grimaldo
I'm not sure what's going on here, but here are two things I notice: (1) You're not closing your input tag. No idea if this matters to Capybara. (2) In your jsFiddle, when I click on the label (in Firefox 22.0), the file dialog opens twice. The second dialog opens after I click cancel on the first one.Melon
@Melon input tags do not need the trailing slash to close them in HTML5Grimaldo
W
16

With capybara-webkit you can tell the driver to run any javascript you want within the context of the page, so you can write something custom to hack around the visibility issue:

script = "$('thelabel').toggle(); " # hide the label
script << "$('myfield').toggle();"  # show your field

page.driver.browser.execute_script(script)

This is pseudo-code, but you should be able to do something similar to make the field visible before you call attach_file on it.

That said, every time (I at least) do something a little gross like this in my tests it is a good idea to take a quick moment and ask if it is the test or the interface that needs to be fixed. If you're happy with the interface, you should be able to use a small js snippet like the above to get the element visible for your test.

Update:

Support for this behavior has become more widespread and is now standardized in capybara, so you can just:

page.execute_script(script)

This shorter version should work with capybara 2.x and recent versions of capybara-webkit or poltergeist, which is a lower-dependency alternative I'm using now.

There is also a partner method, evaluate_script:

result = page.evaluate_script('4 + 4');

Hope this helps!

Winna answered 6/7, 2013 at 1:9 Comment(2)
Finally, an answer! Thank you very much — you just saved my testing! Yeah sure solution is a bit unclean, but it is working and this solution keeps my production code clean; which is more important than clean testing code.Grimaldo
Agree, much better to sacrifice on the testing side. Happy to help! :-)Winna
V
4

Matt Sanders suggests using JS to toggle the element's visibility. That'll work but here's another solution which is a bit cleaner, IMO.

I recommend including hidden fields only when necessary. To accomplish this, I used this helper for those rare cases when you actually want Capybara to include hidden fields. For example:

# features/support/capybara_helpers.rb
module CapybaraHelpers
  # By default, capybara will ignore all hidden fields. This is a smart default
  # except in rare cases. For example, our AS3 file uploader requires you to
  # click a hidden file field - and that makes perfect sense. In those rare
  # cases, you can use this helper to override the default and force capybara
  # to include hidden fields.
  #
  # Examples
  #
  #   include_hidden_fields do
  #     attach_file("hidden-input", "path/to/fixture/file")
  #   end
  #
  def include_hidden_fields
    Capybara.ignore_hidden_elements = false
    yield
    Capybara.ignore_hidden_elements = true
  end
end
World(CapybaraHelpers)
Velodrome answered 4/6, 2014 at 16:22 Comment(1)
The problem in not in field being hidden; the problem exists because the form field is overlaid by a label. So no; your solution won't work in this case.Grimaldo
V
1

Now there is an option "make_visible" https://www.rubydoc.info/github/jnicklas/capybara/Capybara/Node/Actions%3Aattach_file

Vanscoy answered 15/6, 2020 at 15:49 Comment(1)
This is the best option with newer Capybara versions.Florez
V
0

for someone else, may find this useful:

Sometimes 'toggle' is not enough, then check 'opacity' (shouldnt be zero):

script = "$('#file-field').css({opacity: 100, display: 'block'});"
page.driver.browser.execute_script(script)
Vicenary answered 27/1, 2014 at 8:57 Comment(0)
S
-1

Try this

file_field = page.find('input[type="file"]', visible: false) file_field.set('path/to/my/image.jpg')

Surfeit answered 17/7, 2016 at 17:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.