Rails unit test failing - ruby-on-rails

The following User test passes with no problem, the user is valid:
user_test.rb:
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def setup
#user = User.new(name: "Example User", email: "user#example.com", callsign: "example",
password: "foobar", password_confirmation: "foobar")
end
test "user should be valid" do
assert #user.valid?
end
end
User model:
class User < ActiveRecord::Base
attr_accessor :remember_token, :activation_token, :reset_token
has_many :personas, dependent: :destroy
has_secure_password
before_save do
email.downcase!
callsign.downcase!
end
before_create :create_activation_digest
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 }
VALID_CALLSIGN_REGEX = /\A[a-z\d\-.\_]+\z/i
validates :callsign, presence: true,
length: { maximum: 20 },
format: { with: VALID_CALLSIGN_REGEX },
uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6 }, allow_blank: true
def to_param
callsign
end
.
.
end
However, when I set up exactly the same user in the persona_test, the validation fails. (The persona validation fails too, each User has_many personas)
persona_test.rb:
require 'test_helper'
class PersonaTest < ActiveSupport::TestCase
def setup
#user = User.new(name: "Example User", email: "user#example.com", callsign: "example",
password: "foobar", password_confirmation: "foobar")
#persona = #user.personas.build(name: "Bazman", callsign: "Baz")
end
test "user should be valid" do
assert #user.valid?
end
test "persona should be valid" do
assert #persona.valid?
end
end
Persona model:
class Persona < ActiveRecord::Base
belongs_to :user
before_save do
self.callsign.downcase!
set_persona_id
end
validates :name, presence: true,
length: { maximum: 50 }
VALID_CALLSIGN_REGEX = /\A[a-z\d\-.\_]+\z/i
validates :callsign, presence: true,
length: { maximum: 20 },
format: { with: VALID_CALLSIGN_REGEX },
uniqueness: { case_sensitive: false }
validates :user_id, presence: true
validates :persona_id, presence: true
def to_param
callsign
end
.
.
end
Failed test output:
FAIL["test_user_should_be_valid", PersonaTest, 0.754914]
test_user_should_be_valid#PersonaTest (0.75s)
Failed assertion, no message given.
test/models/persona_test.rb:18:in `block in <class:PersonaTest>'
FAIL["test_persona_should_be_valid", PersonaTest, 0.893247]
test_persona_should_be_valid#PersonaTest (0.89s)
Failed assertion, no message given.
test/models/persona_test.rb:22:in `block in <class:PersonaTest>'
I don't understand why the User validation in persona_test.rb is failing when the setup user is identical to the one in user_test.rb. Are you not allowed to test Users in a Personas test? If so, how do I successfully test personas? Each persona belongs_to a user, so I have to create a user in order to create a persona.
EDIT:
persona_test.rb:
require 'test_helper'
class PersonaTest < ActiveSupport::TestCase
def setup
#user = User.new(name: "Example User", email: "user#example.com", callsign: "example",
password: "foobar", password_confirmation: "foobar")#, activated: true)
#persona = #user.personas.build(name: "Bazman", callsign: "Baz")
#persona.user = #user
#persona.persona_id = 1
end
test "user should be valid" do
assert #user.valid?, #user.errors.full_messages
end
test "persona should be valid" do
assert #persona.valid?, #persona.errors.full_messages
end
end
With the updated persona test above, I get the error message 'User can't be blank'. Why is
#persona.user = #user
not working?

The reason for the failed assertion is that some validations in Persona won't pass:
validates :user_id, presence: true
validates :persona_id, presence: true
The validations are run before saving them to the database. For new records, user_id and persona_id will still be nil.
Because Persona is invalid, the User will be invalid in the other test as well.

In your persona model you have:
validates :user_id, presence: true
validates :persona_id, presence: true
But it doesn't look like a user_id is being set. Try setting it with #persona.user = #user in your test.
Additionally, as a tool for debugging, you can print #persona.errors.full_messages in your test to see where exactly it is not validating.
E.g. assert #persona.valid?, #persona.errors.full_messages
Hope that helps.
EDIT: as per the comments below, the line should actually be #persona.user_id = #user.id. Another way you could achieve the same effect is to actually save the records to the database. So in your setup function, you would use create instead of build. This would, however, be slower.

Related

Not able to validate credit card using active merchant?

When i charge credit card using form, it throws validation error "The credit card information you provided is not valid. Please double check the information you provided and then try again."
Any solution??
This is my payment.rb
class Payment < ActiveRecord::Base
require "active_merchant/billing/rails"
attr_accessor :card_security_code
attr_accessor :credit_card_number
attr_accessor :expiration_month
attr_accessor :expiration_year
validates :first_name, presence: true
validates :last_name, presence: true
validates :card_security_code, presence: true
validates :credit_card_number, presence: true
validates :expiration_month, presence: true, numericality: { greater_than_or_equal_to: 1, less_than_or_equal_to: 12 }
validates :expiration_year, presence: true
validates :amount, presence: true, numericality: { greater_than: 0 }
validate :valid_card
def credit_card
ActiveMerchant::Billing::CreditCard.new(
number: credit_card_number,
verification_value: card_security_code,
month: expiration_month,
year: expiration_year,
first_name: first_name,
last_name: last_name
)
end
def valid_card
if !credit_card.valid?
errors.add(:base, "The credit card information you provided is not valid. Please double check the information you provided and then try again.")
false
else
true
end
end
def process
if valid_card
response = GATEWAY.authorize(amount * 100, credit_card)
if response.success?
transaction = GATEWAY.capture(amount * 100, response.authorization)
if !transaction.success?
errors.add(:base, "The credit card you provided was declined. Please double check your information and try again.") and return
false
end
update_columns({authorization_code: transaction.authorization, success: true})
true
else
errors.add(:base, "The credit card you provided was declined. Please double check your information and try again.") and return
false
end
end
end
end
This is my activemerchant.rb
if Rails.env == 'development'
ActiveMerchant::Billing::FirstdataE4Gateway.wiredump_device = File.open(Rails.root.join('log','active_merchant.log'), 'a+')
ActiveMerchant::Billing::FirstdataE4Gateway.wiredump_device.sync = true
ActiveMerchant::Billing::Base.mode = :test
login = 'mylogin'
password='mypassword'
elsif Rails.env == 'production'
login = 'mylogin'
password='mypassword'
end
GATEWAY = ActiveMerchant::Billing::FirstdataE4Gateway.new({
login: login,
password: password
})
Check here
You also need to provide credit card brand name as
def credit_card
ActiveMerchant::Billing::CreditCard.new(
number: credit_card_number, # 4111111111111111
verification_value: card_security_code, # 123
month: expiration_month, # 1
year: expiration_year, # 2020
first_name: first_name, # Bibek
last_name: last_name, # Sharma
brand: credit_card_brand # visa
)
end

