24

After upgrade to ruby 3 and rails 6.1 my tests break on the line

subject.avatar.attach(fixture_file_upload(Rails.root.join('spec', 'fixtures', 'images', 'avatar.jpg')))

with:

NoMethodError:
        undefined method `file_fixture_path' for RSpec::Rails::FixtureFileUploadSupport::RailsFixtureFileWrapper:Class
        Did you mean?  fixture_path

the error stack points to webmock-3.11.0/lib/webmock/rspec.rb:37

Any suggestions how to debug it?

mingle
  • 1,567
  • 1
  • 16
  • 19
  • 4
    After changing to file_fixture it works just fine https://relishapp.com/rspec/rspec-rails/v/3-8/docs/file-fixture – mingle Jan 09 '21 at 11:00
  • 1
    thanks for the info! I just ran into the same problem. You should write the info into an answer yourself and then accept your own answer :) – Michael Smart Jan 22 '21 at 15:48
  • 5
    Had the same issue but for `FactoryBot::Syntax::Default::DSL:Class`. That's why all proposed solutions didn't work for me. Just replace fixture_file_upload with `Rack::Test::UploadFile.new('file_path', mime_type)` I know it's not the best solution ever. But I think then there is some issue in `actionpack-6.1.3/lib/action_dispatch/testing/test_process.rb:43`. They should add `self.class.respond_to?(:file_fixture_path)` to the condition. – Pavel Kalashnikov Mar 07 '21 at 23:00
  • @PavelKalashnikov This is the only solution that works for me. Do you know why this is right? – Qwertie Sep 14 '21 at 04:10
  • @Qwertie I've explored the sources of the actionpack. – Pavel Kalashnikov Sep 16 '21 at 07:33

5 Answers5

19

Anything above didn't worked for me, but I found another solution.

In the factory changed this:

photo { fixture_file_upload(Rails.root.join('spec/support/images/test_image.png'), 'image/png') }

to this:

photo { Rack::Test::UploadedFile.new('spec/support/images/test_image.png', 'image/png') }

But after that I faced with another error:

unknown attribute 'service_name' for ActiveStorage::Blob

And solved this with two commands:

rails active_storage:update
rails db:migrate

I hope this may be useful to anybody.

Ruslan Valeev
  • 1,529
  • 13
  • 24
17

Ran into the same error, but had to solve it differently as the post in a request spec doesn't accept the object returned by file_fixture.

Including include ActionDispatch::TestProcess::FixtureFile in my request solved it for me.

RSpec.describe "Attachments", type: :request do
  include Rack::Test::Methods
  include ActionDispatch::TestProcess::FixtureFile
  #...
    expect {
      file = fixture_file_upload("image.jpg", "image/jpeg", :binary)
      post collection_work_attachments_path(collection, work), {attachment: {file: file, name: image_name, visibility: [:admin]}}
    }.to change(Attachment, :count).by(1)
  #...
end
murb
  • 1,736
  • 21
  • 31
  • Huh, interesting. Thanks for the solution. – alex Mar 02 '21 at 13:09
  • 2
    I guess we have updates how to solve it https://github.com/rspec/rspec-rails/issues/2402#issuecomment-737625958. The current approach resolves, however, it's not appropriated (https://github.com/thoughtbot/factory_bot/issues/385#issuecomment-439040731) – Alex Jul 18 '22 at 12:00
  • 1
    !! Including the content from @Alex's link above. Don't include `ActionDispatch::TestProcess`. It has some nasty consequences. This is a bad practice because it includes other methods such as `session` which override existing methods on *all objects*. https://github.com/honeybadger-io/honeybadger-ruby/blob/a18b1c3c4d912f96f1a3cb1435cc8a50e436f7f5/lib/honeybadger/notice.rb#L487 Proper solution is to use `Rack::Test::UploadedFile` directly in the factory (what fixture_file_upload essentially does anyway): `file { Rack::Test::UploadedFile.new('spec/factories/test.png', 'image/png') }` – Kelton Temby May 02 '23 at 05:16
  • 1
    Reading the comments I have been a bit confused and I spent a certain amount of time wondering if they mean the accepted answer is risky. I just want to point out the answer says to "include [ActionDispatch::TestProcess::FixtureFile](https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/testing/test_process.rb#L8)", **not** its parent `ActionDispatch::TestProcess`. Just be careful and import only what you need. The accepted answer seems not risky to me . I hope my comment helps to clarify the situation somehow. – Mason Aug 10 '23 at 01:19
4

Adding the following initializer addresses the issue without potential side-effects of including the ActionDispatch::TestProcess::FixtureFile module.

# config/initializers/rspec.rb

module RSpec
  module Rails
    module FixtureFileUploadSupport
      class RailsFixtureFileWrapper
        class << self
          attr_accessor :file_fixture_path
        end
      end
    end
  end
end

This is how the issue is actually fixed by RSpec maintainers. As of the date of this post, the patch is not yet released.

1

I was having the same issue for a long time and kept landing on this SO answer. My problem was that in a lot of my specs, one of my FactoryBot factories was calling fixture_file_upload and nothing suggested here fixed the issue.

I went into the ActionDispatch code and found that in the ActionDispatch::TestProcess::FixtureFile module's fixture_file_upload method, the factory object was queried for its fixture_path attribute, which it doesn't have. This is why the answer by @murb will work if your fixture_file_upload is within a spec file, but not in a factory file. For me, the answer was to add the following code to spec/support/factory_bot.rb in my Rails project:

FactoryBot::SyntaxRunner.instance_eval do
  def fixture_path
    File.absolute_path('spec/fixtures/files')
  end

  def file_fixture_path
    'spec/fixtures/files'
  end
end

Note that the second method (file_fixture_path) is to silence the warning in ActionDispatch::TestProcess::FixtureFile#fixture_file_upload.

I hope this helps someone, took me and another engineer a couple of days to land on this solution.

ewhiting
  • 244
  • 1
  • 10
0

After changing to file_fixture it works just fine relishapp.com/rspec/rspec-rails/v/3-8/docs/file-fixture

mingle
  • 1,567
  • 1
  • 16
  • 19
  • 3
    Has not worked for me `undefined method `file_fixture' for # – Qwertie Sep 14 '21 at 03:53
  • I guess it will resolve, I had the same problem https://github.com/thoughtbot/factory_bot/issues/385#issuecomment-439040731 – Alex Jul 18 '22 at 12:01