File uploads in request specs

Augusts Bautra - Aug 21 - - Dev Community

Today I was working with logic around file uploads, and here's what I learned:

In request specs, to simulate a form submission of a file, you can use a Rack::Test::UploadedFile object (see docs). Initializing it is a bit involved, so I recommend setting up a spec helper:

# in some place that gets loaded for specs like spec/support/helpers/uploaded_file_helper.rb
module UploadedFileSpecHelper
  # Mimics a file upload parameter. Use like so:
  #   uploaded_file(fixtures_path("example.pdf"), "custom_name.pdf", "application/pdf")
  def uploaded_file(path, name, mime_type, binmode: true)
    Rack::Test::UploadedFile.new(path, mime_type, binmode, original_filename: name)
  end
end

RSpec.configure do |config|
  config.include UploadedFileSpecHelper, type: :request
end
Enter fullscreen mode Exit fullscreen mode

Then setting up params in a request spec for some #create action is a breeze:

let(:params) do
  {
    upload: {
      file: uploaded_file(fixtures_path("example.pdf"), "custom_name.pdf", "application/pdf"),      
    }
  }
end
Enter fullscreen mode Exit fullscreen mode

In the controller, Rails will have parsed this object into a regular ActionDispatch::Http::UploadedFile object like in a real request. If this object is passed deeper into backend, for example, some service, for specs there you'll have to use this instead:

ActionDispatch::Http::UploadedFile.new(
  filename: "custom_name.pdf",
  type: "application/pdf",
  tempfile: File.open(fixtures_path("example.pdf"))
)
Enter fullscreen mode Exit fullscreen mode
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .