title: How to Simulate ActiveStorage Uploads in RSpec Request Specs
body: <p>I'm writing an API-Only Rails App (rails 5.2) and I need to make use of ActiveStorage. I want to write an RSpec Request Spec to ensure that file uploads work properly, but that's proving very difficult. Here's my spec so far:</p>
  
  <pre class="lang-rb prettyprint-override"><code>RSpec.describe 'POST /profile/photos', type: :request do
    let(:url) { '/profile/photos' }
    let(:file) { fixture_file_upload('photo.jpg') }
  
    before do
      log_user_in
  
      ## Do a file upload ##
      post '/rails/active_storage/direct_uploads', params: {
        blob: {
          filename: "woman.jpg",
          content_type: "image/jpeg",
          byte_size: File.size(file.path),
          checksum:  Digest::MD5.base64digest(File.read(file.path))
        }
      }
  
      post url, params: {signed_id: json["signed_id"]}
    end
  
    it "Performs an upload" do
      # Never gets here, error instead
    end
  end
  </code></pre>
  
  <p>I've tried using the <code>put</code> helper to upload the file between the first and second <code>post</code> call in the <code>before</code> step, but I keep running into 422 unprocessable entity errors, likely because the <code>put</code> helper doesn't support setting the raw request body. But I'm not entirely sure what the format of that put should be, or if there's a better way to test this.</p>
  
  <p>I've tried using <code>fixture_file_upload</code>, as described in <a href="https://stackoverflow.com/questions/40796140/how-to-upload-a-file-in-a-rails-rspec-request-spec">this question</a>:</p>
  
  <pre class="lang-rb prettyprint-override"><code>put json["direct_upload"]["url"], params: {file: fixture_file_upload('photo.jpg')}
  </code></pre>
  
  <p>But that request returns 422 like all of my other attempts. I think the direct_upload URL really wants the body of the request to contain the file and nothing else. </p>
  
  <p>I suspect there's a lot wrong with my approach here, but the Rails docs are somewhat sparse on how to use ActiveStorage if you're not using the out-of-the-box javascript to hide most of the interactions.</p>