How do you test uploading a file with Capybara and Dropzone.js?
To solve this, simulate a drop event to trigger dropping an attachment onto Dropzone. First add this function to your step definition:
# Upload a file to Dropzone.js
def drop_in_dropzone(file_path)
# Generate a fake input selector
page.execute_script <<-JS
fakeFileInput = window.$('<input/>').attr(
{id: 'fakeFileInput', type:'file'}
).appendTo('body');
JS
# Attach the file to the fake input selector
attach_file("fakeFileInput", file_path)
# Add the file to a fileList array
page.execute_script("var fileList = [fakeFileInput.get(0).files[0]]")
# Trigger the fake drop event
page.execute_script <<-JS
var e = jQuery.Event('drop', { dataTransfer : { files : [fakeFileInput.get(0).files[0]] } });
$('.dropzone')[0].dropzone.listeners[0].events.drop(e);
JS
end
Then test with:
When(/^I upload "([^"]*)"$/) do |filename|
drop_in_dropzone File.expand_path(filename)
# add assertion here
end
NOTE: You need to have jQuery loaded, and the Dropzone element requires the dropzone class.
These days I find this way more graceful
page.attach_file(Rails.root.join('spec/fixtures/files/avatar.png')) do
page.find('#avatar-clickable').click
end
Where is in my case #avatar-clickable
is a div which contain Dropzone form tag.
Building off of @deepwell's answer which didn't quite work for me, here is a solution using vanilla JS for the events and event dispatching, and a neutral selector for the dropzone:
def drop_in_dropzone(file_path, zone_selector)
# Generate a fake input selector
page.execute_script <<-JS
fakeFileInput = window.$('<input/>').attr(
{id: 'fakeFileInput', type:'file'}
).appendTo('body');
JS
# Attach the file to the fake input selector
attach_file("fakeFileInput", file_path)
# Add the file to a fileList array
page.execute_script("fileList = [fakeFileInput.get(0).files[0]]")
# Trigger the fake drop event
page.execute_script <<-JS
dataTransfer = new DataTransfer()
dataTransfer.items.add(fakeFileInput.get(0).files[0])
testEvent = new DragEvent('drop', {bubbles:true, dataTransfer: dataTransfer })
$('#{zone_selector}')[0].dispatchEvent(testEvent)
JS
end
uses global vars on purpose, so I could test in js console, but feel free to scope them.