Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions spec/factories/posts.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
FactoryBot.define do
# Implementar factory
factory :post do
title { Faker::Lorem.sentence }
body { Faker::Lorem.paragraph }
user
end
end
26 changes: 26 additions & 0 deletions spec/models/post_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Podemos aprovechar una configuración que agregamos en spec/rails_helper.rb por la cual no hace falta agregar el FactoryBot. a estos métodos.

La línea en cuestión es la siguiente:

config.include FactoryBot::Syntax::Methods

Además, pese a que el test pasa y está bien, podemos usar un build para no persistir al Post en la base de datos (para mejorar la performance). De todas formas, el build persiste aquellas asociaciones que tenga definido el factory, por lo cual podemos usar uno mejor: build_stubbed. En la próxima clase lo vemos.

expect(build_stubbed(: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) }

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternativamente podemos usar subject:

subject { create(:post) }

it { is_expected.to validate_uniqueness_of(:title) }
end
end
24 changes: 24 additions & 0 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misma consideración para el test de factory del modelo Post. Igualmente está bien.

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) }

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misma consideración para el test similar del modelo Post. Igualmente está bien.

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
Expand All @@ -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') }

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tanto para este caso como para el del siguiente context, creo que en lugar de hacer let!(:subject) haría subject directamente. De todas formas el uso de let! también está bien.

Podría ser de la siguiente forma:

context 'when given value is different from password' do
  subject { create(:user, password: 'password') }
  ...
end


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
64 changes: 48 additions & 16 deletions spec/services/api_login_manager_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,79 +9,111 @@
# 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
described_class.new(email: user.email, password: password).call
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)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

En el ejemplo de arriba el subject es la aplicación de call sobre la instancia, mientras que en éste es la instancia, y luego le mandás el mensaje call en el it. Ambas están bien, pero sería preferente usar una convención.

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