How to test whether an element is displayed on the page - ruby

The following code checks whether an element is displayed and if the element is present runs a specific action, else the test continues normally:
require "selenium-webdriver"
require "rspec"
require 'rspec/expectations'
describe "Current Expense" do
before(:all) do
#driver = Selenium::WebDriver.for :firefox
#base_url = "http://the-internet.herokuapp.com/disappearing_elements"
#driver.manage.window.maximize
end
after(:all) do
#driver.quit
end
it "Check icon" do
#driver.get(#base_url)
if expect(#driver.find_element(:xpath, "//*[#href='/gallery/']").displayed?).to be_truthy
#driver.find_element(:xpath, "//*[#href='/gallery/']").click
sleep 2
puts "element appears"
else
puts "element NOT appears"
end
end
end
When the element is present, the message appears, but when the element is not present in the page, an error occurs and the else block is not executed. What is causing this error?

I think the problem is that you're using expect when you should just have the conditional #driver.find_element(:xpath, "//*[#href='/gallery/']").displayed?. If the conditional is true you will see the expected message; likewise if it evaluates to false you will see `"element NOT appears".
As currently constructed, if the find_element method returns false then the spec should fail. Please post the error or exception you're seeing so that we can know for sure.
On a side note, what you have right now is fine for a quick and dirty test of whether or not the page is functioning correctly, but you'll probably want to give two cases in your test file: one where you know the icon will be on the page, and one where it shouldn't be on the page, and then test the outcome for each. For example:
#Code omitted
it "has the icon when x is the case" do
# make x be the case
#driver.get(#base_url)
#driver.find_element(:xpath, "//*[#href='/gallery/']").displayed?
#driver.find_element(:xpath, "//*[#href='/gallery/']").click
sleep 2
# code that verifies that the element is on the page
end
it "doesn't have the icon when y is the case" do
# make y be the case
#driver.get(#base_url)
expect {
#driver.find_element(:xpath, "//*[#href='/gallery/']").displayed?
}.to be_false
end
#code omitted

expect is the reason for test failure. Find the below snippet for solution.. Cheers!
it "has the icon when x is the case" do
#driver.get(#base_url)
begin
#driver.find_element(:xpath, "//*[#href='/gallery/']")
#driver.find_element(:xpath, "//*[#href='/gallery/']").click
rescue Selenium::WebDriver::Error::NoSuchElementError
raise 'The Element ' + what + ' is not available'
end
end
it "doesn't have the icon when y is the case" do
#driver.get(#base_url)
begin
#driver.find_element(:xpath, "//*[#href='/gallery/']")
raise 'The Element ' + what + ' is available'
rescue Selenium::WebDriver::Error::NoSuchElementError
expect(true).to be_truthy
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.

Siteprism section won't respond to has_element

I'm trying to use SitePrism with my ruby/capybara/selenium test suite and I continue to get an error around expecting an element to respond to has_<element_name>? The last line of the spec is what is failing. It is giving me an error saying:
expected #<PageObjects::Pages::SalesPage:0x00000000066782b0> to respond to 'has_toolbar_title?'
sales_page.rb
module PageObjects
module Pages
class SalesPage < SitePrism::Page
set_url "REDACTED"
section :toolbar, PageObjects::Sections::Toolbar, '#qHybridViewToolbar'
end
end
end
toolbar.rb
module PageObjects
module Sections
class Toolbar < SitePrism::Section
element :new_button, '#ToolBtnNew'
element :edit_button, '#ToolBtnUpdate'
element :delete_button, '#ToolBtnDelete'
element :toolbar_title, '#qToolbarViewTitle'
end
end
end
my_spec.rb
require 'spec_helper'
describe 'On sales page' do
context 'without a password' do
it "does the things" do
sales_page = PageObjects::Pages::SalesPage.new
sales_page.load
expect(sales_page).to have_toolbar
sales_page.toolbar.new_button.click
puts sales_page.toolbar.toolbar_title
puts sales_page.toolbar.toolbar_title.text
expect(sales_page).to have_toolbar_title
end
end
end
This error is completely correct. You're asking the page whether it has a toolbar_title, but the toolbar_title is actually on the toolbar. You need to call
expect(sales_page.toolbar).to have_toolbar_title

RSpec before blocks not being called before contexts or describes

Given the following code:
RSpec.configure do |config|
config.before(:all) { puts 'before all' }
config.before(:suite) { puts 'before suite'}
config.before(:context) { puts 'before context'}
config.before(:each) { puts 'before each'}
end
RSpec.describe "SomeClass" do
it 'matches some regex' do
puts 'in first it block'
expect('some string').to match(/.*/)
end
describe 'some group of tests' do
puts 'in some group'
context 'when some thing happens' do
puts 'in context'
it 'does something' do
expect(true).to be_truthy
end
end
end
end
I would expect the following output:
before suite
before all
before context
before each
in some group
in context
in first it block
.before each
But instead I get:
in some group
in context
before suite
before all
before context
before each
in first it block
.before each
Meaning that context or describe gets run before any before configuration I've set up.
I expect it to be the first output because of what I've read here and here.
What do I do when I absolutely need code to run before absolutely anything else in the test files? Including (nested) context or describes? And why doesn't it work the way I expect?
Note: I see the same behavior when I include the before :something statements within the scope of the uppermost describe.
(This question is similar to this question, but not the same. I would like to know why my tests are running this way and what the proper RSpec convention is to run a piece of code before absolutely anything else.)
Version info:
RSpec 3.6
- rspec-core 3.6.0
- rspec-expectations 3.6.0
- rspec-mocks 3.6.0
- rspec-support 3.6.0
UPDATE:
It may be helpful to know some context: I'm writing selenium front end automated tests using the selenium-webdriver gem. Before any and all it blocks run, I need to call a function called navigate() (in order to take me to the web page I'm writing the tests for, this function takes about 30 seconds to run because it takes me through two login pages before it gets to where it needs to go) to be called and complete before anything else happens. In my RSpec file I'm using before blocks in an attempt to make this happen, however rspec keeps running tests before the before blocks, and failing.
If you were to put puts "in some group" and puts "in context" into before(:all) blocks, then the output is closer to what you're expecting.
RSpec.configure do |config|
config.before(:all) { puts 'before all' }
config.before(:suite) { puts 'before suite'}
config.before(:context) { puts 'before context'}
config.before(:each) { puts 'before each'}
end
RSpec.describe "SomeClass" do
it 'matches some regex' do
puts 'in first it block'
expect('some string').to match(/.*/)
end
describe 'some group of tests' do
before(:all) { puts 'in some group' }
context 'when some thing happens' do
before(:all) { puts 'in context' }
it 'does something' do
expect(true).to be_truthy
end
end
end
end
outputs
before suite
before all
before context
before each
in first it block
.in some group
in context
before each
.
or, if you did before(:each) you would get
before suite
before all
before context
before each
in first it block
.before each
in some group
in context
.
The reason for the current output is your puts statements for "in some group" and "in context" are being executed when the file is being parsed, not waiting for RSpec at all. If we gave a different example, without Rspec in the mix, imagine we had a file with just
class SomeClass
puts "in class"
def do_something
puts "doing something"
end
end
if we load that file into an irb session or run it on the command line with ruby, we would see "in class" output in the console even though we haven't done anything with that class.

Why browser.text.include? produces error in Watir Ruby script

Issue: I have researched online on how to verify if text exists on my page, but I keep getting error messages. I have attempted using "expect" and one without "expect". For something that seems basic, I am not sure why this is not asserting correctly.
Ruby File:
require "rubygems"
require "watir-webdriver"
require "rspec"
require "selenium-webdriver"
require "rspec/expectations"
#browser = Watir::Browser.new :internet_explorer
begin
if expect(#browser.text.include?("Welcome")).to be_true
##browser.text.include?("Welcome").should == true
puts "Test passed!"
else
puts "Test failed!"
end
end
Error:
test2.rb:61:in <main>': undefined methodexpect' for main:Object (NoMethodError)
You should have your expectations defined inside a test case
describe "IE" do
it "should have test 'Welcome'" do
expect(#browser.text.include("Welcome")).to be_true
end
end
Or if you just want your script to print pass or fail, just do
begin
if #browser.text.include?("Welcome")
puts "Test passed!"
else
puts "Test failed!"
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

Resources