Checking if test failed and giving console output accordingly - ruby

I am new to ruby and would like to add a step in my ruby/capybara test where
"if Test A failed,
log this message in the console: "Microservice A is currently down."
Should this be done in the after hook or inside the test? Also, what would the commands be?
describe 'Test Description' do
before (:each) do
login end
after (:each) do
logout
if test fail do
console.log ("Error: Microservice A currently is down")
end
end
it 'Check Page X Loads', :retry => 3, :retry_wait => 3 do
page.should have_content 'Frisbee'
navigate_to_menu 'Toys'
page.has_content?("Frisbee")
expect(page).to have_content('Buy Frisbee') end
end
Thank you

The after hook receives the test that was run as a parameter so you can do
after do |example|
if example.exception
puts "Error: Microservice A currently is down"
end
end

Related

Is there a way to abort a test cleanly?

Using Selenium, Ruby
I'm trying to learn the correct way of closing out a test should an object not exist. For example I have a test that calls a function "Click_Login" which in turn goes to the function and returns the object reference or the text "Stop Test" if it does not exist. That part is working correctly.
However after the browser is closed, the test continues on and tries to varLoginBtn.click and fails because Stop Test.click does not exist. I thought the test would have stopped after the driver.quit and not continue on to varLoginBtn.click.
My goal is to have the test stop cleanly if an object does not exist. I maybe doing this incorrectly.
#The test.rb
varLoginBtn = toNavigate.Click_LogIn(driver) #calls function down below.
if varLoginBtn == "Stop Test"
driver.quit
end
varLoginBtn.click #click on the button
#functions.rb
#in the Class toNavigate
#Login Button
def Click_LogIn(driver)
puts "In the login"
wait = Selenium::WebDriver::Wait.new(:timeout => 15)
begin
element= wait.until{driver.find_element(:xpath, "//*[#xas-string='SDE_LOG_INN']")} #Log_INN is intentional I want it to fail.
return element
rescue
puts "The Login button did not exist"
return "Stop Test"
end
end
Thanks for your help.
You don't need to rescue, you have a condition if nil and you can use abort to exit script with a message
But also use snake_case for def ruby methods
def click_login(driver)
puts "In the login"
wait = Selenium::WebDriver::Wait.new(:timeout => 15)
if element = wait.until{driver.find_element(:xpath, "//*[#xas-string='SDE_LOG_INN']")} #Log_INN is intentional I want it to fail.
return element
else
puts 'The Login button did not exist'
abort 'Stop Test'
end
end
This is an overengineered way to do this... why not just throw an exception when this occurs and let the test die with a good message? Something like
...
rescue
raise "The Login button did not exist"
end
Your test library should be able to handle this and print a nice message that you can use to investigate, etc.
Read more about exceptions in ruby here.

Run after block after specific test in Rspec

Is there a way I can run the after/before block after/before a specific test using labels?
I have 3 it blocks
describe "describe" do
it "test1" do
end
it "test2" do
end
after(<<what goes here??>>) do
end
end
How do I run the after block only after test2? Is that possible?
You should use contexts to do this. Something like:
describe "describe" do
context 'logged in' do
before(:each) do
# thing that happens in logged in context
end
after(:each) do
# thing that happens in logged in context
end
it "test1" do
end
end
context 'not logged in' do
# No before/after hooks here. Just beautiful test isolation
it "test2" do
end
end
end
Having if/else conditions in before/after blocks is a code smell. Don't do it that way. It'll only make your tests brittle, error prone, and hard to change.
The best way to do this is just use a context. For your example:
describe "AutomateFr33k's fr33ky tests" do
it "runs test1" do
expect(true).to be_true
end
context "do something afterwards" do
after { puts "running something after test2!" }
it "runs test2" do
expect(5).not_to eq(4)
end
end
end
Yes you can do that, have a look here
You can achieve that using metadata in rspec
RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
end
describe "Skip hook demo" do
# If prior to RSpec 2.99.0.beta1
after do
puts "before hook" unless example.metadata[:skip]
end
# If RSpec 2.99.0.beta1 or later
after do |example|
puts "before hook" unless example.metadata[:skip]
end
it "will use before hook" do
end
it "will not use before hook", :skip do
end
end

How to ignore or skip a test method using RSpec?

