Reputation: 241
I am testing the carrierwave upload functionality using rspec and capybara. I have something like:
describe "attachment" do
let(:local_path) { "my/file/path" }
before do
attach_file('Attachment file', local_path)
click_button "Save changes"
end
specify {user.attachment.should_not be_nil}
it { should have_link('attachment', href: user.attachment_url) }
end
And this works great. The problem is that after testing the uploaded image remains in my public/uploads directory. How can I remove it after the test is done? I tried something like this:
after do
user.remove_attachment!
end
but it did not work.
Upvotes: 1
Views: 4198
Reputation: 481
A cleaner solution that seems to work for me is the following in spec/support/carrierwave.rb
:
uploads_test_path = Rails.root.join('uploads_test')
CarrierWave.configure do |config|
config.root = uploads_test_path
end
RSpec.configure do |config|
config.after(:suite) do
FileUtils.rm_rf(Dir[uploads_test_path])
end
end
This would set the whole root folder specific to the test environment and delete it all after the suite, so you do not have to worry about store_dir
and cache_dir
separately.
Upvotes: 4
Reputation: 3103
The latest CarrierWave documentation for this technique is as follows:
config.after(:suite) do
if Rails.env.test?
FileUtils.rm_rf(Dir["#{Rails.root}/spec/support/uploads"])
end
end
Note that the above simply assumes youre using spec/support/uploads/
for images and you dont mind deleting everything in that directory. If you have different locations for each uploader, you may want to derive the upload and cache directories straight from the (factory) model:
config.after(:suite) do
# Get rid of the linked images
if Rails.env.test? || Rails.env.cucumber?
tmp = Factory(:brand)
store_path = File.dirname(File.dirname(tmp.logo.url))
temp_path = tmp.logo.cache_dir
FileUtils.rm_rf(Dir["#{Rails.root}/public/#{store_path}/[^.]*"])
FileUtils.rm_rf(Dir["#{temp_path}/[^.]*"])
end
end
or, if you want to delete everything under the CarrierWave root that you set in an initializer, you can do this:
config.after(:suite) do
# Get rid of the linked images
if Rails.env.test? || Rails.env.cucumber?
FileUtils.rm_rf(CarrierWave::Uploader::Base.root)
end
end
Upvotes: 0
Reputation: 509
Ha! I found the answer to this today.
The auto-removal of the downloaded file is done in an after_commit hook. These do not get run by default in rails tests. I never would have guessed that.
It is however documented offhandedly in a postscript note here: http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#method-i-after_commit
I discovered this by deep diving into the carrierwave code with a debugger and just happened to notice it in the comments above the source code to after_commit when I stepped into it.
Thank goodness ruby libraries are not stripped of comments at runtime like JS. ;)
The workaround suggested in the docs is to include the 'test_after_commit' gem in your Gemfile BUT ONLY IN THE TEST ENVIRONMENT.
i.e.
Gemfile:
...
gem 'test_after_commit', :group => :test
...
When I did this, it completely solved the problem for me.
Now, my post-destruction assertions of cleanup pass.
Upvotes: 0
Reputation: 115531
You're not the only one having issues to delete the files in carrierwave.
I ended up doing:
user.remove_attachment = true
user.save
I got this tip reading this.
Upvotes: 5