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