Search code examples
ruby-on-railstestingrspecrequestrails-activestorage

RSpec request spec to test ActiveStorage with FactoryBot


I read many Q&A and posts on the web and tried each proposed solution without coming up to a working one for RSpec request testing with ActiveStorage and FactoryBot.

As of now, I've the code:

# factories/user.rb

factory :registered_user, :class => User do
  sequence(:email) { |n| "foobar_#{n}@email.com" }
  ...

  factory :invalid_user, :class => User do
    email { '!!!' }
    ...

    # I'm trying to make this (or similar) to work
    picture { Rack::Test::UploadedFile.new(Rails.root.join('spec/factories/files/pictures/image-INVALID-size-too-big.jpg'), 'image/jpeg') }
  end
end
# requests/users/images_spec.rb

RSpec.describe 'Users image requests', :type => :request do
  describe 'test request at users_image_path' do
    before(:each) do
      @regular_user = FactoryBot.create(:regular_user)

      login_as(@regular_user, :scope => :user) # Devise ruby-gem
    end

    subject(:user) { @regular_user }

    let(:invalid_user_params) { 
      ActionController::Parameters.new(:picture => FactoryBot.attributes_for(:invalid_user)[:picture]).permit! 
      # Also tried this without success:
      # { :picture => FactoryBot.attributes_for(:invalid_user)[:picture] }
    }


    it 'status :unprocessable_entity' do
      patch users_image_path(:user => invalid_user_params, :as => :html

      expect(response).to have_http_status(:unprocessable_entity)
    end
  end
end

By running the above spec I get the error:

ActiveSupport::MessageVerifier::InvalidSignature: mismatched digest

The logs

... when running the above spec:

Started PATCH "/users/image?user%5Bpicture%5D=%23%3CRack%3A%3ATest%3A%3AUploadedFile%3A0x0000000122758d98%3E" for 127.0.0.1 at 2024-01-09 09:07:41 +0100
[ActiveJob] Enqueued ActiveStorage::AnalyzeJob (Job ID: 835acb7e-3d89-45b5-9f1e-be2ab4f7b9cd) to Test(default) with arguments: #<GlobalID:0x000000012108d488 @uri=#<URI::GID gid://my-app/ActiveStorage::Blob/95>>
  Processing by Users::ImagesController#update as HTML
  Parameters: {"user"=>{"picture"=>"#<Rack::Test::UploadedFile:0x0000000122758d98>"}}

... when uploading the file manually in the browser:

Started PATCH "/users/image" for 127.0.0.1 at 2024-01-09 07:03:08 +0100
  Processing by Users::ImagesController#update as HTML
  Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"picture"=>#<ActionDispatch::Http::UploadedFile:0x0000000121786190 @tempfile=#<Tempfile:/var/folders/74/bpsjzpcx73vd5601bgrny37w0000gn/T/RackMultipart20240109-45321-1ccx6n.jpg>, @content_type="image/jpeg", @original_filename="image-INVALID-size-too-big", @headers="Content-Disposition: form-data; name=\"user[picture]\"; filename=\"image-INVALID-size-too-big\"\r\nContent-Type: image/jpeg\r\n">}, "commit"=>"Update picture"}

How to make things to work?


Solution

  • Parameters have to go into patch instead of a url helper:

    let(:invalid_user_params) {
      # permitted params are on the other side of the request, not here
      {picture: Rack::Test::UploadedFile.new(Rails.root.join("spec/test.png"), "image/png")}
    }
    
    it "status :unprocessable_entity" do
      #                       v
      patch(users_image_path, params: {user: invalid_user_params})
      expect(response).to have_http_status(:unprocessable_entity)
    end
    

    https://api.rubyonrails.org/classes/ActionDispatch/Integration/RequestHelpers.html#method-i-patch