Support for multiple file upload.

Squashed commit of the following:

commit fb88141863
Author: Jarl Friis <jarl@softace.dk>
Date:   Mon Sep 3 22:06:07 2012 +0200

    Improved implementation. Removing need for YAML. Extending the driver API to take an Array when 'multiple' attribute is present.

commit 977f1c50c2
Author: Jarl Friis <jarl@softace.dk>
Date:   Mon Sep 3 11:56:04 2012 +0200

    Changing decision criteria to support 1.8.7

commit b217deef4a
Author: Jarl Friis <jarl@softace.dk>
Date:   Mon Sep 3 10:38:16 2012 +0200

    Support for 'multiple' attribute in input tags, see https://github.com/jnicklas/capybara/issues/778

commit 155b9fcf79
Author: Jarl Friis <jarl@softace.dk>
Date:   Mon Sep 3 10:33:00 2012 +0200

    Test that demonstrates lack of support for 'multiple' attribute in input tags, see https://github.com/jnicklas/capybara/issues/778

Conflicts:

	lib/capybara/node/actions.rb
	lib/capybara/selenium/node.rb
	lib/capybara/spec/session/attach_file_spec.rb
This commit is contained in:
Jarl Friis 2012-09-17 14:48:13 +02:00
parent 13dee1649f
commit 3e2d7c2114
7 changed files with 44 additions and 10 deletions

View File

@ -20,6 +20,7 @@ module Capybara
raise NotImplementedError
end
# @param value String or Array. Array is only allowed if node has 'multiple' attribute
def set(value)
raise NotImplementedError
end

View File

@ -135,10 +135,12 @@ module Capybara
# page.attach_file(locator, '/path/to/file.png')
#
# @param [String] locator Which field to attach the file to
# @param [String] path The path of the file that will be attached
# @param [String] path The path of the file that will be attached, or an array of paths
#
def attach_file(locator, path)
raise Capybara::FileNotFound, "cannot attach file, #{path} does not exist" unless File.exist?(path.to_s)
(String === path ? [path] : path).each do |p|
raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s)
end
find(:file_field, locator).set(path)
end
end

View File

@ -12,6 +12,9 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
end
def set(value)
if (Array === value) && !self[:multiple]
raise ArgumentError.new "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
end
if tag_name == 'input' and type == 'radio'
other_radios_xpath = XPath.generate { |x| x.anywhere(:input)[x.attr(:name).equals(self[:name])] }.to_s
driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute("checked") }
@ -29,7 +32,17 @@ class Capybara::RackTest::Node < Capybara::Driver::Node
# Firefox, allowing no input
value = value[0...self[:maxlength].to_i]
end
native['value'] = value.to_s
if Array === value #Assert multiple attribute is present
value.each do |v|
new_native = native.clone
new_native.remove_attribute('value')
native.add_next_sibling(new_native)
new_native['value'] = v.to_s
end
native.remove
else
native['value'] = value.to_s
end
elsif tag_name == "textarea"
native.content = value.to_s
end

View File

@ -19,12 +19,16 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
end
def set(value)
if (Array === value) && !self[:multiple]
raise ArgumentError.new "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
end
if tag_name == 'input' and type == 'radio'
click
elsif tag_name == 'input' and type == 'checkbox'
click if value ^ native.attribute('checked').to_s.eql?("true")
elsif tag_name == 'input' and type == 'file'
native.send_keys(value.to_s)
path_names = value.to_s.empty? ? [] : value
native.send_keys(*path_names)
elsif tag_name == 'textarea' or tag_name == 'input'
native.send_keys(("\b" * native[:value].size) + value.to_s)
end

View File

@ -0,0 +1 @@
ThisIsTheOtherTestFile

View File

@ -1,6 +1,7 @@
Capybara::SpecHelper.spec "#attach_file" do
before do
@test_file_path = File.expand_path('../fixtures/test_file.txt', File.dirname(__FILE__))
@another_test_file_path = File.expand_path('../fixtures/another_test_file.txt', File.dirname(__FILE__))
@test_jpg_file_path = File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__))
@session.visit('/form')
end
@ -11,7 +12,7 @@ Capybara::SpecHelper.spec "#attach_file" do
@session.click_button('awesome')
extract_results(@session)['image'].should == File.basename(__FILE__)
end
it "should set a file path by label" do
@session.attach_file "Image", __FILE__
@session.click_button('awesome')
@ -54,12 +55,22 @@ Capybara::SpecHelper.spec "#attach_file" do
@session.click_button 'Upload Single'
@session.should have_content('image/jpeg')
end
it "should not break when using HTML5 multiple file input" do
it "should not break when using HTML5 multiple file input" do
@session.attach_file "Multiple Documents", @test_file_path
@session.click_button('Upload Multiple')
@session.body.should include("1 | ")#number of files
@session.should have_content(File.read(@test_file_path))
end
it "should not break when using HTML5 multiple file input uploading multiple files" do
pending "Selenium is buggy on this, see http://code.google.com/p/selenium/issues/detail?id=2239" if @session.respond_to?(:mode) && @session.mode == :selenium
@session.attach_file "Multiple Documents", [@test_file_path, @another_test_file_path]
@session.click_button('Upload Multiple')
@session.body.should include("2 | ")#number of files
@session.body.should include(File.read(@test_file_path))
@session.body.should include(File.read(@another_test_file_path))
end
end
context "with a locator that doesn't exist" do

View File

@ -151,9 +151,11 @@ class TestApp < Sinatra::Base
post '/upload_multiple' do
begin
buffer = []
buffer << "Content-type: #{params[:form][:multiple_documents][0][:type]}"
buffer << "File content: #{params[:form][:multiple_documents][0][:tempfile].read}"
buffer = ["#{params[:form][:multiple_documents].size}"]
params[:form][:multiple_documents].each do |doc|
buffer << "Content-type: #{doc[:type]}"
buffer << "File content: #{doc[:tempfile].read}"
end
buffer.join(' | ')
rescue
'No files uploaded'