From 28e2242c40fe08ca37581bcb91c06b59b41ddb1b Mon Sep 17 00:00:00 2001 From: Giuliano De La Penna Date: Fri, 24 May 2019 12:40:33 -0300 Subject: [PATCH] Added specs for ApiLoginManager, User model and Post model --- spec/factories/posts.rb | 5 ++ spec/models/post_spec.rb | 26 ++++++++++ spec/models/user_spec.rb | 24 ++++++++++ spec/services/api_login_manager_spec.rb | 64 ++++++++++++++++++------- 4 files changed, 103 insertions(+), 16 deletions(-) diff --git a/spec/factories/posts.rb b/spec/factories/posts.rb index 402d675..dadce03 100644 --- a/spec/factories/posts.rb +++ b/spec/factories/posts.rb @@ -1,3 +1,8 @@ FactoryBot.define do # Implementar factory + factory :post do + title { Faker::Lorem.sentence } + body { Faker::Lorem.paragraph } + user + end end diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index 2162433..e4fc817 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -3,4 +3,30 @@ RSpec.describe Post, type: :model do # En base al modelo de test propuesto para el modelo User, # implementar los tests para el modelo Post. + describe 'Factory' do + it 'has a valid factory' do + # Testear que el factory definido es válido. + expect(FactoryBot.create(:post)).to be_valid + end + end + + describe 'Associations' do + # Testear asociaciones (shoulda-matchers). + # https://github.com/thoughtbot/shoulda-matchers#activerecord-matchers + it { is_expected.to belong_to(:user) } + end + + describe 'Presence validations' do + # Testear validaciones de presencia (shoulda-matchers). + # https://github.com/thoughtbot/shoulda-matchers#activemodel-matchers + it { is_expected.to validate_presence_of(:title) } + it { is_expected.to validate_presence_of(:body) } + end + + describe 'Uniqueness validations' do + # Testear validaciones de unicidad (shoulda-matchers). + # https://github.com/thoughtbot/shoulda-matchers#activemodel-matchers + let!(:subject) { FactoryBot.create(:post) } + it { is_expected.to validate_uniqueness_of(:title) } + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 4db8f67..a4382e3 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -4,31 +4,40 @@ describe 'Factory' do it 'has a valid factory' do # Testear que el factory definido es válido. + expect(FactoryBot.create(:user)).to be_valid end end describe 'Associations' do # Testear asociaciones (shoulda-matchers). # https://github.com/thoughtbot/shoulda-matchers#activerecord-matchers + it { is_expected.to have_many(:posts).dependent(:destroy) } end describe 'Presence validations' do # Testear validaciones de presencia (shoulda-matchers). # https://github.com/thoughtbot/shoulda-matchers#activemodel-matchers + it { is_expected.to validate_presence_of(:email) } + it { is_expected.to validate_presence_of(:password) } + it { is_expected.to validate_presence_of(:role) } end describe 'Uniqueness validations' do # Testear validaciones de unicidad (shoulda-matchers). # https://github.com/thoughtbot/shoulda-matchers#activemodel-matchers + let!(:subject) { FactoryBot.create(:user) } + it { is_expected.to validate_uniqueness_of(:email) } end describe 'Length validations' do # Testear validaciones de longitud (shoulda-matchers). # https://github.com/thoughtbot/shoulda-matchers#activemodel-matchers + it { is_expected.to validate_length_of(:password).is_at_least(8) } end describe 'Enumeratives' do # Testear definición de enumerativos (shoulda-matchers). + it { is_expected.to define_enum_for(:role).with([:admin, :regular])} end # Testear métodos de instancia y de clase como para el caso de cualquier @@ -37,5 +46,20 @@ # Testear funcionamiento de método. Podemos definir dos contexts: # - 'when given value is different from password' # - 'when given value is equal to password' + context 'when given value is different from password' do + let!(:subject) { FactoryBot.create(:user, password: 'password') } + + it 'returns false' do + expect(subject.valid_password?('passw0rd')).to be false + end + end + + context 'when given value is equal to password' do + let!(:subject) { FactoryBot.create(:user, password: 'password') } + + it 'returns true' do + expect(subject.valid_password?('password')).to be true + end + end end end diff --git a/spec/services/api_login_manager_spec.rb b/spec/services/api_login_manager_spec.rb index 5ea0316..ce2cf15 100644 --- a/spec/services/api_login_manager_spec.rb +++ b/spec/services/api_login_manager_spec.rb @@ -9,14 +9,21 @@ # utilizarla. Es por eso que conviene usarla desde una variable con # let!(:password) { SecureRandom.hex }. Al crear el usuario, # en let!(:user) { ... }, usar esta variable. + EMPTY_EMAIL = 'El email no puede estar en blanco.'.freeze + EMPTY_PASSWORD = 'La contraseña no puede estar en blanco.'.freeze + USER_NOT_FOUND = 'El usuario no existe'.freeze + WRONG_PASSWORD = 'La contraseña es incorrecta'.freeze + EXTERNAL_VALIDATOR = 'El usuario ya no tiene cuota disponible'.freeze + let!(:password) { SecureRandom.hex } - let!(:user) { } # -- crear usuario con FactoryBot -- # + let!(:user) { FactoryBot.create(:user, password: password) } # -- crear usuario con FactoryBot -- # describe '#call' do context 'when user provided data is valid' do before do # Realizar un stub del ExternalValidator para que se ejecuta realmente + allow(ExternalValidator).to receive(:call).and_return(true) end subject do @@ -24,64 +31,89 @@ end it "update user's auth_token" do - skip 'Una vez que definan a user, este test va a fallar. ¿Por qué?' - expect { subject }.to change { user.auth_token } + # skip 'Una vez que definan a user, este test va a fallar. ¿Por qué?' + # Por dos cosas: primero, un usuario creado sin parámetros recibirá una password + # generada que nunca sabremos cuál es, por lo que hay que crearlo con una pass + # conocida (la definida al comienzo del test). Segundo, si no se recarga el + # registro desde la base de datos, el cambio no se verá reflejado. + expect { subject }.to change { user.reload.auth_token } end it 'returns the auth_token' do - skip 'Implementar' + expect(subject).to eq(user.reload.auth_token) end end context 'when no email is provided' do - subject { } # implementar + subject { described_class.new(password: password) } it 'returns false' do - skip 'Implementar' + expect(subject.call).to eq(false) end it 'returns EMPTY_EMAIL error with a reader' do - skip 'Implementar' + subject.call + expect(subject.error).to eq(EMPTY_EMAIL) end end context 'when no password is provided' do - subject { } # implementar + subject { described_class.new(email: user.email) } it 'returns false' do - skip 'Implementar' + expect(subject.call).to eq(false) end it 'returns EMPTY_PASSWORD error with a reader' do - skip 'Implementar' + subject.call + expect(subject.error).to eq(EMPTY_PASSWORD) end end context 'when the email is incorrect' do - subject { } # implementar + subject { described_class.new(email: 'wrong@email.com', password: password) } it 'returns false' do - skip 'Implementar' + expect(subject.call).to eq(false) end it 'returns USER_NOT_FOUND error with a reader' do - skip 'Implementar' + subject.call + expect(subject.error).to eq(USER_NOT_FOUND) end end context 'when the password is incorrect' do - subject { } # implementar + subject { described_class.new(email: user.email, password: 'wrong_pass') } it 'returns false' do - skip 'Implementar' + expect(subject.call).to eq(false) end it 'returns WRONG_PASSWORD error with a reader' do - skip 'Implementar' + subject.call + expect(subject.error).to eq(WRONG_PASSWORD) end end # Definir un nuevo context para cuando la conexión # con ExternalValidator falla. Acá los quiero ver... + + context 'when ExternalValidator fails' do + subject { described_class.new(email: user.email, password: password) } + + before do + allow(ExternalValidator).to receive(:call).and_return(false) + end + + it 'returns false' do + expect(subject.call).to eq(false) + end + + it 'returns WRONG_PASSWORD error with a reader' do + subject.call + expect(subject.error).to eq(EXTERNAL_VALIDATOR) + end + end end end