Rails Functional Test Case and Uploading Files to ActionDispatch::Http::UploadFile

Kevin Sylvestre picture Kevin Sylvestre · Dec 22, 2010 · Viewed 8.7k times · Source

I'm am adding tests to a Rails app that remotely stores files. I'm using the default Rails functional tests. How can I add file uploads to them? I have:

test "create valid person" do
  post(:create, :person => { :avatar => fixture_file_upload('avatar.jpeg') })
end

This for some reason uploads a Tempfile and causes the AWS/S3 gem to fail with:

NoMethodError: undefined method `bytesize' for Tempfile

Is their any way that I can get the test to use an ActionDispatch::Http::UploadedFile and perform more like it does when testing with the web browser? Is fixture_file_upload the way to test uploading files to a controller? If so why doesn't it work like the browser?

As a note, I really don't want to switch testing frameworks. Thanks!

Answer

Stefaan Colman picture Stefaan Colman · Jan 6, 2011

I use the s3 gem instead of the aws/s3 gem. The main reasons for this are no support for european buckets and development of aws/s3 seems to be stopped.

If you want to test file upload than using the fixtures_file_upload method is correct, it maps directly to Rack::Test::UploadedFile.new (you can use this if the test file isn't in the fixtures folder).

But I've also noticed that the behavior of the Rack::Test::Uploaded file objects isn't exactly the same as the ActionDispatch::Http::UploadedFile object (that's the class of uploaded files). The basic methods (original_filename, read, size, ...) all work but there are some differences when working with the file method. So limit your controller to these methods and all will be fine.

An other possible solution is by creating an ActionDispatch::Http::Uploaded file object and using that so:

upload = ActionDispatch::Http::UploadedFile.new({
  :filename => 'avatar.jpeg',
  :type => 'image/jpeg',
  :tempfile => File.new("#{Rails.root}/test/fixtures/avatar.jpeg")
})

post :create, :person => { :avatar => upload }