Rspec testing validation - ruby-on-rails

I am new to rails and I'm trying to understand testing using Rspec. I created a simple model (just for testing purposes) named Contact that contains firstname:string, lastname:string and email:string. I am just trying to set a test for firstname to fail if is empty.
my Rspec test is as follow:
describe Contact do
it "creates a valid model" do
contact = Contact.new(
firstname: 'firstname',
lastname: 'lastname',
email: 'email'
)
expect(contact).to be_valid
end
it "is invalid without a firstname" do
contact = Contact.new(firstname: nil)
contact.valid?
expect(contact.errors[:firstname]).to include("can't be blank")
end
My understanding is that this test should not return any failures but it does. Output below:
Failures:
1) Contact is invalid without a firstname
Failure/Error: expect(contact.errors[:firstname]).to include("can't be blank")
expected [] to include "can't be blank"
# ./spec/models/contact_spec.rb:16:in `block (2 levels) in <top (required)>'
Finished in 0.11659 seconds (files took 2.39 seconds to load)
18 examples, 1 failure, 15 pending
Failed examples:
rspec ./spec/models/contact_spec.rb:13 # Contact is invalid without a firstname
If I change the expect statement from ".to" to "not_to" the test passes, so I think I am getting this backwards, any help or explanation is greatly appreciated.

As smathy said in the comments, I forgot to include the validation inside my model. That solved my problem.

Related

Date.today.to_s(:long) not converting to string

I am working on an assignment and I have written the following method based on our instructions:
def create_todolist(params)
due_date = Date.today.to_s(:long)
TodoList.create(list_name: params[:name],list_due_date: params[:due_date])
end
But when I run the rspec test, I get the following error:
1) Assignment rq03 rq03.2 assignment code has create_todolist method should create_todolist with provided parameters
Failure/Error: expect(testList.list_due_date).to eq due_date
expected: Thu, 07 May 2020
got: "2020-05-07"
(compared using ==)
Diff:
## -1,2 +1,2 ##
-Thu, 07 May 2020
+"2020-05-07"
# ./spec/assignment_spec.rb:177:in `block (4 levels) in <top (required)>'
# ./spec/assignment_spec.rb:14:in `block (2 levels) in <top (required)>'
Here is the rspec test:
context "rq03.2 assignment code has create_todolist method" do
it { is_expected.to respond_to(:create_todolist) }
it "should create_todolist with provided parameters" do
expect(TodoList.find_by list_name: "mylist").to be_nil
due_date=Date.today
assignment.create_todolist(:name=> 'mylist', :due_date=>due_date)
testList = TodoList.find_by list_name: 'mylist'
expect(testList.id).not_to be_nil
expect(testList.list_name).to eq "mylist"
expect(testList.list_due_date).to eq due_date
expect(testList.created_at).not_to be_nil
expect(testList.updated_at).not_to be_nil
end
end
At first I had just due_date = Date.today and was getting the same error and I'm not sure how to fix it. I'm wondering if it is because I am using a different version of ruby/rails than what was used when the course was created ( 5 years ago -_-).
Any help would be greatly appreciated!
Thank you :)
You are trying to compare a Date object:
due_date = Date.today
With a string object you generated while you created your record:
Date.today.to_s(:long)
As you can see, these are different types of objects:
Date.today.to_s(:long)
=> "May 07, 2020"
Date.today.to_s(:long).class
=> String
Date.today
=> 2020-05-07
Date.today.class
=> Date
Date.today.to_s(:long) == Date.today
=> false
I figured it out. When I was creating the TodoLists table, I didn't specify the migration type as :date. so by default, due_date was set to be a string. So I set to type :date and changed due_date to equal:
due_date = Date.today
Thank you for taking the time to help me out :)

Ruby On Rails testing User Model with RSpec - password and password_confirmation doesn't work properly

