diff --git a/lib/webrat/core/elements/field.rb b/lib/webrat/core/elements/field.rb
index b81c38d..1a2088d 100644
--- a/lib/webrat/core/elements/field.rb
+++ b/lib/webrat/core/elements/field.rb
@@ -359,10 +359,16 @@ module Webrat
protected
def test_uploaded_file
- if content_type
- ActionController::TestUploadedFile.new(@value, content_type)
- else
- ActionController::TestUploadedFile.new(@value)
+ case Webrat.configuration.mode
+ when :rails
+ if content_type
+ ActionController::TestUploadedFile.new(@value, content_type)
+ else
+ ActionController::TestUploadedFile.new(@value)
+ end
+ when :merb
+ # TODO: support content_type
+ File.new(@value)
end
end
diff --git a/lib/webrat/merb_session.rb b/lib/webrat/merb_session.rb
index fcc9099..6c6ab94 100644
--- a/lib/webrat/merb_session.rb
+++ b/lib/webrat/merb_session.rb
@@ -5,6 +5,13 @@ gem "extlib"
require "extlib"
require "merb-core"
+begin
+ # Require Merb::Test::MultipartRequestHelper with multipart support.
+ require "merb-core/two-oh"
+rescue LoadError => e
+ # Maybe Merb got rid of this. We'll do more checking for multiparth support.
+end
+
# HashWithIndifferentAccess = Mash
module Webrat
@@ -37,13 +44,44 @@ module Webrat
@response.status
end
+ include Merb::Test::MultipartRequestHelper
+
def do_request(url, data, headers, method)
- @response = request(url,
- :params => (data && data.any?) ? data : nil,
- :headers => headers,
- :method => method)
+ if method == "POST" && supports_multipart? && has_file?(data)
+ @response = multipart_post(url, data, :headers => headers)
+
+ elsif method == "PUT" && supports_multipart? && has_file?(data)
+ @response = multipart_put(url, data, :headers => headers)
+
+ else
+ @response = request(url,
+ :params => (data && data.any?) ? data : nil,
+ :headers => headers,
+ :method => method)
+ end
end
+ protected
+
+ # multipart_post and multipart_put which use request to do their
+ # business through multipart_request. Older implementations of
+ # multipart_post and multipart_put use the controller directly.
+ def supports_multipart?
+ respond_to?(:multipart_request)
+ end
+
+ # Recursively search the data for a file attachment.
+ def has_file?(data)
+ data.each do |key, value|
+ if value.is_a?(Hash)
+ return has_file?(value)
+ else
+ return true if value.is_a?(File)
+ end
+ end
+ return false
+ end
+
end
end
diff --git a/spec/integration/merb/app/controllers/testing.rb b/spec/integration/merb/app/controllers/testing.rb
index 31ccbeb..14cba1b 100644
--- a/spec/integration/merb/app/controllers/testing.rb
+++ b/spec/integration/merb/app/controllers/testing.rb
@@ -4,6 +4,15 @@ class Testing < Application
render
end
+ def upload
+ case request.method
+ when :get then render
+ when :post then
+ uploaded_file = params[:uploaded_file]
+ render [uploaded_file[:filename], uploaded_file[:tempfile].class.name].inspect
+ end
+ end
+
def submit_form
end
diff --git a/spec/integration/merb/app/views/testing/upload.html.erb b/spec/integration/merb/app/views/testing/upload.html.erb
new file mode 100644
index 0000000..f750c55
--- /dev/null
+++ b/spec/integration/merb/app/views/testing/upload.html.erb
@@ -0,0 +1,9 @@
+
Webrat Form
+
+
\ No newline at end of file
diff --git a/spec/integration/merb/config/router.rb b/spec/integration/merb/config/router.rb
index c57ec70..6ff8c3c 100644
--- a/spec/integration/merb/config/router.rb
+++ b/spec/integration/merb/config/router.rb
@@ -28,6 +28,7 @@
Merb.logger.info("Compiling routes...")
Merb::Router.prepare do
match("/").to(:controller => "testing", :action => "show_form")
+ match("/upload").to(:controller => "testing", :action => "upload")
match("/internal_redirect").to(:controller => "testing", :action => "internal_redirect")
match("/external_redirect").to(:controller => "testing", :action => "external_redirect")
end
diff --git a/spec/integration/merb/spec/webrat_spec.rb b/spec/integration/merb/spec/webrat_spec.rb
index bdaad20..6264dae 100644
--- a/spec/integration/merb/spec/webrat_spec.rb
+++ b/spec/integration/merb/spec/webrat_spec.rb
@@ -29,4 +29,11 @@ describe "Webrat" do
response = visit "/external_redirect"
response.status.should == 302
end
+
+ it "should upload files" do
+ visit "/upload"
+ attach_file "File", __FILE__
+ response = click_button "Upload"
+ response.should contain(%(["webrat_spec.rb", "Tempfile"]))
+ end
end
diff --git a/spec/private/merb/attaches_file_spec.rb b/spec/private/merb/attaches_file_spec.rb
new file mode 100644
index 0000000..5c17cfa
--- /dev/null
+++ b/spec/private/merb/attaches_file_spec.rb
@@ -0,0 +1,93 @@
+require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
+
+describe "attach_file with merb" do
+ before do
+ Webrat.configuration.mode = :merb
+ @filename = __FILE__
+ end
+
+ it "should fail if no file field found" do
+ with_html <<-HTML
+
+
+
+ HTML
+ lambda { attach_file("Doc", "/some/path") }.should raise_error(Webrat::NotFoundError)
+ end
+
+ it "should submit empty strings for blank file fields" do
+ with_html <<-HTML
+
+
+
+ HTML
+ webrat_session.should_receive(:post).with("/widgets", { "widget" => { "file" => "" } })
+ click_button
+ end
+
+ it "should submit the attached file" do
+ with_html <<-HTML
+
+
+
+ HTML
+ webrat_session.should_receive(:post).with { |path, params|
+ path.should == "/widgets"
+ params.should have_key("widget")
+ params["widget"].should have_key("file")
+ params["widget"]["file"].should be_an_instance_of(File)
+ params["widget"]["file"].path.should == @filename
+ }
+ attach_file "Document", @filename
+ click_button
+ end
+
+ it "should support collections" do
+ with_html <<-HTML
+
+
+
+ HTML
+ webrat_session.should_receive(:post).with { |path, params|
+ path.should == "/widgets"
+ params.should have_key("widget")
+ params["widget"].should have_key("files")
+ params["widget"]["files"][0].should be_an_instance_of(File)
+ params["widget"]["files"][0].path.should == @filename
+ params["widget"]["files"][1].should be_an_instance_of(File)
+ params["widget"]["files"][1].path.should == @filename
+ }
+ attach_file "Document", @filename
+ attach_file "Spreadsheet", @filename
+ click_button
+ end
+
+ xit "should allow the content type to be specified" do
+ with_html <<-HTML
+
+
+
+ HTML
+ ActionController::TestUploadedFile.should_receive(:new).with(@filename, "image/png").any_number_of_times
+ attach_file "Picture", @filename, "image/png"
+ click_button
+ end
+end
diff --git a/spec/private/merb/merb_session_spec.rb b/spec/private/merb/merb_session_spec.rb
index 25560f7..06b4b99 100644
--- a/spec/private/merb/merb_session_spec.rb
+++ b/spec/private/merb/merb_session_spec.rb
@@ -22,6 +22,25 @@ describe Webrat::MerbSession do
end
end
+ %w{post put}.each do |request_method|
+ it "should call do request with method #{request_method.upcase} with a file attachment" do
+ session = Webrat::MerbSession.new
+ response = OpenStruct.new
+ response.status = 200
+
+ file = File.new(__FILE__)
+ session.should_receive(:request).with { |path, env|
+ path.should == "url"
+ env[:method].should == request_method.upcase
+ env[:headers].should be_nil
+ env[:input].should be_an_instance_of(StringIO)
+ env["CONTENT_LENGTH"].should be_an_instance_of(Fixnum)
+ env["CONTENT_TYPE"].should match(/multipart.*boundary/)
+ }.and_return(response)
+ session.send(request_method, 'url', { :file => file }, nil)
+ end
+ end
+
context "a session with a response" do
before do
@session = Webrat::MerbSession.new