How could patch method in Rails update only some attributes while the other attributes are blank?

I have these questions while reading the Ruby On Rails Tutorial in
here
The validation of User class is:
class User < ActiveRecord::Base
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 }
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, length: { minimum: 6 }, allow_blank: true
.
.
.
end
In test,while patching a updated user information to the route of the user like this:
def setup
#user = users(:michael)
end
.
.
.
test "successful edit" do
get edit_user_path(#user)
assert_template 'users/edit'
name = "Foo Bar"
email = "foo#bar.com"
patch user_path(#user), user: { name: name,
email: email,
password: "",
password_confirmation: "" }
assert_not flash.empty?
assert_redirected_to #user
#user.reload
assert_equal name, #user.name
email, #user.email
end
The test would pass and only the user's name and email would be updated and password won't change.
If the validation of the password doesn't include the "allow_blank:true",this test would fail.
So I don't understand that: When the test passed which means the password could be blank, why it wouldn't change the password to be blank? How could Rails know I just want to update some of the attributes?
has_secure_password adds a password= setter method method to your model which discards empty? input when setting the password.
irb(main):012:0> "".empty?
=> true
This prevents users from choosing a blank password. If you dont want to take my word for it you can easily test this:
test "does not change password to empty string" do
patch user_path(#user), user: { name: name,
email: email,
password: "",
password_confirmation: "" }
#user.reload
assert_false #user.authenticate("")
end
However what your validation does do is that if the user sets a password it must be over 6 characters:
test "does not allow a password less than 6 characters" do
patch user_path(#user), user: { name: name,
email: email,
password: "abc",
password_confirmation: "abc" }
assert assigns(:user).errors.key?(:password)
end
(PS. this is something that is better tested in a model test than a controller test)

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 set a virtual attribute in model with Rails?

I have a model User with usual attributes email, email_confirmation, password, password_confirmation. I use "has_secure_password" so the real attributes in the database are email and password_digest. However I would like to limit password length without spaces to 6 characters.
Here is my model :
class User < ActiveRecord::Base
before_validation :auto_strip_confirmation
validates :email, presence: true,
length: { maximum: MAX_SIZE_DEFAULT_INPUT_TEXT },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false },
confirmation: true
validates :email_confirmation, presence: true
has_secure_password
validates :password, length: { minimum: MIN_SIZE_USER_PASSWORD,
maximum: MAX_SIZE_USER_PASSWORD }
private
def auto_strip_confirmation
self.password.strip!
self.password_confirmation.strip!
end
end
But I get this in console :
> user.password = user.password_confirmation = "a "
=> "a "
> user.valid?
User Exists (0.8ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('user#example.com') LIMIT 1
=> true
Thanks for your help.
After reload, my code actually works in console : user.valid? => false (thanks surendran). But my initial problem was in my tests : I thought I could not set virtual attributes because of the error message "undefined method `strip!' for nil:NilClass". But I forgot I test if my user is valid when password is nil, nearly like this :
before { user.password = nil) }
it { should_not be_valid }
before_validation comes before this test so he tries to strip a nil object.

Assigning to a class attribute from a method rails

Following the Michael Hartl rails tutorial. Struggling to get the remember token tests to pass, specifically, the test for non-blankness of the remember token.
The code for the User class is below
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
before_save { |user| user.email = email.downcase }
before_save { :create_remember_token }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: {case_sensitive: false}
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
and the test I can't get to pass:
subject { #user }
...
describe "remember token" do
before { #user.save }
its (:remember_token) { should_not be_blank }
end
and the error message I get is:
.....................F
Failures:
1) User remember token remember_token
Failure/Error: its (:remember_token) { should_not be_blank }
expected blank? to return false, got true
# ./spec/models/user_spec.rb:120:in `block (3 levels) in <top (required)>'
Finished in 0.68878 seconds
22 examples, 1 failure
Failed examples:
rspec ./spec/models/user_spec.rb:120 # User remember token remember_token
I don't know if this is relevant but sublime_text isn't doing anything with the self keyword (ie its not highlighting it in a different colour).
I'm using Ruby 1.9.3
The issue is that you're writing before_save { :create_remember_token } when you should have before_save :create_remember_token. The { } is a block. Same as when you do
do
#This is some code
end
That is also a block of code.
That's why your first before_save works, because you're giving the block a piece of code to execute. In the second before_save you're just giving it the name of the method to execute which has the block of code.
Tl:dr:
Change
before_save { :create_remember_token }
to
before_save :create_remember_token
and you should be good to go.

Resources