it's my first post. I start to learn Ruby and Ruby On Rails framework.
I want to test User Model with RSpec and i have problem with pass validation of password and password_confirmation.
Code: https://github.com/paw3lgora/gCMS/blob/master/spec/models/user_spec.rb
I have problem with line: it { should validate_confirmation_of(:password) }
I don't wanna use devise gem or has_secure_password method from BCrypt because i learn Ruby and I want to implement my authentcation systems from scratch and add Argon2 in the future.
This give me error like:
1) User validation password should validate that
:password_confirmation matches :password
Failure/Error: it { should validate_confirmation_of(:password) }
User did not properly validate that :password_confirmation matches
:password.
After setting :password_confirmation to ‹"some value"›, then setting
:password to ‹"different value"›, the matcher expected the User to be
invalid and to produce the validation error "doesn't match Password"
on :password_confirmation. The record was indeed invalid, but it
produced these validation errors instead:
* name: ["Nazwa użytkownika nie może być pusta.", "Nazwa użytkownika
jest za krótka. Minimum 2 znaki."]
* email: ["Nie podałeś emaila.", "Email jest za krótki. Minimum 5
znaków.", "Podałeś złą nazwę użytkownika."]
* password_confirmation: ["Hasła nie pasują do siebie."]
# ./spec/models/user_spec.rb:27:in `block (4 levels) in <top (required)>'
Help me guys! :)
If you read the whole message carefully you'll see
The record was indeed invalid, but it
produced these validation errors instead:
Which means that the validation failed, but the matcher expects the validation errors to be exactly as specified. And there were more.
You have two options:
add all failed validation expectations in your spec
prepare the user object in such way that :name and :email are valid.

having trouble testing upload file with Capybara attach_file method

I'm having trouble trying to test whether image upload works with paperclip using Capybara's attach_file method.
rspec returns these errors below:
Failures:
1) Upload Background Image cannot upload a background image
Failure/Error: page.attach_file('#artist_background_image', Rails.root + 'spec/Fixtures/Snow.jpg')
Capybara::ElementNotFound:
Unable to find file field "#artist_background_image"
# ./spec/models/artist_spec.rb:65:in `block (2 levels) in <top (required)>'
my test is listed below. I assumed the choose file button is the selector for attach_file so I used the id of the selector '#artist_background_page'.
describe 'Upload Background Image', js: true do
before :each do
p '================='
pp Artist.all
#artist = Artist.first || Artist.create(artist_name:'Double Stuff Oreos', email:'i#love.oreos', password:'letmein')
visit "/artists/" + #artist.id.to_s
pp #artist.id
pp #artist.artist_name
p #artist.errors.full_messages
click_button 'Log in'
fill_in 'Email', with: 'i#love.oreos'
fill_in 'Password', with: 'letmein'
page.find('#loginButtonModal').click
page.find('#addBackgroundImagePrompt').click
page.attach_file('#artist_background_image', Rails.root + 'spec/Fixtures/Snow.jpg')
p Rails.root + 'spec/Fixtures/Snow.jpg'
click_button 'upload'
end
it "cannot upload a background image", js: true do
backgroundURL = #artist.background_image.url.include?('Snow.jpg')
p #artist.background_image.url
expect(backgroundURL).to be_truthy
end
end
However when I change the selector to just 'artist_background_page' without the id '#' symbol. rspec gives me different error:
...."================="
[]
"is_active_session is called"
#<Artist id: 1, artist_name: "Double Stuff Oreos", route_name: "double-stuff-oreos", created_at: "2014-07-20 17:20:48", updated_at: "2014-07-20 17:20:48", password_digest: "$2a$04$vgozdgieklXPjJ9Ri4Cv1e1d/hme0ybNnSEGXrmob5z...", remember_token: nil, email: "i#love.oreos", description: nil, youtube: nil, twitter: nil, facebook: nil, instagram: nil, hometown: nil, confirmation_code: nil, is_confirmed: nil, background_image_file_name: nil, background_image_content_type: nil, background_image_file_size: nil, background_image_updated_at: nil>
1
"Double Stuff Oreos"
[]
"is_active_session is called"
#<Pathname:/Users/bob/rails_projects/audience/spec/Fixtures/Snow.jpg>
"/background_images/original/missing.png"
"Hello from update"
"Logged in!"
An error occurred in an after hook
ActiveRecord::RecordNotFound: Couldn't find Artist with 'id'=1
occurred at /Users/shuo/.rvm/gems/ruby-2.1.2/gems/activerecord- 4.1.4/lib/active_record/relation/finder_methods.rb:320:in `raise_record_not_found_exception!'
F....
Failures:
1) Upload Background Image cannot upload a background image
Failure/Error: expect(backgroundURL).to be_truthy
expected: truthy value
got: false
# ./spec/models/artist_spec.rb:74:in `block (2 levels) in <top (required)>'
In this case, the model was created but the errors says that it cannot find it for some reason...
Is there any other method I can use to attach files in capybara and test successfully uploads?
Possibilities for failure:
Wrong path for file upload
Wrong method to use or invalid use of method
something wrong with server
This error:
Capybara::ElementNotFound:
Unable to find file field "#artist_background_image"
shows that capybara can't find a field named #artist_background_image. What you need to do is to reference the file upload field by its name.
Suppose you have
<input id="artist_background_image" name="file_upload" type="file">
Then you can reference the field like:
page.attach_file('file_upload', Rails.root + 'spec/Fixtures/Snow.jpg')
With that, capybara will know what field to upload through.
I know this is a late response but I think it will help other people facing this issue.
This might be the case if you're using simple_form gem.
Note that it does automatically generate ids for your form elements, hence manually id-ing elements yourself is futile!
You can make sure of this by manually id-ing a form element then view the source on you browser. You'll defiantly see that your manually-assigned ids aren't anywhere in the page source.
There is; however, a naming convention that simple_form follows to id form elements.
object_attribute
The example bellow might clarify this even more (HAML exmaple):
= simple_form_for #user do |f|
= f.input :image, as: :file
simple_form will then automatically generate an id for the form element image as so (object_attribute):
id="user_image"
Now you can simply make use of this naming convention to target ids in your test. Hope this helps.

