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
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 :)
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.
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.
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.
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'.