Reputation: 918
I am testing to build user authentication from scratch.
I started by testing and setting up validations and they all passed. Once I added the format: { with: ... }
method, my test suite broke.
Here's the failure along with the code:
Failures:
1) User validations requires an email
Failure/Error: expect(user).to validate_presence_of(:email)
NoMethodError:
undefined method `validate_presence_of' for #<RSpec::ExampleGroups::User::Validations:0x007fae7f5551b0>
# ./spec/models/user_spec.rb:14:in `block (3 levels) in <top (required)>'
2) User validations requires a unique email
Failure/Error: expect(user).to validate_uniqueness_of(:email)
NoMethodError:
undefined method `validate_uniqueness_of' for #<RSpec::ExampleGroups::User::Validations:0x007fae83193b90>
# ./spec/models/user_spec.rb:18:in `block (3 levels) in <top (required)>'
3) User validations requires a unique email (case insensitive)
Failure/Error: expect(user).to validate_uniqueness_of(:email)
NoMethodError:
undefined method `validate_uniqueness_of' for #<RSpec::ExampleGroups::User::Validations:0x007fae83168670>
# ./spec/models/user_spec.rb:23:in `block (3 levels) in <top (required)>'
Finished in 0.04888 seconds (files took 1.2 seconds to load)
6 examples, 3 failures
spec/models/user_spec.rb
require 'rails_helper'
RSpec.describe User, :type => :model do
let(:valid_attr) { attributes_for(:user) }
context "validations" do
let(:user) { User.new(valid_attr) }
before do
User.create(valid_attr)
end
it "requires an email" do
expect(user).to validate_presence_of(:email)
end
it "requires a unique email" do
expect(user).to validate_uniqueness_of(:email)
end
it "requires a unique email (case insensitive)" do
user.email = "[email protected]"
expect(user).to validate_uniqueness_of(:email)
end
it "requires the email to look like an email" do
user.email = "brown"
expect(user).to_not be_valid
end
end
describe "#downcase_email" do
it "makes the email attribute lowercase" do
user = User.new(valid_attr.merge(email: "[email protected]"))
expect{ user.downcase_email }.to change{ user.email }.
from("[email protected]").
to("[email protected]")
end
it "downcases an email before saving" do
user = build(:user)
user.email = "[email protected]"
expect(user.save).to be true
expect(user.email).to eq("[email protected]")
end
end
end
Factory Girl users.rb
FactoryGirl.define do
factory :user do
first_name "Charlie"
last_name "Brown"
email "[email protected]"
password "charbar1234"
password_confirmation "charbar1234"
end
end
models/user.rb
class User < ActiveRecord::Base
has_secure_password
validates :email, presence: true,
uniqueness: true,
format: {
with: /\A[A-Za-z0-9._%+-]+@[A-Za-z0-9\.-]+\.[A-Za-z]+\Z/
}
before_save :downcase_email
def downcase_email
self.email = email.downcase
end
end
Upvotes: 1
Views: 1337
Reputation: 207
A better way is to use the URI object:
validates_format_of :website_url, with: URI.regexp
Upvotes: 1
Reputation: 4808
Rspec is probably confused by this extra format parameter so it cannot dynamically create the validates_*_of
methods properly. You could either rewrite your test to be more direct:
it "requires an email" do
expect(user).to be_valid
# other test on error message here perhaps?
end
or put the format parts on its own validates line:
validates :email, presence: true, uniqueness: true
validates :email, format: {
with: /\A[A-Za-z0-9._%+-]+@[A-Za-z0-9\.-]+\.[A-Za-z]+\Z/
}
Upvotes: 1