.visible? doesn't give false when element not visible - ruby

There are test cases where I want to check:
Load more button visible
Load more not visible
I wrote this method:
def loadmore_button_visible?
wait_until(20) do
#browser.refresh
link_element(:title => 'load_more').visible?
end
end
and used it as
expect(on(ProductViewPage).loadmore_button_visible?).to be_true for "test1"
and expect(on(ProductViewPage).loadmore_button_visible?).to be_false for "test2"
It works test1 but for test2 it gives Time Out Error. I think I have asked similar question here wait_until block is giving time out error
but this time I think its not about wait_until block as wait_until works for "test1".

Your wait_until block is expecting to resolve to true. If it does not, it will raise a TimeoutError. The first test passes because link_element(:title => 'load_more').visible? is true and that satisfies the wait_until method. If you want the method to return true and false, you need to catch the error and explicitly return false. Something like:
def loadmore_button_visible?
begin
wait_until(20) do
#browser.refresh
link_element(:title => 'load_more').visible?
end
rescue TimeoutError
false
end
end

Related

RSpec how to stub out yield and have it not hit ensure

I have an around action_action called set_current_user
def set_current_user
CurrentUser.set(current_user) do
yield
end
end
In the CurrentUser singleton
def set(user)
self.user = user
yield
ensure
self.user = nil
end
I cannot figure out how to stub out the yield and the not have the ensure part of the method called
Ideally I would like to do something like
it 'sets the user' do
subject.set(user)
expect(subject.user).to eql user
end
Two errors I am getting
No block is given
When I do pass a block self.user = nil gets called
Thanks in advance
A few things to point out that might help:
ensure is reserved for block of codes that you want to run no matter what happens, hence the reason why your self.user will always be nil. I think what you want is to assign user to nil if there's an exception. In this case, you should be using rescue instead.
def set(user)
self.user = user
yield
rescue => e
self.user = nil
end
As for the unit test, what you want is to be testing only the .set method in the CurrentUser class. Assuming you have everything hooked up correctly in your around filter, here's a sample that might work for you:
describe CurrentUser do
describe '.set' do
let(:current_user) { create(:user) }
subject do
CurrentUser.set(current_user) {}
end
it 'sets the user' do
subject
expect(CurrentUser.user).to eq(current_user)
end
end
end
Hope this helps!
I am not sure what you intend to accomplish with this as it appears you just want to make sure that user is set in the block and unset afterwards. If this is the case then the following should work fine
class CurrentUser
attr_accessor :user
def set(user)
self.user = user
yield
ensure
self.user = nil
end
end
describe '.set' do
subject { CurrentUser.new }
let(:user) { OpenStruct.new(id: 1) }
it 'sets user for the block only' do
subject.set(user) do
expect(subject.user).to eq(user)
end
expect(subject.user).to be_nil
end
end
This will check that inside the block (where yield is called) that subject.user is equal to user and that afterwards subject.user is nil.
Output:
.set
sets user for the block only
Finished in 0.03504 seconds (files took 0.14009 seconds to load)
1 example, 0 failures
I failed to mention I need to clear out the user after every request.
This is what I came up with. Its kinda crazy to put the expectation inside of the lambda but does ensure the user is set prior to the request being processed and clears it after
describe '.set' do
subject { described_class }
let(:user) { OpenStruct.new(id: 1) }
let(:user_expectation) { lambda{ expect(subject.user).to eql user } }
it 'sets the user prior to the block being processed' do
subject.set(user) { user_expectation.call }
end
context 'after the block has been processed' do
# This makes sure the user is always cleared after a request
# even if there is an error and sidekiq will never have access to it.
before do
subject.set(user) { lambda{} }
end
it 'clears out the user' do
expect(subject.user).to eql nil
end
end
end

How to create mock test cases for scalar valued function

I am calling a scalar valued function but having hard time trying to figure out how can i create mock test cases for it.
I just want to create some mock test cases like,
function returns successfully one value
function returns conversion error
I tried something below but here i have to call the actual function, which i dont want to because if database changes it'll cause the test case fail hence want to mock cases.
require 'rails_helper'
describe ScalarSqlFunction::Base do
describe '#exec' do
let!(:success) { 0 }
context 'with valid input' do
let(:response) {
ScalarSqlFunction::CalcTotal(105)
}
before do
allow(response)
.to receive(return_code).and_return(success)
end
it 'returns success' do
expect(response.return_code).to eq(success)
end
end
end
end
You can create a mock object for ScalarSqlFunction::CalcTotal
require 'rails_helper'
describe ScalarSqlFunction::Base do
describe '#exec' do
let!(:success) { 0 }
context 'with valid input' do
let(:response) { double('Response') }
before do
allow(response)
.to receive(return_code).and_return(success)
end
it 'returns success' do
expect(response.return_code).to eq(success)
end
end
end
end

How to use yield self within Rspec

