8

I have a Rails project using Cucumber and Capybara for tests. I have a file upload page using Dropzone.js.

My uploads work great using the dialog box or drag and drop. Testing is another matter.

I have the following field in my form:

<input id="photo_image" multiple="multiple" name="image" type="hidden">

However, in the step definitions, I've tried a few methods of finding and attaching the file data, but none of them work.

I've tried fill_in:

fill_in "photo_image",  with: photo

I've tried find with css selectors:

find('#photo_image').set photo

I've tried find with xpath:

find(:xpath, "//input[@id='photo_image']").set photo

But none of them see the hidden field.

Unable to find css "#photo_image" (Capybara::ElementNotFound)

Unable to find xpath "//input[@id='photo_image']" (Capybara::ElementNotFound)

Unable to find field "photo_image" (Capybara::ElementNotFound)

Is there any testing method that can handle the upload using Dropzone.js or is it hopeless?

Flip
  • 6,233
  • 7
  • 46
  • 75
David Watson
  • 3,394
  • 2
  • 36
  • 51

8 Answers8

11

Capybara 2.1 doesn't find hidden elements by default.

You can either set ignore_hidden_elements to false:

Capybara.ignore_hidden_elements = false

or add :visible option to your method:

attach_file('photo_image', path_to_file, visible: false)

I prefer the second variant as in most of cases elements to be found in tests are visible and it's better to keep Capybara to throw exception if one of them is hidden.

Note: :visible option is also supported by most of Capybara methods that internally work with Capybara::Query (like find, all, has_css?, have_selector etc.)

Andrei Botalov
  • 20,686
  • 11
  • 89
  • 123
  • Also, like an answer below mentions, for tests like these please ensure that `:js => true` is set. – bbbco Jun 04 '13 at 11:42
  • I tried setting visible to false but attach_file still doesn't find it. What's strange is that I added a line immediately above attach_file to do the find and it finds the input field just fine. I looked at the source and discovered that attach_file is doing a find also but I don't understand why attach_file's find doesn't find the input field. – David Watson Jun 05 '13 at 17:32
  • @DavidWatson It's strange. Please answer those 3 questions: 1. Which Capybara version do you use? 2. What is your driver? 3. Have you tried the exact `find` method that Capybara's `attach_file` invokes: `find(:field, 'photo_image')`? – Andrei Botalov Jun 05 '13 at 18:30
  • I've tried it with selenium, chrome, and poltergeist drivers. capybara (2.1.0) capybara-webkit (1.0.0 9bbf4f6) I will try the exact find method soon. – David Watson Jun 06 '13 at 11:56
4

Since I just had to help someone figure this out, this is an updated answer for current versions of Capybara and dropzone.js.

By default Dropzone adds a hidden file field to the body of the page at initialization with a class of 'dz-hidden-input'. To add a file to that for testing purposes you can do

attach_file(file_path, class: 'dz-hidden-input', make_visible: true)

Explanation: There is no known id/name/label text so we don't pass a locator, instead we pass the class option to limit the found file inputs to ones with the specified class. Then we specify the make_visible: true to have Capybara temporarily change the CSS so the file input becomes visible, adds the file, then restores the original CSS.

Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78
1

The point here is: dropzone only uses the input field as a marker or as a fallback. It deletes it from the dom. If you inspect the source of the page after successful dropzone initialization you will not be able to find the element any more.

So it's not about a hidden input field but about a deleted one 'which is gone' and can't be found since it's not part of the dom anymore.

What I ended up doing was adding the input field manually in the specs:

page.execute_script(%|$('#your-form').append('<input id="photo_image" name="image" type="file">');|)

This will make your form behave as in the dropzone fallback mode.

1

You do not need to add a new page execution, all you need to do is find .dz-hidden-input and attach_file to it...

   attach_file("path/to/file", class: "dz-hidden-input", make_visible: true)
gustavoanalytics
  • 584
  • 6
  • 18
1

Dropzone.js uses the next input to attach files(take it from my website):

<input type="file" multiple="multiple" class="dz-hidden-input" accept="image/*,application/pdf" style="visibility: hidden; position: absolute; top: 0px; left: 0px; height: 0px; width: 0px;">

So everything you need is just to run the following code to attach file through dropzone.js:

page.find('.dz-hidden-input', visible: false).set('file_path_here'))
0

U can use

it "should upload a file" do
  visit upload_file_path
  attach_file "uploadfile(id of field)", /path/to/file/to/upload
  click_button "Upload File"
end

Steps between do ... end should work with both rspec + capybara or cucumber + capybara

and why not use :js => true , It will help out to find hidden elements tooo..

Grey
  • 676
  • 8
  • 23
0

I think Capybara is not finding is because you're not creating a file field.

<input id="photo_image" multiple="multiple" name="image" type="file">

type="file" is what you want. An input with type="hidden" should just accept a string.

I too am trying to test a dropzone.js area in rspec/capybara and hitting a wall. Did you ever get this figured out?

I was trying the solution here, with no luck: Using Selenium to imitate dragging a file onto an upload element

Community
  • 1
  • 1
Brett C
  • 291
  • 2
  • 13
-2

your input type is hidden,pls remove it as capybara wont be able to see it on the browser.Try this,it works for me:-

web_steps.rb

When /^I attach the file "([^"]*)" to "([^"]*)"$/ do |path, field|
  attach_file(field, File.expand_path(path))
end

upload_picture.feature

 ###.....some other steps too
 When I attach the file "app/assets/images/default/accept.jpg" to "image[image]"
  • This answer addresses the question in the least possible way and in the context of the question it is wrong. Did you read the question? op is stating "I have a file upload page using dropzone js." – Overbryd Aug 18 '16 at 10:09