Rails nested models failing validation

I'm writing model spec tests using rspec for nested models 3 levels deep. Each -> represents a has_many relationship.
Users->Goals->Milestones
Right now, my spec/models/milestone_spec.rb test is failing a be_valid check, and I'm a little stumped as to why this is happening.
Failures:
1) Milestone
Failure/Error: it { should be_valid }
expected valid? to return true, got false
# ./spec/models/milestone_spec.rb:17:in `block (2 levels) in <top (required)>'
The spec itself:
describe Milestone do
let(:user) { FactoryGirl.create(:user) }
let(:goal) { user.goals.build(content: "Loreum Ipsum", amount: "30", interval: 2) }
before do
#milestone = goal.milestones.build(amount: "20")
end
subject { #milestone }
it { should respond_to(:goal_id) }
it { should respond_to(:amount) }
# not sure why this isn't working
it { should be_valid }
Could it be with how I'm creating the #milestone? I've tried goal.milestones.new, and that doesn't seem to make a difference. Below in the spec I have some tests for fields properly validating, and those run fine.
Any ideas?
Try this:
it "should be valid" do
#milestone.valid?
puts #milestone.errors.full_messages
end
That will run the validations and print out the the validation errors for you so you can see what's going on.

Tests are not passing

I'm using RSpec for tests and I don't know how to get this to green.
In this case, I have a model called "PartType" that holds an attribute called "quotation".
The value for quotation comes from a form, so it will be a string.
To demonstrate you can go to console and type:
(1..1000).includes?("50") # false
but..
(1..1000).includes?(50) # true
And this value can have decimals. So I needed to do a "type_cast".
I have this on my PartTypemodel:
before_validation :fix_quotation, :if => :quotation_changed?
protected
def fix_quotation
self[:quotation] = quotation_before_type_cast.tr(' $, ' , '.' )
end
This are working as expected BUT when go to tests, it fails.
Here is my part_type_spec.rb:
require 'spec_helper'
describe PartType do
before(:each) do
#attr = { :title => "Silver", :quotation => 100 }
end
it "should create a instance given a valid attributes" do
PartType.create!(#attr)
end
it "should accept null value for quotation" do
PartType.new(#attr.merge(:quotation => nil)).should be_valid
end
it "should accept 0 value for quotation" do
PartType.new(#attr.merge(:quotation => 0)).should be_valid
end
end
And finally the failing tests:
Failures:
1) PartType should create a instance given a valid attributes
Failure/Error: PartType.create!(#attr)
NoMethodError:
undefined method tr' for 100:Fixnum
# ./app/models/part_type.rb:7:infix_quotation'
# ./spec/models/part_type_spec.rb:10:in `block (2 levels) in '
2) PartType should accept 0 value for quotation
Failure/Error: PartType.new(#attr.merge(:quotation => 0)).should be_valid
NoMethodError:
undefined method tr' for 0:Fixnum
# ./app/models/part_type.rb:7:infix_quotation'
# ./spec/models/part_type_spec.rb:18:in `block (2 levels) in '
Finished in 0.06089 seconds
3 examples, 2 failures
Your include? snippets are wrong, I got false in the first, true in the second.
before_validation is executed and quotation_before_type_cast is expected to be a String but it is a Fixnum. Change 100 to '100' and 0 to '0'.

Resources