This is a description of how to create a helper method in Rspec taken from the Rspec book (page 149). This example assumes that there is a method called 'set_status' which is triggered when the 'Thing' object is created.
Both sets of code create a new 'Thing' object, set the status, then do 'fancy_stuff'. The first set of code is perfect clear to me. One of the 'it' statements it triggered, which then calls the 'create_thing' method with options. A new 'Thing' object is created and the 'set_status' method is called with the 'options' attribute as the parameter.
The second set of code is similar. One of the 'it' statements is triggered, which then calls the 'given_thing_with' method while passing ':status' hash assignment as a parameter. Within the 'given_thing_with' method the 'yield' is triggered taking the 'Thing.new' as a parameter. This is where I am having trouble. When I try to run this code I get an error of "block given to yield". I understand that whatever attributes that are passed by yield will be returned to the 'thing' in pipe brace from the 'it' statement that called the 'given_thing_with' method. I can get the new
What I don't understand is why the code block is not called in the 'given_thing_with' method after the 'yield' command. In other words, I can't code in that block to run.
Thanks in advance for your help.
The remainder of this question is quoted directly from the Rspec book:
describe Thing do
def create_thing(options)
thing = Thing.new
thing.set_status(options[:status])
thing
end
it "should do something when ok" do
thing = create_thing(:status => 'ok')
thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
...
end
it "should do something else when not so good" do
thing = create_thing(:status => 'not so good')
thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
...
end
end
One idiom you can apply to clean this up even more is to yield self from initializers in your objects. Assuming that Thing's initialize() method does this and set_status() does as well, you can write the previous like this:
describe Thing do
def given_thing_with(options)
yield Thing.new do |thing|
thing.set_status(options[:status])
end
end
it "should do something when ok" do
given_thing_with(:status => 'ok') do |thing|
thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
...
end
end
it "should do something else when not so good" do
given_thing_with(:status => 'not so good') do |thing|
thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
...
end
end
end
The example in the book is a bit confusing because the implementation of Thing is not shown. To make this work you need to write Thing like so:
class Thing
def initialize
yield self
end
end
When given_thing_with is called it yields a new Thing, which will yield itself when it is constructed. This means that when the inner code block (the one containing thing.set_status) is executed it will have a reference to he newly built Thing.
There are 2 issues with the code from book.
1. Setting up the initializer to yield itself
When the Thing object is created, it needs an initializer and need yield itself.
class Thing
def initialize
yield self
end
end
However, this alone will still causes an error, at least on my system, which is Ruby 1.9.3. Specifically, the error is 'block given to yield (SyntaxError)'. This doesn't make much sense, since that is what we want it to do. Regarless, that is the error I get.
2. Fixing the 'block given to yield' error
This is not as obvious and has something to do with either Ruby or the 'yield' statement, but creating a block using 'do...end' as was written in the book and is shown below causes the error.
yield Thing.new do |thing|
thing.set_status(options[:status])
end
Fixing this error is simlpy a matter of creating the block using braces, '{...}', as is shown below.
yield Thing.new { |thing|
thing.set_status(options[:status])
}
This is not good form for multiline Ruby code, but it works.
Extra. How the series of yields works to set the parameters of the 'Thing' object
The problem is already fixed, but this explains how it works.
the "caller block" calls 'given_thing_with' method with a parameter
that method yields back to the "caller block" a new "Thing" and a block (I'll call it the "yield block")
to execute the "yield block", the Thing class needs the initialization and 'yield self', otherwise the 'set_status' method will never be run because the block will be ignored
the new "Thing" is already in the "caller block" and has it's status set and now the relevant method is executed

Why can't I get a be_nil test to fail in Rspec

In Rspec I have the following:
describe "triangle.parameter" do
it "should return nil when it has 0 sides" do
#triangle = Triangle.new({})
#triangle.paramater.should be_nil
end
end
And I have my parameter method like so:
def parameter
return 4
end
I've tried true, false, 4, "apple" for parameter to return and nothing will fail. I also can't get it to fail with nothing in the method. What am I doing wrong?
You have #triangle.paramater instead of #triangle.parameter; since it doesn't know what paramater is, it will always be nil.

How do you rescue I18n::MissingTranslationData?

I want to be able to rescue I18n::MissingTranslationData like so:
begin
value = I18n.t('some.key.that.does.not.exist')
puts value
return value if value
rescue I18n::MissingTranslationData
puts "Kaboom!"
end
I tried the above, but it doesn't seem to go into the rescue block. I just see, on my console (because of puts): translation missing: some.key.that.does.not.exist. I never see Kaboom!.
How do I get this to work?
IMO, it's pretty strange but in the current version of i18n (0.5.0) you should pass an exception that you want to rescue:
require 'i18n'
begin
value = I18n.translate('some.key.that.does.not.exist', :raise => I18n::MissingTranslationData)
puts value
return value if value
rescue I18n::MissingTranslationData
puts "Kaboom!"
end
and it will be fixed in the future 0.6 release (you can test it - https://github.com/svenfuchs/i18n)
Same as above but nicer.
v = "doesnt_exist"
begin
puts I18n.t "langs.#{v}", raise: true
rescue
puts "Nooo #{v} has no Translation!"
end
or
puts I18n.t("langs.#{v}", default: "No Translation!")
or
a = I18n.t "langs.#{v}", raise: true rescue false
unless a
puts "Update your YAML!"
end
In the current version of I18n, the exception you're looking for is actually called MissingTranslation. The default exception handler for I18n rescues it silently, and just passes it up to ArgumentError to print an error message and not much else. If you actually want the error thrown, you'll need to override the handler.
See the source code for i18n exceptions, and section 6.2 of RailsGuides guide to I18n for how to write a custom handler
Note that now you simply pass in :raise => true
assert_raise(I18n::MissingTranslationData) { I18n.t(:missing, :raise => true) }
...which will raise I18n::MissingTranslationData.
See https://github.com/svenfuchs/i18n/blob/master/lib/i18n/tests/lookup.rb

Resources