RSPEC - Expected vs Received Error - ruby-on-rails

Here is my test:
describe Item do
subject {Item.new(:report_id => 26 , :name => 'Gas' , :tax_rate => 0.13, :tax_id => 1 , :category_id => 15 , :sub_category_id => 31 , :job_id => 1 , :total => 20 )}
let(:tax) {Tax.where(id: subject.tax_id).first}
let(:sub_category) {SubCategory.where(id: subject.sub_category_id).first}
it 'Calculate with just Total' do
subject.name.should be == 'Gas'
tax = Tax.find_by_id(subject.tax_id)
subject.sub_category_id.should be == 31
subject.set_nil_values
sub_category.should_receive(:taxable).and_return(1)
tax.should_receive(:rate).and_return(0.13)
sub_category.should_receive(:tax_adjustment).and_return(nil)
subject.should_receive(:tax_rate).and_return(0.13)
subject.calculate_tax(tax, sub_category)
subject.tax_amount = (((subject.total - subject.deduction) - ((subject.total - subject.deduction) / (1 + 0.13))) * 1)
subject.calculate_cost
subject.cost.should be_within(0.01).of(17.70)
end
Here is my error:
1) Item Calculate with just Total
Failure/Error: subject.should_receive(:tax_rate).and_return(0.13)
(#<Item:0x007faab7299c30>).tax_rate(any args)
expected: 1 time with any arguments
received: 3 times with any arguments
# ./spec/models/item_spec.rb:25:in `block (2 levels) in <top (required)>'
I did some research, and tried to use this instead:
expect_any_instance_of(subject).to receive(:tax_rate)
But now get the following error:
1) Item Calculate with just Total
Failure/Error: expect_any_instance_of(subject).to receive(:tax_rate)
NoMethodError:
undefined method `method_defined?' for #<Item:0x007fe6fdaa1bf8>
# ./spec/models/item_spec.rb:25:in `block (2 levels) in <top (required)>'

Your initial error occurred because, as the error message stated, the method in question was called three times rather than once, which is the implicit expectation. Assuming the actual behavior is what it should be, you can change the expectation to be:
...receive(...).exactly(3).times
See http://rubydoc.info/gems/rspec-mocks/frames for more info.
As for the second error you encountered, based on my testing, this occurs when you use expect_any_instance_of with a class that already has an instance stubbed and then you call that stubbed instance. In any event, even if this had worked, I don't believe it's what you would have wanted, as the semantics in terms of frequency of expect_any_instance_of is the same as expect, namely "one (total) call across the stubbed instance(s)".
If this second error occurred without you having removed the existing expectation on subject, let me know.

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

Expect that a JSON has just a particular set of keys in rspec?

