Testing Paperclip file uploading with RSpec - ruby-on-rails

I don't really care about testing file uploads, but since I have validates_attachment_presence, etc.. in my model, rspec is complaining.
So now I'm creating my model with these attributes in the spec to try and shut it up:
#attr = {
:name => "value for name",
:title => "value for title",
:content => "value for content",
:pic_file_name => "example.jpg",
:pic_content_type => "image/jpg",
:pic_file_size => "8192",
:pic_updated_at => nil
}
This doesn't work, though.
I found this: http://fr.ivolo.us/posts/mocking-paperclip-with-rspec
So I tried something like this:
Post.should_receive(:save_attached_files).and_return(true)
Which doesn't work either. How do I appease RSpec?

If the model has_attached_file :pic, you should be able to just point the pic attribute at some file and all should be dandy.
Meaning something like #attr = { :pic => File.open(File.join(Rails.root, 'spec', 'fixtures', 'file.png')) }

Related

Paperclip Content Type Validation Failing in Rspec

I'm using Rails 4.0.0 with Paperclip 4.1.1 for attaching mp3 and pdf files. I'm writing my integration tests in Rspec with Capybara.
I have content type and file name validations in place for both types of files.
class Song < ActiveRecord::Base
validates :title, presence: true
validates :writeup, presence: true
has_attached_file :mp3
validates_attachment :mp3,
:content_type => { :content_type => "audio/mp3" },
:file_name => { :matches => [/mp3\Z/] }
has_attached_file :chords
validates_attachment :chords,
:content_type => { :content_type => 'application/pdf' },
:file_name => { :matches => [/pdf\Z/] }
end
I use this in my integration test to fill in attributes for a valid song:
def fill_in_valid_song
fill_in("Title", with: "Valid Song")
fill_in("Writeup", with: "Description of song")
attach_file("Mp3", File.join(Rails.root, "/spec/factories/Amazing_Grace.mp3" ))
attach_file("Chords", File.join(Rails.root, "/spec/factories/FakeChordChart.pdf" ))
end
When I run the integration test for creating a valid song, the pdf file is accepted, but the mp3 file fails the content type validation.
When I follow the same steps myself in the browser, the song uploads successfully without errors. The model spec also passes using the same file.
I thought the problem might be the capital "M" in "Mp3" when I attach the file, but this is just to specify which file field the attachment goes with. When I tried changing it to a lowercase "m", the error changed to Capybara not being able to find the field.
Change the content type validation for the mp3 file to be:
validates_attachment :mp3,
:content_type => { :content_type => ["audio/mpeg", "audio/mp3"] },
:file_name => { :matches => [/mp3\Z/] }
The RFC defined MIME type for mp3 files is audio/mpeg. However some browsers load them as audio/mp3 which is probably why it works through the browser.
If this doesn't work you could also add audio/mpeg3 and audio/x-mpeg-3 as I've seen these used too.

how can I define a specil struct by factory girl?

Using RSpec and Factory Girl, I create a factory like this:
factory :hot_type do
ad_type_id 4
city_id 110000
image "111"
content { :link_url => 'xxx', :link_title => 'xxx', :count => 11 }
end
when I ran the rspec, it happened an error:
syntax error, unexpected ',', expecting '}'
content { :link_url => 'xx', :link_title => '1xx', :count => 11 }
How can I define the right struct?
Ruby interprets space + {} as a block. You need you specify the hash as arguments explicitly. Just use brackets around it.
content({ :link_url => 'xx', :link_title => '1xx', :count => 11 })

How do I get Paperclip to recognize custom processors instead of just pushing styles through to thumbnail?

