Class methods and expect argument - ruby-on-rails

I have simple test case: (board has_many links, link belongs_to board)
context "with feeds" do
let (:board) {FactoryGirl.create(:board_tree)}
it "returns links from all feeds" do
expect(board.all_links.count).to eq Link.all.count
end
end
It fails (expected 8 got 2) - which is ok, I expected the same.
Now I switch this expect with:
expect(Link.all.count).to eq board.all_links.count
This time I thought it will fail with expected 2 got 8, but instead of it I get: expected 2, got 0.
Any idea why? For me both expectations should be equal.

If you try changing:
let (:board) {FactoryGirl.create(:board_tree)}
into
let! (:board) {FactoryGirl.create(:board_tree)}
you will see that the results won't change when you invert the conditions. The problem is that links are created by rspec the first time that the board variable is referenced, so in the second example, there are no links yet when rspec is evaluating the expect(Link.all.count) part.

Related

Testing an update operation in RSpec, evaluates to true, but test fails?

I have this test:
it "saves the notification id in the referral for future reference" do
expect { subject.perform(*args) }
.to change(referral, :notification_id).from(nil).to(customer_notification_delivery.id)
end
And the code that it runs on top is:
if notification.present?
referral.update(friend_customer_notification_delivery_id: notification.id)
end
I added a few debug messages, to check on them after firing the test, to ensure that this condition was being met, and the code was being run, and I got true for both
p notification.present?
p referral.update(friend_customer_notification_delivery_id: customer_notification_delivery.id)
Anything I am missing? Why the update returns true, but the value is not getting updated on the test?
The output I get:
expected #notification_id to have changed from nil to 5, but did not change
referral in your test and referral in your object-under-test are two different objects, I'm willing to bet. Changes to one do not affect the other. referral in the test does not magically pull up updates from the related database record made by some other code.
I normally do it like this
it "saves the notification id in the referral for future reference" do
expect { subject.perform(*args) }
.to change{ referral.reload.notification_id }.from(nil).to(customer_notification_delivery.id)
end

RSpec do not see updated attributes in factory_bot object

I have report object called SiegeReport, that makes some calculations and returns integer object. When there is no warrior in the building, then siege_ability equals 0. The code itself is not important here, because it works fine in console and in application. Factories made by factory_bot work ok in all the other examples. I just have problem with testing the method:
require 'rails_helper'
RSpec.describe Reports::SiegeReport do
subject(:siege_report) { Reports::SiegeReport.new(building: building).call }
let(:building) { create(:building, granary: 100) }
let(:clan) { create(:clan) }
context 'with 1 infantry' do
let(:warrior) { create(:warrior, clan_id: clan.id, building_id: building.id) }
it 'returns 9' do
expect(siege_report).to eq(9)
end
end
end
RSpec returns:
Reports::SiegeReport siege ability with 1 infantry returns 9
Failure/Error: expect(siege_report).to eq(9)
expected: 9
got: 0
(compared using ==)
I checked it with pry and warrior object is valid, even building.warriors returns warrior, but in attributes number of warriors is still 0. The very same example works when i type it manually in console. How can I make RSpec update building attributes before testing?
Ok, I found solution but is really not elegant:
it 'returns 9' do
warrior.save
expect(siege_report).to eq(9)
end
It works but it seems to me that it is not the proper way of testing. Still, I can't find a better solution.

Expecting string but getting nil in Rspec test

I am working on a Ruby problem called "Speaking Grandma" where I need to create a method that should should take in a string argument containing a phrase and check to see if the phrase is written in all uppercase: if it isn't, then grandma can't hear you. She should then respond with (return) HUH?! SPEAK UP, SONNY!.
However, if you shout at her (i.e. call the method with a string argument containing a phrase that is all uppercase, then she can hear you (or at least she thinks that she can) and should respond with (return) NO, NOT SINCE 1938!.
I wrote the following code:
def speak_to_grandma(input)
if
input != input.upcase
puts 'HUH?! SPEAK UP, SONNY!'
else
puts 'NO, NOT SINCE 1938!'
end
end
When I run RSpec, I fail both tests. It gives the following message:
Failure/Error: expect(speak_to_grandma('Hi Nana, how are you?')).to eq 'HUH?! SPEAK UP, SONNY!'
expected: "HUH?! SPEAK UP, SONNY!"
got: nil
and
Failure/Error: expect(speak_to_grandma('WHAT DID YOU EAT TODAY?')).to eq "NO, NOT SINCE 1938!"
expected: "NO, NOT SINCE 1938!"
got: nil
(compared using ==)
I have no idea what I am doing wrong here. Can anyone help?
The speak_to_grandma method returns the return value of the puts method, being the last line in the method. The return value of puts is nil(Why are all my puts returning =>nil?)
The eq method in Rspec checks the return value of a method. The string is output to the screen with puts, but the return value is nil, and that's what Rspec is checking for.
If you remove puts, the tests should pass, because the string will be the return value of the method. But the correct way would be to test it with the output method in Rspec. Write your test like this:
expect { speak_to_grandma('WHAT DID YOU EAT TODAY?') }.to output("NO, NOT SINCE 1938!").to_stdout

How to test the eq of a .rjust 8, "0" with rspec

I have a little function to make a customer_nr with
id.to_s.rjust 8, "0"
This gives me a 8 diget number with the id and before filled with 0 until I have 8 diggets.
How can I test this with rspec? The first test works, but the second on is wrong since the id is interactive. Any Idea how to test the eq? FactoryGirl creates a user with FactoryGirl.create(:user). This works if the created user gets an single digget id.
When it gets a more diggets id then the test fails.
Like expected: "00000002398" got: "00002398"
describe "#customer_nr" do
it "should have 8 digits" do
user.customer_nr.length.should eq 8
end
it "should use the user_id" do
user.customer_nr.should eq "0000000#{user.id}"
end
end
best regard
denym
After my comment and your edit issue is easy. Everything is correct but your user have id 2398. You can make test in irb
2398.to_s.rjust 8, "0"
give exactly what test return. In test your db created records and destroy after tested but id still increment. You can make:
user.customer_nr.should eq "0000000#{user.id}".split(//).last(8).join
or like toro2k wrote in his comment.

rspec/shoulda fails comparing two seemingly identical collections

(mentioning shoulda because I know it is in Gemfile - but don't know how it affects rspec tests, have no experience with it, don't know if it's involved here or not)
I have two [controller] tests:
first:
it { should assign_to( :messages ).with(
current_user.messages.ordered.decorate ) }
and second:
it { should assign_to( :messages ).with(
current_user.messages.order("send_at DESC").decorate ) }
note: the message.rb defines:
scope :ordered, order( 'messages.send_at DESC' )
,so they are testing exactly the same thing - except that ordered method used to sort by a wrong field, and the first test would always pass, expected collection being the same as the actual; hence the 2nd test, which explicitly demands the correct sorting order.
Now, the madness: 1st test passes, 2nd test fails. Rspec prints:
Expected action to assign #<DecoratedEnumerableProxy of
MessageDecorator for [#<Message id: 1, ... >, <Message id: 2, ...>]>,
but got #<DecoratedEnumerableProxy of MessageDecorator for [#<Message
id: 1, ... >, <Message id: 2, ...>]>
You guessed it - the "expected.." and "but got.." parts printed here are absolutely identical. I've triple-checked them with diff. If both tests were failing, I would not be so perplexed, but 1st one passes, and 2nd one fails. I suspected that 1st test must be producing some kind of a side effect, but no, reordering or commenting out one of the tests doesn't change anything.
Any ideas?

Resources