Skip to content

Instantly share code, notes, and snippets.

@cupakromer
Created July 25, 2014 16:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cupakromer/fc5ccd67714c878dd5d8 to your computer and use it in GitHub Desktop.
Save cupakromer/fc5ccd67714c878dd5d8 to your computer and use it in GitHub Desktop.
Sample model spec using RSpec 3.0 and Ruby 2.x
require 'rails_helper'
RSpec.describe User, type: :model do
def build_valid_user(opts = {})
valid_opts = {
name: "Example User",
email: "user@example.com",
password: "foobar",
password_confirmation: "foobar",
}
User.new valid_opts.merge(opts)
end
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(:authenticate) }
context "given a valid user" do
subject(:any_valid_user) { build_valid_user }
it { should be_valid }
end
context "validations" do
subject(:a_user) { build_valid_user }
before do
expect(a_user).to be_valid, "PRECONDITION FAILED: User is not valid!"
end
it "requries a name" do
expect{ a_user.name = " " }.to change(a_user, :valid?).to(false)
end
it "requires an email" do
expect{ a_user.email = " " }.to change(a_user, :valid?).to(false)
end
it "requires a name less than 51 characters" do
expect{ a_user.name = "a" * 51 }.to change(a_user, :valid?).to(false)
end
context "verifies the email format" do
# In general, using a Regex for validating an email is horribly broken.
# Email addresses can have many different things. Additionally, there's
# nothing a regex can do to verify that the email account is even open.
#
# Generally, in our apps we do not validate emails outside of forcing it
# as part of the sign-up process. Thus it has to be a live email for at
# least part of the time.
it "does not allow symbols in the domain" do
expect{ a_user.email = "user@foo,com" }
.to change(a_user, :valid?).to(false)
end
it "requires an @ symbol between address and domain" do
expect{ a_user.email = "user_at_foo.org" }
.to change(a_user, :valid?).to(false)
end
it "requires an TLD in the domain" do
expect{ a_user.email = "example.user@foo." }
.to change(a_user, :valid?).to(false)
end
end
it "requires a unique email address" do
_an_existing_user = a_user.dup
expect{ _an_existing_user.save! }.to change(a_user, :valid?).to(false)
end
it "requires a password" do
expect{ a_user.password = " " }.to change(a_user, :valid?).to(false)
end
it "requires the password to match the confirmation password" do
expect{ a_user.password_confirmation = "mismatch" }
.to change(a_user, :valid?).to(false)
end
it "requires a password longer than 5 characters" do
expect{ a_user.password = a_user.password_confirmation = "a" * 5 }
.to change(a_user, :valid?).to(false)
end
end
context "valid email format" do
# ... one spec per email format
end
context "authenticating a user" do
# Note I only extracted these lets and before **AFTER** I wrote the
# following three specs with these as local variables. I then made the
# decision that yes these could all "be the exact same user", meaning I
# could extract them.
let(:any_password) { 'this is not a good password' }
let(:any_valid_email) { 'any_email@example.com' }
let(:existing_user) {
build_valid_user(
email: any_valid_email,
password: any_password,
)
}
before { existing_user.save! }
it "passes given valid authentication credentials" do
registered_email, matching_password = any_valid_email, any_password
expect(
User.authenticate(email: registered_email, password: matching_password)
).to eq existing_user
end
context "with invalid credentials", "no matching email" do
matching_password = any_password
bad_email = 'tricky@hobbits.com'
expect(
User.authenticate(email: bad_email, password: matching_password)
).to be false
end
context "with invalid credentials", "no matching password" do
registered_email = any_valid_email
different_password = 'try all the combos!'
expect(
User.authenticate(email: registered_email, password: different_password)
).to be false
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment