Reputation: 1418
I have just switched to using ActiveStorage on rails 5.1.4 and I am new to TDD and struggling to figure out how to test a model that has_one_attached :avatar
require 'rails_helper'
RSpec.describe User, :type => :model do
let (:valid_user) { FactoryBot.build(:user) }
describe "Upload avatar" do
context "with a valid image" do
it "saves the image" do
valid_user.save!
saved_file = valid_user.avatar.attach(io: File.open("/home/ubuntu/workspace/spec/fixtures/files/avatar.jpg"), filename: "face.jpg", content_type: "image/jpg")
expect(saved_file).to be_an_instance_of(ActiveStorage::Attachment::One)
end
end
end
end
But I am getting the following error:
Failures:
1) User Upload avatar with a valid image saves the image
Failure/Error:
saved_file = valid_user.avatar.attach(io: File.open("/home/ubuntu/workspace/spec/fixtures/files/avatar.jpg"), filename: "face.jpg",
content_type: "image/jpg")
NoMethodError:
undefined method `upload' for nil:NilClass
Did you mean? load
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/blob.rb:48:in `upload'
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/blob.rb:21:in `block in build_after_upload'
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/blob.rb:16:in `tap'
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/blob.rb:16:in `build_after_upload'
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/blob.rb:26:in `create_after_upload!'
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/attached.rb:25:in `create_blob_from'
# /usr/local/rvm/gems/ruby-2.3.4/gems/activestorage-0.1/lib/active_storage/attached/one.rb:9:in `attach'
# ./spec/models/user_spec.rb:47:in `block (4 levels) in <top (required)>'
Any hints?
Upvotes: 50
Views: 31997
Reputation: 29
In my case, I have used rails shoulda gem
it { should have_one_attached(:image) }
Upvotes: 2
Reputation: 17
Rspec.describe User, type: :model do
describe 'relations' do
it { is_expected.to have_one_attached(:avatar_attachment) }
end
end
Upvotes: -1
Reputation: 463
With some help of these post I did an update of rspec test for active storage at rails 6.1
# .\spec\models\activestorage_spec.rb
require 'rails_helper'
RSpec.describe User, :type => :model do
before(:each) do
@user = FactoryBot.create(:user)
@user.save!
saved_file = @user.pictures.attach(io: File.open("./storage/test.jpg"), filename: "test.jpg", content_type: "image/jpg")
end
describe "Upload picture" do
context "with a valid picture" do
it "saves the picture" do
expect(@user.pictures).to be_attached
end
end
end
end
Now you can only add some more tests
Upvotes: 5
Reputation: 332
I was running into a similar nil error (Module::DelegationError: to_model delegated to attachment, but attachment is nil), but it was only occurring when multiple tests were using the same factory.
The problem appears to be that the cleanup from the previous test's teardown was deleting the file after it was attached on the next factory call. The key was updating the ActiveJob queue adapter to inline so that the file would be deleted right away.
Add both of these settings to config/environments/test.rb:
# Use inline job processing to make things happen immediately
config.active_job.queue_adapter = :inline
# Store uploaded files on the local file system in a temporary directory.
config.active_storage.service = :test
Upvotes: 7
Reputation: 1732
Why not:
RSpec.describe User, type: :model do
describe 'relations' do
it { is_expected.to have_one(:avatar_attachment) }
end
end
Upvotes: 0
Reputation: 301
Here is how I solved it
# model
class Report < ApplicationRecord
has_one_attached :file
end
# factory
FactoryBot.define do
factory :report, class: Report do
any_extra_field { 'its value' }
end
end
# spec
require 'rails_helper'
RSpec.describe Report, type: :model do
context "with a valid file" do
before(:each) do
@report = create(:report)
end
it "is attached" do
@report.file.attach(
io: File.open(Rails.root.join('spec', 'fixtures', 'file_name.xlsx')),
filename: 'filename.xlsx',
content_type: 'application/xlsx'
)
expect(@report.file).to be_attached
end
end
end
I hope it help you
Upvotes: 13
Reputation: 266
In config/environments/test.rb
config.active_storage.service = :test
In your spec
it {expect(valid_user.avatar).to be_attached}
Upvotes: 3
Reputation: 499
I solved using
FactoryBot.define do
factory :culture do
name 'Soy'
after(:build) do |culture|
culture.image.attach(io: File.open(Rails.root.join('spec', 'factories', 'images', 'soy.jpeg')), filename: 'soy.jpeg', content_type: 'image/jpeg')
end
end
end
After
describe '#image' do
subject { create(:culture).image }
it { is_expected.to be_an_instance_of(ActiveStorage::Attached::One) }
end
Upvotes: 35
Reputation: 1418
Problem solved. After tracing the error to the ActiveStorage::Blob::upload method, where it said: Uploads the io to the service on the key for this blob.
I realized I had not set the active_storage.service for the Test environment. Simply put, just add:
config.active_storage.service = :test
To config/environments/test.rb file
Upvotes: 20