How to test file upload with Grape Framework

Grape is a Rack based Ruby framework for building API. It’s only a few years old and has not reached version 1.0 yet. The main github page has a very good documentation but is still not as complete as Rails guide. In this post, I will discuss how to test file upload endpoint with RSpec.

Suppose you have an endpoint that takes a file input.

class MyAPI::FileUpload < Grape::API
  desc 'Upload a file'
  params do
    require :file, type: File
  end
  post '/upload' do
    # params[:file][:tempfile] is a Tempfile
    size = File.size(params[:file][:tempfile])

    present {
      filename: params[:file][:filename],
      type: params[:file][:type],
      size: size
    }
  end
end

How do we actually send a real file to the endpoint in your RSpec test? In Rails we have a fixture_file_upload helper.

post :upload, file: fixture_file_upload('images/image.jpg', 'image/jpg')

# Under the hood, fixture_file_upload basically creates
Rack::Test::UploadedFile.new(File.open(File.join(Rails.root, '/spec/fixtures/images/image.jpg')), 'image/jpg')

Because Grape is just a Rack based framework, you can use the same way to test file upload. That is by creating an instance of Rack::Test::UploadedFile.

RSpec.describe MyAPI::FileUpload do
  it 'upload a file' do
    file_path = '/path/to/image.jpg'
    post '/upload', file: Rack::Test::UploadedFile.new(file_path, 'image/jpeg')

    json_response = JSON.parse(last_response.body)
    expect(json_response[:filename]).to eq('image.jpg')
    expect(json_response[:type]).to eq('image/jpeg')
    expect(json_response[:size]).to eq(File.size(file_path))
  end
end