please guide how to disable one of the below test methods using RSpec. I am using Selenuim WebDriver + RSpec combinations to run tests.
require 'rspec'
require 'selenium-webdriver'
describe 'Automation System' do
before(:each) do
###
end
after(:each) do
#driver.quit
end
it 'Test01' do
#positive test case
end
it 'Test02' do
#negative test case
end
end
You can use pending() or change it to xit or wrap assert in pending block for wait implementation:
describe 'Automation System' do
# some code here
it 'Test01' do
pending("is implemented but waiting")
end
it 'Test02' do
# or without message
pending
end
pending do
"string".reverse.should == "gnirts"
end
xit 'Test03' do
true.should be(true)
end
end
Another way to skip tests:
# feature test
scenario 'having js driver enabled', skip: true do
expect(page).to have_content 'a very slow test'
end
# controller spec
it 'renders a view very slow', skip: true do
expect(response).to be_very_slow
end
source: rspec 3.4 documentation
Here is an alternate solution to ignore (skip) the above test method (say, Test01) from sample script.
describe 'Automation System' do
# some code here
it 'Test01' do
skip "is skipped" do
###CODE###
end
end
it 'Test02' do
###CODE###
end
end
Pending and skip are nice but I've always used this for larger describe/context blocks that I needed to ignore/skip.
describe Foo do
describe '#bar' do
it 'should do something' do
...
end
it 'should do something else' do
...
end
end
end if false
There are a number of alternatives for this. Mainly marking it as pending or skipped and there is a subtle difference between them. From the docs
An example can either be marked as skipped, in which is it not executed, or pending in which it is executed but failure will not cause a failure of the entire suite.
Refer the docs here:
https://relishapp.com/rspec/rspec-core/v/3-4/docs/pending-and-skipped-examples/pending-examples
https://relishapp.com/rspec/rspec-core/v/3-4/docs/pending-and-skipped-examples/skip-examples
There are two ways to skip a specific block of code from being running while testing.
Example : Using xit in place of it.
it "redirects to the index page on success" do
visit "/events"
end
Change the above block of code to below.
xit "redirects to the index page on success" do #Adding x before it will skip this test.
visit "/event"
end
Second way: By calling pending inside the block.
Example:
it "should redirects to the index page on success" do
pending #this will be skipped
visit "/events"
end

Rspec and prevent tests from being run under some circumstances

I use rspec like this:
describe
it 'should check if the xx':
end
How do I prevent some tests in the it end body from being run if some condition is met? For example, if the function is_disabled returns true then the following tests should not run:
it 'should check if the xx1':
end
it 'should check if the xx2':
end
but the following should:
it 'should check if the xx3':
end
it 'should check if the xx4':
end
can you do :
context "if api calls enabled for MC, #app.is_disabled => 'USD' do
it 'should check if the xx3':
end
it 'should check if the xx4':
end
end
Yes, you can use rspec implicit filters. Example:
describe "if the app is enabled", :unless => #app.is_disabled do
it 'should check if the xx3':
end
it 'should check if the xx4':
end
end
describe "if the app is disabled", :if => #app.is_disabled do
it 'should check if the xx1':
end
it 'should check if the xx2':
end
end

how to force a cucumber scenario to fail?

Is there a way to force a cucumber scenario to fail?
I need to check for a few failing scenarios at the end of each of my tests. So I thought I could do the check for an 'error' dialog and then fail the test if it occurred.
This is possible with the code below however there is a problem. Once I raise the exception in the fail! function, then cucumber stops running the rest of the After hook, so the logout function doesnt get called.
Was:
After() do |scenario|
#Checking for Error popups
if page.has_selector?(:dialog_message, 1, :text => 'Error')
fail!(raise(ArgumentError.new('Unexpected Error dialog!')))
end
logout
end
Now:
After() do |scenario|
#Checking for Error popups
if page.has_selector?(:dialog_message, 1, :text => 'Error')
scenario.fail!(logout)
end
end
Is there a better way to fail a cucumber test without raising an exception?
You can get the after hook to fail using your normal assertions. Have not done much with Capybara/rspec exceptions, but I think you can do:
page.should have_selector?(:dialog_message, 1, :text => 'Error')
However, if you do this or do the scenario.fail!(), you will still not logout. You need to wrap it in a begin-ensure block.
Try this:
After do |scenario|
begin
page.should have_selector?(:dialog_message, 1, :text => 'Error')
ensure
logout
end
end
Update
If you do not want to call the standard assertions and directly fail the scenario, you can do the following - you need to use fail instead of fail!:
After() do |scenario|
begin
#Checking for Error popups
if page.has_selector?(:dialog_message, 1, :text => 'Error')
fail(ArgumentError.new('Unexpected Error dialog!'))
#Or you can just do fail('Unexpected Error dialog') if you do not care about the type.
end
ensure
logout
end
end
Just a preliminary answer as I haven't been able to check it out yet, but I'd assume that calling Raise is always guaranteed to halt execution (unless it's done inside a proc or lambda so it's evaluation is deferred).
Try simply
if page.has_selector?(:dialog_message, 1, :text => 'Error')
scenario.fail!(StandardError.new('Unexpected Error Dialog!'))
end
logout

Resources