All rspec tests passing when they should not (Rails 3.2, Rspec) - ruby-on-rails

I'm building a daily deal rails app and I have followed M. Hartl tutorial to set some rspec tests.
For users they work perfectly.
But now I have used it for the model Eals and all are passing, when they shouldn't. For example, in my models, I put that titles can't be longer than 200 characters (note:on my view, when I try to set titles longer than this, it works and alerts me it's not possible)
But when I do tests no matter if I try for the title character length's test with long = "a" * 50, a * 201 or even a * 10000 in the title test, it always pass! There is a big problem I don't manage to find.
And actually all the other tests have the same problem: they always pass!
Here is my models/deal.rb
class Deal < ActiveRecord::Base
belongs_to :admin_user
attr_accessible :url_path,
:country,
:title,
:description,
:twitter_msg,
:admin_user_id
validates :url_path,
presence: true,
uniqueness: { :case_sensitive => false }
validates :country,
:inclusion => { :in => ['France', 'Germany', 'United States'],
:message => "%{value} is not a valid country. " }
validates :title,
presence: true,
length: { maximum: 200,
:message => "Your title has %{value} characters but must be shorter than 200 characters" }
validates :description,
presence: true,
length: { maximum: 500,
:message => "Your title has %{value} characters but must be shorter than 500 characters" }
validates :twitter_msg,
presence: true,
uniqueness: { :case_sensitive => false }
validates :admin_user_id, presence: true
And my deal_spec.rb:
require 'spec_helper'
describe Deal do
let(:admin_user) { FactoryGirl.create(:admin_user) }
before (:each) do
#attr = { url_path: "lorem ipsum",
country:"France",
title: "lorem ipsum",
description:"lorem ipsum",
twitter_msg:"lorem ipsum",
}
end
it { should respond_to(:url_path) }
it { should respond_to(:country) }
it { should respond_to(:title) }
it { should respond_to(:description) }
it { should respond_to(:twitter_msg) }
describe "title test" do
it "should reject deals with title that is too long" do
long = "a" * 50
hash = #attr.merge(:title => long)
Deal.new(hash).should_not be_valid
end
[other tests]
end #end of title test
If anybody can help me understand that, that would be great, I have been spending hours without any clue.
After following sb advice, I changed my test with
Deal.new(hash).should have(1).error_on(:title)
describe "test" do
it "should reject games with title that is too long" do
long = "a" * 250
hash = #attr.merge(:title => long)
Game.new(hash).should have(1).error_on(:title)
end
end
But now it's passing all the time, i.e it's telling me I have one error on title no matter if I put long= "a" * 5, long="a" * 300...

This is not the correct way to test validation using RSpec because it doesn't tell you why the object is invalid. It may be invalid because you're missing a totally different attribute that the one you're testing for. You should be using the have(x).errors_on(y) assertion:
Deal.new(hash).should have(1).error_on(:title)

I recommend using shoulda_matchers for testing such things