I am not having any problem getting the custom processor to load, however when I try to call it from has_attached_file, paperclip ignores it, and instead just runs thumbnail.
model
has_attached_file :file,
:styles => { :web => "some input" },
:processors => [ :custom ],
:url => ":class/:id/:style/:basename.:extension",
:path => ":class/:id/:style/:basename.:extension"
:storage => :s3
As simple a processor as can be made just to show that the processor has been run
processor.rb
module Paperclip
class Custom < Processor
attr_accessor :input
def initialize(file, options = {}, attachment = nil)
super
#basename = File.basename(file.path, File.extname(file.path))
end
def make
dst = Tempfile.new([ #basename, 'jpg' ].compact.join("."))
dst
end
end
end
But instead when I check the saved record it returns instance variables from thumbnail
>record.file.styles
{:web=>
#<Paperclip::Style:0x00000102f185d0
#attachment=
http://s3.amazonaws.com/bucket/model/id/base_name/file_name.jpg,
#format=nil,
#geometry="some_input",
#name=:web,
#other_args={}>}
I must be missing something in either writing the processor or calling it. Any idea what is going on here?
Have you tried something like this?
has_attached_file :file,
:styles => {
:my_super_style => {:geometry => "100x100#", :foo => "bar", :processors => [:custom]}
},
Have you put in the right place?
lib/paperclip_processors/custom.rb
:styles => { :web => "some input" },
:processors => [ :custom ],
should be:
:styles => {
:web => {:geometry => "some input", :processors => [:custom]},

Error while testing assets : can't dup NilClass

I'm using rails 3.0.9 with ruby 1.9.2. I am doing a system that allow users to put items into different closets. One of the user's possibility is to copy an item of an other user into his own closet (please tell me if you don't understand, I'm not good in explaining things..).
To handle images, I'm using paperclip 2.3.16. I'm testing my app with Rspec-rails 2.6.1, Cucumber-rails 1.0.2. When I run my tests with guard & spork on the asset's copy part, i'm having a "TypeError: can't dup NilClass". I've search on the net for an answer but didn't find anything specific and working :(.
Have you an idea about this issue ?
My code for closet_spec.rb (if you need something else, just tell me) :
describe '#tidy_up' do
let!(:other_user) { Factory.create(:confirmed_user, :user_name => 'Plop', :email => 'coin#plop.fr') }
let!(:closet) { other_user.closets.first }
let!(:item) { Item.create! :type_id => 42, :closet_id => dream_dressing.id }
let!(:dressing_item) { Item.create! :type_id => 42, :closet_id => dressing.id }
before do
path = File.join(Rails.root, "spec", "support", 'image.jpg')
f = File.open(path)
2.times.map do |n|
i = Item.new :type_id => 2#, :asset => Asset.new(picture)
i.save!
puts ">>>>>>>>>>>>>>>>>>>>> #{i.id}"
i.build_asset(:picture => f)
closet.items << i
end
#count = 0
end
it 'copies given items and assets to closet' do
expect { dream_dressing.tidy_up closet.items }.to change { dream_dressing.items.count }.by 2
expect { dream_dressing.tidy_up closet.items }.to change { dream_dressing.items.map{|i| i.asset; puts ">>>>>>>>>>>>>>>>> asset : #{i.asset} " }.length }.by 2
end

Why is this RSpec test failing?

I'm in the process of learning Ruby on Rails, so treat me like a total neophyte, because I am.
I've got a User model with some associated RSpec tests, and the following test fails:
require 'spec_helper'
describe User do
it 'should require a password' do
User.new({:email => 'valid_email#example.com', :password => '', :password_confirmation => ''}).should_not be_valid
end
end
The relevant part of the User model looks like this:
class User < ActiveRecord::Base
...
validates :password, :presence => true,
:confirmation => true,
:length => { :minimum => 6 }
...
end
Here's the catch: if I run User.new(...).valid? from a Rails console using the arguments above, it returns false as expected and shows the correct errors (password is blank).
I was using spork/autotest and I restarted both to no avail, but this test also fails even running it directly with rspec. What am I doing wrong here?
EDIT
I tried a few more things with the test. This fails:
u = User.new({:email => 'valid_email#example.com', :password => '', :password_confirmation => ''})
u.should_not be_valid
So does this:
u = User.new({:email => 'valid_email#example.com', :password => '', :password_confirmation => ''})
u.valid?
u.errors.should_not be_empty
This passes, confirming that :password is indeed blank:
u = User.new({:email => 'valid_email#example.com', :password => '', :password_confirmation => ''})
u.password.should == ''
So, it's actually spork that is causing the problem. You can turn caching off, so that it won't need restarting every time :
http://ablogaboutcode.com/2011/05/09/spork-testing-tip-caching-classes
I think this is what happens :
ruby-1.9.2-p180 :020 > u = User.new
=> #<User id: nil, email: ...
ruby-1.9.2-p180 :021 > u.errors
=> {}
ruby-1.9.2-p180 :022 > u.save
=> false
ruby-1.9.2-p180 :023 > u.errors
=> {:email=>["can't be blank", "can't be blank"], ...}
In short, if you change new to create, it will work :) I think that this happens because the matcher be_valid checks on the model validation errors. There can be a deeper explanation, but i think that if you use create instead of new, it will work.
EDIT : I have a be_valid_verbose version that might help. Just create a 'be_valid_verbose.rb' file in your rspec/custom_matchers folder, and inside it write :
RSpec::Matchers.define :be_valid_verbose do
match do |model|
model.valid?
end
failure_message_for_should do |model|
"#{model.class} expected to be valid but had errors:n #{model.errors.full_messages.join("n ")}"
end
failure_message_for_should_not do |model|
"#{model.class} expected to have errors, but it did not"
end
description do
"be valid"
end
end
Now check against be_valid_verbose instead of be_valid. It will hopefully present you with some more information on what is happening in your case.
As I feared, the answer was stupidity. This was a spork problem. I thought I had killed the existing process and was running rspec independently, but I later found the spork process still running in a different shell, and rspec had been connecting to it all along. Restarting spork (or killing it entirely) and re-running the tests fixed the problem.
I found this particularly deceptive in that rspec continually updated the test output to reflect the fact that it was aware of my test changes, so it appeared to me that it was running against up-to-date code. Now I'm left to wonder what the real utility of spork is, since apparently I can't trust that it's actually running the right tests correctly.

Resources