您如何测试使用 Capybara 和 Dropzone.js 上传文件?
How do you test uploading a file with Capybara and Dropzone.js?
我已改用 Dropzone.js 插件进行拖放文件上传。如何编写 Capybara 测试以确保此功能继续工作?
之前我有一个带有输入文件元素的模板:
<input type="file" name="attachments">
而且测试很简单:
When(/^I upload "([^"]*)"$/) do |filename|
attach_file("attachments", File.expand_path(filename))
# add assertion here
end
但是这不再有效,因为 Dropzone 没有可见的文件输入。
要解决此问题,请模拟一个拖放事件以触发将附件拖放到 Dropzone 上。首先将此函数添加到您的步骤定义中:
# 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
然后测试:
When(/^I upload "([^"]*)"$/) do |filename|
drop_in_dropzone File.expand_path(filename)
# add assertion here
end
注意:您需要加载 jQuery,并且 Dropzone 元素需要 dropzone class.
如果有人感兴趣,我将@deepwell 的功能移植到 javascript,以便与 javascript 风味的硒一起使用:
this.dropInDropzone = function(filePath) {
var script = "fakeFileInput = $('#fakeFileInput'); if (fakeFileInput.length === 0) fakeFileInput = window.$('<input/>').attr({id: 'fakeFileInput', type:'file'}).appendTo('body');";
// Generate a fake input selector
return driver.executeScript(script).then(function() {
// Attach the file to the fake input selector
return driver.findElement(webdriver.By.css('#fakeFileInput')).sendKeys(filePath);
}).then(function() {
// Add the file to a fileList array
return driver.executeScript("var fileList = [fakeFileInput.get(0).files[0]]");
}).then(function() {
// Trigger the fake drop event
script = "var e = jQuery.Event('drop', { dataTransfer : { files : [fakeFileInput.get(0).files[0]] } }); $('.dropzone')[0].dropzone.listeners[0].events.drop(e);"
return driver.executeScript(script);
});
};
基于 @deepwell 的回答,这对我来说不太适用,这里是一个使用 vanilla JS 进行事件和事件调度的解决方案,以及一个用于 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
故意使用全局变量,因此我可以在 js 控制台中进行测试,但可以随意调整它们的范围。
最近觉得这样比较优雅
page.attach_file(Rails.root.join('spec/fixtures/files/avatar.png')) do
page.find('#avatar-clickable').click
end
在我的例子中 #avatar-clickable
是一个包含 Dropzone 表单标签的 div。
自 Capybara 3.21.0 以来,您可以将文件拖放到这样的元素上:
find(".dropzone").drop(Rails.root.join("spec/fixtures/file.txt"))
详情见Element#drop
source。
我已改用 Dropzone.js 插件进行拖放文件上传。如何编写 Capybara 测试以确保此功能继续工作?
之前我有一个带有输入文件元素的模板:
<input type="file" name="attachments">
而且测试很简单:
When(/^I upload "([^"]*)"$/) do |filename|
attach_file("attachments", File.expand_path(filename))
# add assertion here
end
但是这不再有效,因为 Dropzone 没有可见的文件输入。
要解决此问题,请模拟一个拖放事件以触发将附件拖放到 Dropzone 上。首先将此函数添加到您的步骤定义中:
# 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
然后测试:
When(/^I upload "([^"]*)"$/) do |filename|
drop_in_dropzone File.expand_path(filename)
# add assertion here
end
注意:您需要加载 jQuery,并且 Dropzone 元素需要 dropzone class.
如果有人感兴趣,我将@deepwell 的功能移植到 javascript,以便与 javascript 风味的硒一起使用:
this.dropInDropzone = function(filePath) {
var script = "fakeFileInput = $('#fakeFileInput'); if (fakeFileInput.length === 0) fakeFileInput = window.$('<input/>').attr({id: 'fakeFileInput', type:'file'}).appendTo('body');";
// Generate a fake input selector
return driver.executeScript(script).then(function() {
// Attach the file to the fake input selector
return driver.findElement(webdriver.By.css('#fakeFileInput')).sendKeys(filePath);
}).then(function() {
// Add the file to a fileList array
return driver.executeScript("var fileList = [fakeFileInput.get(0).files[0]]");
}).then(function() {
// Trigger the fake drop event
script = "var e = jQuery.Event('drop', { dataTransfer : { files : [fakeFileInput.get(0).files[0]] } }); $('.dropzone')[0].dropzone.listeners[0].events.drop(e);"
return driver.executeScript(script);
});
};
基于 @deepwell 的回答,这对我来说不太适用,这里是一个使用 vanilla JS 进行事件和事件调度的解决方案,以及一个用于 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
故意使用全局变量,因此我可以在 js 控制台中进行测试,但可以随意调整它们的范围。
最近觉得这样比较优雅
page.attach_file(Rails.root.join('spec/fixtures/files/avatar.png')) do
page.find('#avatar-clickable').click
end
在我的例子中 #avatar-clickable
是一个包含 Dropzone 表单标签的 div。
自 Capybara 3.21.0 以来,您可以将文件拖放到这样的元素上:
find(".dropzone").drop(Rails.root.join("spec/fixtures/file.txt"))
详情见Element#drop
source。