I am testing a JSON API, and right now I do this:
expect(json).to have_key('name')
expect(json).to have_key('age')
How can I make sure that the JSON has just the keys name and age, and no other keys?
Use the #contain_exactly matcher:
expect(json.keys).to contain_exactly('name', 'age')
Examples
Number #1
Spec:
describe "Hash" do
subject { {a: 2, b: 3} }
it "passes" do
expect(subject.keys).to contain_exactly(:a, :b)
end
end
Let's run it :
arup#linux-wzza:~/Ruby> rspec spec/test_spec.rb
.
Finished in 0.00227 seconds (files took 0.13131 seconds to load)
1 example, 0 failures
Number #2
Spec:
describe "Hash" do
subject { {a: 2, b: 3} }
it "fails" do
expect(subject.keys).to contain_exactly(:a)
end
end
Let's run it:
arup#linux-wzza:~/Ruby> rspec spec/test_spec.rb
F
Failures:
1) Hash fails
Failure/Error: expect(subject.keys).to contain_exactly(:a)
expected collection contained: [:a]
actual collection contained: [:a, :b]
the extra elements were: [:b]
# ./spec/test_spec.rb:7:in `block (2 levels) in <top (required)>'
Finished in 0.00243 seconds (files took 0.13206 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/test_spec.rb:6 # Hash fails
Number #3
Spec:
describe "Hash" do
subject { {a: 2, b: 3, c: 4} }
it "fails" do
expect(subject.keys).to contain_exactly(:a, :b)
end
end
Let's run it:
arup#linux-wzza:~/Ruby> rspec spec/test_spec.rb
F
Failures:
1) Hash fails
Failure/Error: expect(subject.keys).to contain_exactly(:a, :b)
expected collection contained: [:a, :b]
actual collection contained: [:a, :b, :c]
the extra elements were: [:c]
# ./spec/test_spec.rb:7:in `block (2 levels) in <top (required)>'
Finished in 0.00243 seconds (files took 0.13301 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/test_spec.rb:6 # Hash fails
arup#linux-wzza:~/Ruby>
Number #4
When dealing with JSON keys, the splat operator (*) comes in handy to manage a list of arguments.
Spec:
describe "Hash" do
subject { {a: 2, b: 3} }
let(:json_keys) { %w{a b} }
it "passes" do
expect(subject.keys).to contain_exactly(*json_keys)
end
end
Let's run it :
arup#linux-wzza:~/Ruby> rspec spec/test_spec.rb
.
Finished in 0.00227 seconds (files took 0.13131 seconds to load)
1 example, 0 failures
Have you tried this:
expect(json.keys.sort).to eq(["age","name"])
Or
expect(json.keys).to match_array(["name","age"])
I am assuming the json object is pre-parsed such as let(:json){JSON.parse(something)}. If so this is now a Hash and #keys will return an Array of the keys so compare that to the expected Array.
If not pre-parsed then
expect(JSON.parse(json).keys).to match_array(["name","age"])

Multipule posts in loop with FbGraph gives: OAuthException :: (#1) An error occured while creating the share

I'm having an issue posting posts to a page, and only get the helpful error:
OAuthException :: (#1) An error occured while creating the share
The first 20 or so posts worked great, then it started to error.
Does facebook have a limit on the number of posts one can make to a page (spam) or something?
I can reproduce form rails c and I have triple checked my access_token and can manually post from FB directly.
(I'm using the page access_token not my user one)
I opened a issue on FbGraph's githup but nov seems to think its a FB issue.
My Code:
admin = Admin.first
page = FbGraph::Page.new(admin.facebook_page_id)
Story.where(:facebook_post_id => nil).all.each do |story|
post = page.feed!(
:link => 'http://www.example.com/stories/'+story.cached_slug,
:access_token => admin.facebook_page_access_token
)
story.facebook_post_id = post.identifier
story.live = true
story.save
sleep 1
end
Backtrace:
FbGraph::InvalidRequest: OAuthException :: (#1) An error occured while creating the share
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/exception.rb:47:in `block in handle_httpclient_error'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/exception.rb:44:in `each'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/exception.rb:44:in `handle_httpclient_error'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/node.rb:142:in `handle_response'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/node.rb:55:in `post'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/connections/feed.rb:14:in `feed!'
from (irb):9:in `block in irb_binding'
from (irb):5:in `each'
from (irb):5
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/railties-3.2.12/lib/rails/commands/console.rb:47:in `start'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/railties-3.2.12/lib/rails/commands/console.rb:8:in `start'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/railties-3.2.12/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Update:
It looks like my access_token was banned for 24 hours.
I was just able to add another 28 posts to the page before getting this error again. I tried with a 10sec sleep this time but still got banned... I guess I will try with a 60sec sleep tomorrow.. :(
I was not able to fix this problem but I have worked around it.
By uploading 1 post every 3 minutes I was able to get 200-300 posts up a day.
admin = Admin.first
page = FbGraph::Page.new(admin.facebook_page_id)
Story.where(:facebook_post_id => nil).all.each do |story|
post = page.feed!(
:link => 'http://www.example.com/stories/'+story.cached_slug,
:access_token => admin.facebook_page_access_token
)
story.facebook_post_id = post.identifier
story.live = true
story.save
sleep 180
end
I hope this helps someone else with this problem.

Rails time formatting test failing because it's one hour off?

I have the following method in one of my Rails classes:
def human_departure_time
"#{departure_time.strftime("%A, %d %B %Y")} at #{departure_time.strftime("%I:%M %p")}"
end
As you can see, it just takes a datetime attribute of the model and formats it so that it is more human friendly.
Anyway, I have the following test for this method:
describe "human_departure_time" do
it "should output the time in readable format" do
# first I use the Timecop gem to freeze the time
Timecop.freeze(DateTime.now) do
bus_time = DateTime.now + 1.days
# factory a bus with a specific departure time
bus = Factory :bus, departure_time: bus_time
expected = "#{bus_time.strftime("%A, %d %B %Y")} at #{bus_time.strftime("%I:%M %p")}"
# check that the output is as expected
bus.human_departure_time.should == expected
end
end
end
Pretty simple but the test fails by one hour with the following output:
Failures:
1) Bus human_departure_time should output the time in readable format
Failure/Error: bus.human_departure_time.should == expected
expected: "Wednesday, 17 August 2011 at 03:13 AM"
got: "Wednesday, 17 August 2011 at 02:13 AM" (using ==)
# ./spec/models/bus_spec.rb:34:in `block (4 levels) in <top (required)>'
# ./spec/models/bus_spec.rb:30:in `block (3 levels) in <top (required)>'
Here is my bus factory just incase that is important. I'm overwriting the departure time with the frozen time plus one hour in my test.
factory :bus do
origin_name "Drogheda"
event_name "EP"
departure_time { DateTime.now + 14.days }
end
I assume this is something to do with daylight savings time or something? How can I fix this issue?
ActiveRecord could be automatically converting time attributes in your model to local time.
You can try and use the %Z parameter of strftime to see the time zone of the outputted timestamp to see where a possible conversion is sneaking into your time.
Some Googled hints that might be relevant:
default_timezone:
http://apidock.com/rails/ActiveRecord/Base/default_timezone/class
ActiveRecord::Base.time_zone_aware_attributes
config.active_record.time_zone_aware_attributes:
http://tamersalama.com/2011/01/10/rails-disable-timezone-conversions/
https://mirrors.kilnhg.com/Repo/Mirrors/From-Git/Rails/History/70cb470c1ab8
http://www.ruby-forum.com/topic/2096919
http://www.ruby-forum.com/topic/890711

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