Could you please try the following code? It should give you a hint what attribute is invalid (and why):
it "..." do
d = Deal.new(#attr)
d.valid?
puts d.errors.full_messages
end

admin_user_id is not in your #attr hash. However it's mandatory on your Deal model - so your test always passes because the new deal is not valid. Nothing to do with the length of the title.

Related

set custom message in each different error validation in ruby on rails

let say that I have set in model for validation like this
validates :tel, presence: true , length: { minimum: 10, maximum: 11 }, numericality: { only_integer: true }
how do I can display a custom message in view for each validate.
when I set this in views page.
<% if #diary.errors.include?(:tel) %>
<div class="err"><p><%= #diary.errors.full_messages_for(:tel).join("") %></p></div>
<% end %>
it directly displays all error message. I want to make a display in view like this
if(error_require)
echo "tel is needed"
else if(error_length)
echo "tel is to long"
else
echo "tel must numeric"
end
can I make like that?
You can pass message in separate hashes for each validator:
validates :tel,
presence: { message: 'is needed' },
length: { minimum: 10, maximum: 11, too_long: 'is too long' },
numericality: { only_integer: true, message: 'must be numeric' }
Read more about presence, length, and numericality validators.
One way to do this is to define methods for each type of validation (in your model) like this:
validate :chech_length
def chech_length
if tel.length < 10 || tel.length > 11
errors.add(:base, "tel is too long!")
end
end
validate :check_if_present
def check_if_present
if tel.blank?
errors.add(:base, "tel must be present!")
end
end
etc...
Hope this helps.

Rspec test help - email uniqueness test failing yet it works in my app

I have been creating an application based on the Hartl course, and have added in the concept of Organization, which has_many users. The tests are all the standard tests Hartl recommends up to section 9.2 of the guide book. Since implementing Organizations into the application, one of the test cases is failing "when email address is already taken" - this should block a user from signing up with the same email address twice. What is odd is the fact that this is working in the application itself (form error - "users email address is already taken" thrown) but not in my tests. Can you help and indicate why this has broken please?
User code:
class User < ActiveRecord::Base
belongs_to :organization
#accepts_nested_attributes_for :organization
before_save { self.email = email.downcase }
before_create :create_remember_token
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(?:\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
has_secure_password
validates :password, length: { minimum: 6 }
validates :organization, presence: true
Organization code:
class Organization < ActiveRecord::Base
validates :organization_name, presence: true, length: { maximum: 50 }, uniqueness: true
has_many :users, :inverse_of => :organization
accepts_nested_attributes_for :users
User spec:
require 'spec_helper'
describe User do
before do
#user = FactoryGirl.create(:user)
end
subject { #user }
it { should respond_to(:name) }
it { should respond_to(:email) }
it { should respond_to(:password_digest) }
it { should respond_to(:password) }
it { should respond_to(:password_confirmation) }
it { should respond_to(:remember_token) }
it { should respond_to(:authenticate) }
it { should be_valid }
...
describe "when email address is already taken" do
before do
user_with_same_email = #user.dup
user_with_same_email.email = #user.email.upcase
user_with_same_email.save
end
it { should_not be_valid }
end
Factory Girl Code:
FactoryGirl.define do
factory :organization do
organization_name "Example Org"
trait :wrong do
organization_name "Wrong Org"
end
trait :also_wrong do
organization_name "Another Wrong Org"
end
end
factory :user do
association :organization
name "Example Name"
email "email#example.com"
password "foobar"
password_confirmation "foobar"
trait :wrong_org do
association :organization, :factory => [:organization, :wrong]
end
trait :wrong_org2 do
association :organization, :factory => [:organization, :also_wrong]
end
end
end
The error thrown from the Rails console is as follows:
1) User when email address is already taken should not be valid
Failure/Error: it { should_not be_valid }
expected #<User id: 5287, name: "Example Name", email: "email#example.com", created_at: "2014-07-22 15:04:33", updated_at: "2014-07-22 15:04:33", password_digest: "$2a$04$jrxyuz9e574BoaAhZm6xkOUeAY5spyDut2CCEvAykMu...", organization_id: 5025, remember_token: "339dfafcac7bc5925dbf4e44f60a782f3bbbaa1b">.valid? to return false, got true
I've tried changing the code inside the test, but no matter what I do it keeps throwing an error. As mentioned above, when I open up the application in my local server I can use all functions, and when I try to sign up using a duplicate email address it won't let me. What's wrong with my test code?
The #user is completely valid:
You create your subject, #user. This is valid
You create the user_with_same_email
That user is not valid, because it has the same email as #user
Saving user_with_same_email returns false, but that is not checked in your test
The duplicate user is not saved in the db
The original user is still valid
A correct test would just #dupthe user (or make a new one with the same email), and then check that the new record is not valid.

How to make factory girl create a date?

Updated
I'm trying to get Factory Girl to fill my "Release Date" field with a date, a random date, frankly any date right now because I keep getting " Validation failed: Release date can't be blank" errors when I run my item_pages_spec.rb
After some help below, his is what I have in my factories.rb for item pages but I've tried a lot of different things now.
factory :item do
sequence(:name) { |n| "Item #{n}" }
release_date { rand(1..100).days.from_now }
end
Ideally it would be a line that creates different random dates for each factory made instance of an item.
The release date can't be blank because I have validates :release_date, presence: true in my item model. Ideally I'd have a validation there that makes sure any date supplied IS a date but also accepts NIL because I won't always have a date available.
Any help much appreciated. I couldn't find anything specific online about factory girl and dates.
Model
class Item < ActiveRecord::Base
validates :name, presence: true, length: { maximum: 50 }
validates :release_date, presence: true
end
Item_pages_spec.rb
require 'spec_helper'
describe "Item pages" do
subject { page }
describe "Item page" do
let(:item) { FactoryGirl.create(:item) }
before { visit item_path(item) }
it { should have_content(item.name) }
it { should have_title(item.name) }
end
end
The Faker gem has a very nice method for this:
Faker::Date.between(2.days.ago, Date.today)
This will set a date between now and 2 years from now, adjust params (or extract method) if needed:
factory :item do
sequence(:name) { |n| "Item #{n}" }
release_date do
from = Time.now.to_f
to = 2.years.from_now.to_f
Time.at(from + rand * (to - from))
end
end

Rspec test for validity of new object not passing

I worked through all of Michael Hartl's Ruby on Rails Tutorial with all the tests passing. Now that I'm going back and making changes to the site to suit my own needs, it's not as cut and dry as "the tests in this section aren't passing." I've created a new "Charity" object that is strongly based on Hartl's "Micropost" object. The only difference is that instead of having "content" the object has a :name, :description and :summary.
This is the code for the test that is failing, (specifically "it { should be_valid }") which is located in /charity_spec.rb:
require 'spec_helper'
describe Charity do
let(:user) { FactoryGirl.create(:user) }
before { #charity = user.charities.build(summary: "Lorem ipsum") }
subject { #charity }
it { should respond_to(:name) }
it { should respond_to(:user_id) }
it { should respond_to(:summary) }
it { should respond_to(:description) }
it { should respond_to(:user) }
its(:user) { should == user }
it { should be_valid }
...
The test actually passes at first, but once I add the validations to the charity.rb file, they return;
Failures:
1) Charity
Failure/Error: it { should be_valid }
expected valid? to return, true, got false
...
Here's the charity.rb:
class Charity < ActiveRecord::Base
attr_accessible :name, :description, :summary
belongs_to :user
validates :name, presence: true, length: { maximum: 40 }
validates :summary, presence: true
validates :description, presence: true
validates :user_id, presence: true
default_scope order: 'charities.created_at DESC'
end
I'm sure it's something stupid, but my understanding of everything is so weak I can't figure out what I'm doing wrong, my feeling is that it's something wrong with my factory, but I really don't know.
Here's my charity factory located in the factories.rb:
factory :charity do
name "Lorem ipsum"
summary "Lorem ipsum"
description "Lorem ipsum"
user
end
When I remove the :name, :summary, and :description validations from charity.rb, the test passes. For good measure, here's the beginning of my user.rb:
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
has_many :charities
has_many :microposts, dependent: :destroy
Use your factory to have a proper charity:
before { #charity = user.charities.build(FactoryGirl.attributes_for(:charity)) }
It failed because you validate presence of attributes which were not set like name
If you need more background on FactoryGirl, their documentation is really good.

why is rspec telling me that this user is valid

I have the following classes in Rails and am writing some rspec tests (any critiques are more than welcome as I'm a nOOb at rspec).
class User.rb
class User < ActiveRecord::Base
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, :presence => true ,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => true },
:on => :create
end
and in factories.rb
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "my-name#{n}" }
sequence(:email) { |n| "blue#{n}#12blue.com" }
end
end
and in my rspec (users_spec.rb):
require 'spec_helper'
describe User do
let(:user) { FactoryGirl.build(:user) }
it { user.should be_valid }
it { user.should be_a(User) }
it { user.should respond_to(:email) }
it { user.email = " " }
it { user.should_not be_valid } # this is causing the error
end
and get
1) User
Failure/Error: it { user.should_not be_valid }
expected valid? to return false, got true
But based upon the validates, user should be not be valid. What is going on here? What am I not getting (and I know it's my fault)?
thx
I assume that the test failure surprises you because you think the user email should be " ".
In rspec every example is independent. This means that anything you did in a previous example is forgotten.
In your case your second to last example runs, builds a new, valid activerecord user whose email is "blue4#12blue.com", overwrites that email with " " and then passes since it makes no assertions.
Then your last example runs, builds a new, valid activerecord user who's email is "blue5#12blue.com" and fails because the user is valid, it's email has not been overwritten.
You probably want something like this:
it 'should validate the email' do
user.email = " "
user.should_not be_valid
end

Resources