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.
Related
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
I'm trying to run an input validator that would rerun the method where the validator was invoked from if the input was bad. I'm aware (from a similar question) you can use the .caller method to find the name, but I'd like to simply call the method that invoked the current method (I don't need to know what it's name/class is.)
I've grossly simplified/altered my code for brevity here.
def stack(input)
if input == "A"
puts "Good job. Back to continue on the method you were just in."
else
puts "Try again. Back to the beginning of the method you were just in."
# invoke the method that called 'stack(input)' on this instance
# to prompt the user again from whatever method they came from.
# { insert brilliant code here (in this case, it'd call 'overflow') }
end
end
def overflow
p "Misc Instructions / Prompt: Type A to continue"
input = gets.chomp
stack(input)
# continuing code
end
overflow
Thx as always!
In such case, the standard way is to use catch and throw.
def stack(input)
case input
when "A"
puts "Good job. Back to continue on the method you were just in."
throw :continue
else
puts "Try again. Back to the beginning of the method you were just in."
end
end
def overflow
catch(:continue) do loop do
p "Misc Instructions / Prompt: Type A to continue"
stack(gets.chomp)
end end
# continuing code
end
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
I'm studying how the Camping web framework works right now, and I don't understand what the Camping::Server.start at line 10 in /bin/camping is doing.
I expected this to call the start method in /lib/camping/server.rb at line 131, and so I put a simple puts 'hello' statement at the beginning of that method, expecting that statement to be invoked when I ran /bin/camping. However, I never saw my puts statement get called, so I can only assume that it's not that start method getting called.
I feel like I'm missing something obvious here. Here is the link to the camping github page and the relevant sections of code:
Github: https://github.com/camping/camping
From /bin/camping:
#!/usr/bin/env ruby
$:.unshift File.dirname(__FILE__) + "/../lib"
require 'camping'
require 'camping/server'
begin
Camping::Server.start
rescue OptionParser::ParseError => ex
puts "did it error"
STDERR.puts "!! #{ex.message}"
puts "** use `#{File.basename($0)} --help` for more details..."
exit 1
end
From /lib/server.rb:
def start
if options[:server] == "console"
puts "** Starting console"
#reloader.reload!
r = #reloader
eval("self", TOPLEVEL_BINDING).meta_def(:reload!) { r.reload!; nil }
ARGV.clear
IRB.start
exit
else
name = server.name[/\w+$/]
puts "** Starting #{name} on #{options[:Host]}:#{options[:Port]}"
super
end
end
My puts 'hello' on Camping::Server.start wasn't getting called because I didn't understand how static methods were defined in ruby.
start was being called statically, and I realize now that the start method I was looking at in the snippet wasn't a static method, which meant that another start method was getting called. I looked into Camping::Server and realized that it inherited from Rack::Server, which has the following method:
def self.start(options = nil)
new(options).start
end
That was the method getting called, not the one on /lib/camping/server.rb. I had been looking at the wrong method.
I'm trying to make this test fail :)
it "should display the question" do
#ui.should_receive(:puts).with("What's your name?").once
#ui.ask_question("What's your name?")
end
At the moment it passes even if I don't call puts in my function.
Basically, #ui should call .puts on an object that probably defaults to $stdout. Then in your tests, you can replace $stdout with a StringIO object that you can set expectations on. This has the added benefit of making your #ui object more flexible.
Given the code:
require 'rubygems'
require 'spec'
class UI
def ask_question(q)
end
end
describe UI do
before do
#ui = UI.new
end
it "should display the question" do
#ui.should_receive(:puts).with("Whats your name?").once
#ui.ask_question("Whats your name?")
end
end
I get the failure:
F
1) Spec::Mocks::MockExpectationError in 'UI should display the question'
#<UI:0xb738effc> expected :puts with ("Whats your name?") once, but received it 0 times /home/avdi/tmp/puts_spec.rb:15:
Finished in 0.002575 seconds
1 example, 1 failure
What version of RSpec are you using?
You can try stringio or ZenTest, the following ruby-talk thread has more info.