Please please help me before I lose it!
I'm using Ruby Test Unit and Selenium Webdriver. All of my tests start with a login function, therefore I want the tests to pull the username and password values from a central script/csv/text file, whatever is easiest. This would make it easier to control login details from one place rather than hard coding them into every script. I am not a Ruby programmer and therefore I am not finding this particularly easy. I'm thinking I should be able to declare the username and password parameters in the 'def setup' section, so that it reads the values from an external source.
Is this possible?
require "selenium-webdriver"
require "test/unit"
class CMSNewslist < Test::Unit::TestCase
def setup
#driver = Selenium::WebDriver.for :firefox
#base_url = "http://skyintranet/"
#driver.manage.timeouts.implicit_wait = 90
#verification_errors = []
end
def teardown
#driver.quit
assert_equal [], #verification_errors
end
def test_c_m_s_newslist
#driver.get(#base_url + "/Enterprise-Applications-Test/")
#driver.find_element(:link, "Login").click
#driver.find_element(:id, "ctl00_MainRegion_LoginView_LoginControl_UserName").clear
#driver.find_element(:id, "ctl00_MainRegion_LoginView_LoginControl_UserName").send_keys "Ruband"
#driver.find_element(:id, "ctl00_MainRegion_LoginView_LoginControl_Password").clear
#driver.find_element(:id, "ctl00_MainRegion_LoginView_LoginControl_Password").send_keys "Donn1982"
#driver.find_element(:id, "ctl00_MainRegion_LoginView_LoginControl_LoginBtn").click
assert_equal "Logout", #driver.find_element(:class, "loginButton").text, "Login Unsuccessful"
puts "Login Successful"
Many Thanks.
You can put them in a separate file and read it or have a mixin that gets included in each script.
module LoginConfig
##username = 'foo'
##password = 'bar'
end
Then within your class CMSNewslist:
...
require 'login_config'
class CMSNewslist < Test::Unit::TestCase
include LoginConfig
...
Then you can use ##username and ##password. Here's a decent tutorial on Mixins...
http://www.tutorialspoint.com/ruby/ruby_modules.htm
Related
I have some experience of Selenium in Python and Cucumber/Watir/RSpec in Ruby, and can write scripts that execute successfully, but they aren't using classes, so I am trying to learn more about classes and splitting the scripts up in to pageobejcts.
I found this example to learn from: http://watir.com/guides/page-objects/ so copied the script and made some minor edits as you'll see below.
I'm using SublimeText 3.x with Ruby 2.4.x on Win10, so you know what tools I'm using.
I put the whole script in to a single .rb file (the only differences are that I replaced the URL and the elements to enter the username and password) and tried to execute it and get the following error:
C:/selenium/ruby/lotw/lotwlogin.rb:3:in `<main>': uninitialized constant Site (NameError).
I added the top line (required 'watir') line and it made no difference to the error encountered.
So I have in lotwlogin.rb essentilly the structure and syntax of the original script with custom elements. However, the core structure is reporting an error and I don't know what to do about it.
Here is my script:
require 'watir'
site = Site.new(Watir::Browser.new :chrome) # was :firefox but that no longer works since FF63
login_page = site.login_page.open
user_page = login_page.login_as "testuser", "testpassword" # dummy user and password for now
user_page.should be_logged_in
class BrowserContainer
def initialize(browser)
#browser = browser
end
end
class Site < BrowserContainer
def login_page
#login_page = LoginPage.new(#browser)
end
def user_page
#user_page = UserPage.new(#browser)
end
def close
#browser.close
end
end
class LoginPage < BrowserContainer
URL = "https://lotw.arrl.org/lotw/login"
def open
#browser.goto URL
##browser.window.maximize
self # no idea what this is for
end
def login_as(user, pass)
user_field.set user
password_field.set pass
login_button.click
next_page = UserPage.new(#browser)
Watir::Wait.until { next_page.loaded? }
next_page
end
private
def user_field
#browser.text_field(:name => "login")
end
def password_field
#browser.text_field(:name => "password")
end
def login_button
#browser.button(:value => "Log On")
end
end # LoginPage
class UserPage < BrowserContainer
def logged_in?
logged_in_element.exists?
end
def loaded?
#browser.h3 == "Welcome to Your Logbook of the World User Account Home Page"
end
private
def logged_in_element
#browser.div(:text => "Log off")
end
end # UserPage
Any assistance how to not get the Site error would be appreciated.
Thanks
Mike
You define class Site only a few lines below. But at that point, it's not yet known.
Move this logic to after all class definitions:
site = Site.new(Watir::Browser.new :chrome) # was :firefox but that no longer works since FF63
login_page = site.login_page.open
user_page = login_page.login_as "testuser", "testpassword" # dummy user and password for now
user_page.should be_logged_in
I'm trying to make testcase using Selenium WebDriver and Ruby. I started learning Ruby a few times ago.
I created the testcase:
require "test/unit"
require "selenium-webdriver"
require "yaml"
thing = YAML.load_file('config.yaml')
puts thing.inspect
class Test < Test::Unit::TestCase
def setup
browser = thing('browser')
#driver = Selenium::WebDriver.for browser
#driver.get 'http://google.com'
#driver.manage.delete_all_cookies
end
def teardown
#driver.close
end
def test_page_search
end
end
I decided to use YAML for config file where I will can change and for WebDriver.
config.yaml:
# Set browser (firefox, ie, chrome, opera)
browser: ":firefox"
# Search query
search_query: "ios testing"
But when I'm running the testcase I'm getting the error:
"test_yaml.rb:11:in `setup'"
You have:
browser = thing('browser')
Did you mean:
browser = thing['browser']
If you're trying to access the browser key, that should take care of it.
Thank you!
I resolved the issue:
require "test/unit"
require "selenium-webdriver"
require "yaml"
class Test < Test::Unit::TestCase
def setup
thing = YAML.load_file('config.yaml')
puts thing.inspect
browser = thing['browser'].to_sym
#driver = Selenium::WebDriver.for browser
#driver.get 'http://google.com'
#driver.manage.delete_all_cookies
end
def teardown
# #driver.close
end
def test_page_search
end
end
hi getting error which is not understand able i am new to ruby so please help .
i checked all thing which is possible for me.
require 'rubygems'
require 'selenium-webdriver'
require 'test/unit'
class SeleniumTest < Test::Unit::TestCase
driver = Selenium::WebDriver.for :firefox
driver.get "http://localhost:9000/assets/build/index.html#/login"
element = driver.find_element :name => "email"
element.send_keys "kaushik#abc.com"
element = driver.find_element :name => "password"
element.send_keys "password"
element.submit
page.find(:xpath, "//a[#href='#/courses/new']").click
#click_link ("//a[#href='#/courses/new']")
puts "Page title is #{driver.title}"
#page.should have_selector(:link_or_button, ' Create New Course...')
wait = Selenium::WebDriver::Wait.new(:timeout => 2000)
driver.quit
end
getting This error:-
TestClass.rb:7:in `<class:SeleniumTest>': undefined local variable or method `logger' for SeleniumTest:Class (NameError)
from TestClass.rb:6:in `<main>'
It seems that you didn't included the complete source code.
Besides that, all you code is bare in class SeleniumTest. You should put your code into the appropriate method or methods.
This type of errors are generated when objects or methods are not created or not scoped well.
In your case, the error message is telling you that the object logger in line 7 of you script does not exist.
As I can see from your source code, line 7 falls into the class definition. I guess you have something like
logger.log 'logging text'
in that line but you delete it from your post, and in lines 4 and 5 you have something like:
require 'logger'
logger = Logger.new('file.log')
If that is the case, you could put logger = Logger.new('file.log') inside the class definition, or define an instance object of type Logger inside the SeleniumClass class, or a global method or something other for logging messages.
Examples:
class SeleniumTest < Test::Unit::TestCase
logger = Logger.new('file.log')
logger.log "logging text"
...
end
or
class SeleniumTest < Test::Unit::TestCase
def initialize
#logger = Logger.new('file.log')
end
def log(message)
#logger.log mesage
end
...
def some_method_with_your_code
...
log "logging text"
...
end
end
st = SeleniumTest.new
st.some_method_with_your_code
... or something similar...
I hope this can help you solve your problem.
If not, you should put the complete source code and tell us what are you trying to do!
I am using the Selenium Webdriver libraries in Ruby. A typical piece of code looks like this:
require 'rubygems'
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
# driver is an instance of Selenium::WebDriver::Driver
url = 'http://www.google.com/'
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
driver.get(url)
wait.until { driver.title.start_with? "Google" }
I would like to create a subclass of Selenium::WebDriver::Driver called Selenium::WebDriver::Driver::MyClass that will contain some new methods and instance variables.
As the above code illustrates, the way that instances of Selenium::WebDriver::Driver are created is with Selenium::WebDriver.for.
Without wholesale copying of code, how can I create a version of Selenium::WebDriver.for that does the same thing as Selenium::WebDriver.for but creates instances of Selenium::WebDriver::Driver::MyClass?
Why not just override the Selenium::WebDriver.for ? let me show you that my an example
# selenium code
module Selenium
class WebDriver
def self.for
puts "creating oldclass"
end
end
end
# your code
class Selenium::WebDriver
def self.for
puts "creating myclass"
end
end
Selenium::WebDriver.for
output:
creating myclass
Safe alternative is to derive class from Selenium::WebDriver and use that in your code, or to the extreme you can just open Driver class and add your behavior to it.
Check the source code. Selenium::WebDriver.for simply delegate the method call to Selenium::WebDriver::Driver.for.
If you don't have listener attached, you can simple create your own bridge MyClass::Bridge.new and then pass that to Selenium::WebDriver::Driver.new.
If you insist override the for method, here is some code snippet that might help.
module Selenium
module WebDriver
class Driver
class << self
alias_method :old_for, :for
def for(browser, opts = {})
if browser == :myclass
# create your MyClass::Bridge instance and pass that to new()
else
old_for(browser, opts)
end
end
end
end
end
end
If you just want to define some extra methods on your driver, you do not need to override WebDriver.for.
The following worked well for me:
First, in file customdriver.rb
require 'selenium-webdriver'
class CustomDriver < Selenium::WebDriver::Driver
#a custom method..
def click_on (_id)
element = find_element :id => _id
element.click
end
#add other custom methods here
#....
end
Then, in file main.rb
require-relative 'customdriver'
driver = CustomDriver.for :chrome
driver.click_on("buttonID")
Regards,
I've got this simple test case that tests a login form.
For some reason webdriver refuses to run the test and comes back with a "too many redirects" message. The page is just an ordinary login screen, very simple and there are no redirects whatsoever. Access from the server to the page seems ok.
I'm using selenium-webdriver-2.25.0 on a centos server.
Below the error message:
(...)
[WARNING] MultiJson is using the default adapter (ok_json). We recommend loading a different JSON library to improve performance.
EE
Finished in 0.206445 seconds.
1) Error: test_login(Login):
Selenium::WebDriver::Error::WebDriverError: too many redirects
/usr/lib/ruby/gems/1.8/gems/selenium-webdriver-2.25.0/lib/selenium/webdriver/remote/http/default.rb:62:in `request'
/usr/lib/ruby/gems/1.8/gems/selenium-webdriver-2.25.0/lib/selenium/webdriver/remote/http/default.rb:63:in `request'
/usr/lib/ruby/gems/1.8/gems/selenium-webdriver-2.25.0/lib/selenium/webdriver/remote/http/common.rb:40:in `call'
(...)
My code:
require "rubygems"
require "selenium-webdriver"
require "test/unit"
class Login < Test::Unit::TestCase
def setup
#driver =Selenium::WebDriver.for(:remote, :url => "http://selenium.server.com/wd/hub")
#base_url = "http://www.myservice.com"
#driver.manage.timeouts.implicit_wait = 30
#verification_errors = []
end
def teardown
#driver.quit
assert_equal [], #verification_errors
end
def test_login
#driver.get(#base_url + "/login/")
#driver.find_element(:id, "username").clear
#driver.find_element(:id, "username").send_keys "user#server"
#driver.find_element(:id, "password").clear
#driver.find_element(:id, "password").send_keys "mykeys!"
#driver.find_element(:xpath, "//input[#value='Login']").click
verify { assert element_present?(:link, "Logout") }
verify { assert element_present?(:link, "Settings") }
verify { assert element_present?(:link, "Products") }
end
def element_present?(how, what)
#driver.find_element(how, what)
true
rescue Selenium::WebDriver::Error::NoSuchElementError
false
end
def verify(&blk)
yield
rescue Test::Unit::AssertionFailedError => ex
#verificatiohttp://jenkins.dev.emesa-auctions.com/cms/n_errors << ex
end
end
UPDATE
It seems that no matter what url I use for the 'base url' the errors keeps occuring.
I managed to solve this problem myself. The issue was that I was accessing the server through its public facing url (selenium.server.com) instead of through the internal lan url (which bypass the firewall).
Changing that fixed the problem.