unable to locate element in Ruby simple script fail - ruby

When I run the script:
require 'rubygems'
require 'watir-webdriver'
#browser = Watir::Browser.new :firefox
def adopt_puppy_number(num)
#browser.button(:value => 'View details', :index => num - 1).click
#browser.button(:value => 'Adopt Me!').click
end
#browser.goto 'http://puppies.herokuapp.com'
adopt_puppy_number 1
#browser.button(:value => 'Adopt Another Puppy').click
adopt_puppy_number 2
I get the exception:
/var/lib/gems/1.9.1/gems/watir-webdriver-0.9.1/lib/watir-webdriver/elements/element.rb:536:in `assert_element_found': unable to locate element, using {:value=>"View details", :index=>0, :tag_name=>"button"} (Watir::Exception::UnknownObjectException)
from /var/lib/gems/1.9.1/gems/watir-webdriver-0.9.1/lib/watir-webdriver/elements/element.rb:508:in `assert_exists'
from /var/lib/gems/1.9.1/gems/watir-webdriver-0.9.1/lib/watir-webdriver/elements/element.rb:114:in `click'
from /home/giz/Downloads/RubymineProjects/learn_watir/thirdscript_dry.rb:6:in `adopt_puppy_number'
from /home/giz/Downloads/RubymineProjects/learn_watir/thirdscript_dry.rb:11:in `<top (required)>'
from -e:1:in `load'
from -e:1:in `<main>'
Why? Maybe I should add a wait command, but where exactly and which one?

The HTML for the View Details button is:
<input class="rounded_button" value="View Details" type="submit">
Notice that the value attribute is "View Details" not "View details". Watir's locators are case-sensitive, which is the element is not found. The adopt_puppy_number method should be:
def adopt_puppy_number(num)
#browser.button(:value => 'View Details', :index => num - 1).click
#browser.button(:value => 'Adopt Me!').click
end

Related

ArgumentError when accessing pageobject widget

class MainTabsWidget < PageObject::Elements::UnorderedList
include PageObject
include PageObject::PageFactory
link(:first_link, :text => 'First')
link(:second_link, :text => 'Second')
link(:third_link, :text => 'Third')
link(:category_link, :text => 'Category')
link(:subcat1_link, :text => 'Subcat1')
link(:subcat2_link, :text => 'Subcat2')
def goto_tab_item(tab_item)
items = tab_item.split /\//
items.each do |item|
case item
when 'First'
first_link
when 'Second'
second_link
when 'Third'
third_link
when 'Category'
category_link
when 'Subcat1'
subcat1_link
when 'Subcat2'
subcat2_link
end
end
end
end
PageObject.register_widget :main_menu, MainTabsWidget , :ul
I have a page called landing page that uses the widget in the following manner....
class LandingPage
include PageObject
include PageObject::PageFactory
main_menu(:menu_tabs, :id => 'mainMenu')
def select_menu_item(item)
menu_tabs_element.go_to_tab_item item
end
end
This actually did work at one point. If you pass 'First' for select_menu_item, it will click to the page specified by first_link. If you specify 'Category/Subcat1' it will click on the category link and then subcat1.
Howerver, something changed. We are transition from watir-webdriver gem to watir (6.10) gem, and now the code gets the argument exeption
'ArgumentError: wrong number of arguments (0 for 1..2)'
This occurs when menu_tabs_element gets referenced in any way. I've run out of ideas to remedy this.
Stack Trace:
ArgumentError: wrong number of arguments (0 for 1..2)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page-object-2.2.4/lib/page-object/element_locators.rb:10:in `element'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page-object-2.2.4/lib/page-object/elements/element.rb:191:in `respond_to_missing?'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page-object-2.2.4/lib/page-object.rb:53:in `respond_to_missing?'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page-object-2.2.4/lib/page-object.rb:70:in `respond_to?'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page-object-2.2.4/lib/page-object.rb:70:in `initialize'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page-object-2.2.4/lib/page-object/platforms/watir/page_object.rb:1047:in `new'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page-object-2.2.4/lib/page-object/platforms/watir/page_object.rb:1047:in `find_watir_element'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page-object-2.2.4/lib/page-object/platforms/watir/page_object.rb:1118:in `block in define_widget_singular_accessor'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page-object-2.2.4/lib/page-object/widgets.rb:38:in `block (3 levels) in define_accessors'
./lib/pages/menu.rb:13:in `select_menu_item'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page_navigation-0.10/lib/page_navigation.rb:134:in `block in navigate_through_pages'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page_navigation-0.10/lib/page_navigation.rb:129:in `each'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page_navigation-0.10/lib/page_navigation.rb:129:in `navigate_through_pages'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/page_navigation-0.10/lib/page_navigation.rb:67:in `navigate_to'
./spec/refactor/test_spec.rb:6:in `block (2 levels) in <top (required)>'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/hooks.rb:350:in `instance_exec'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/hooks.rb:350:in `run'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/hooks.rb:509:in `block in run_owned_hooks_for'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/hooks.rb:508:in `each'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/hooks.rb:508:in `run_owned_hooks_for'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/hooks.rb:460:in `run'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/example_group.rb:537:in `block in run_before_context_hooks'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/memoized_helpers.rb:186:in `block in isolate_for_context_hook'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/memoized_helpers.rb:182:in `instance_exec'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/memoized_helpers.rb:182:in `isolate_for_context_hook'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/example_group.rb:536:in `run_before_context_hooks'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/example_group.rb:589:in `run'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:118:in `block (3 levels) in run_specs'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:118:in `map'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:118:in `block (2 levels) in run_specs'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1896:in `with_suite_hooks'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:113:in `block in run_specs'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/reporter.rb:79:in `report'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:112:in `run_specs'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:87:in `run'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:71:in `run'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:45:in `invoke'
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rspec-core-3.7.0/exe/rspec:4:in `<top (required)>'
C:/Ruby22/bin/rspec:23:in `load'
C:/Ruby22/bin/rspec:23:in `<top (required)>'
-e:1:in `load'
-e:1:in `<main>'
1 example, 1 failure, 0 passed
Finished in 6.087 seconds
Process finished with exit code 1
It is not clear to me which change in Watir would cause this issue. It seems more likely a change in Page-Object. At any rate, here are 2 solutions. Note that this was tested with Page-Object v 2.2.4.
Using Widgets
As pointed out by Alexis in Page-Object Issue 263, including page object accessor methods in widgets is not as straight forward as one would expect. In the MainTabsWidget class, instead of include PageObject, you need to do:
extend PageObject::Accessors # to get the accessor methods
attr_reader :platform # the accessor methods don't work without a platform
With this change, your page object should work.
Using Page Section
Page-Object has a page section feature that might better suit your needs. It simplifies some of the code (ie address the above issue).
You define a class to represent your main tabs section. Note that you do not need to register the section or have the multi-line setup as with Widgets.
class MainTabs
include PageObject
include PageObject::PageFactory
link(:first_link, :text => 'First')
link(:second_link, :text => 'Second')
link(:third_link, :text => 'Third')
link(:category_link, :text => 'Category')
link(:subcat1_link, :text => 'Subcat1')
link(:subcat2_link, :text => 'Subcat2')
def select_menu_item(tab_item)
items = tab_item.split /\//
items.each do |item|
case item
when 'First'
first_link
when 'Second'
second_link
when 'Third'
third_link
when 'Category'
category_link
when 'Subcat1'
subcat1_link
when 'Subcat2'
subcat2_link
end
end
end
end
The page object can simply become:
class LandingPage
include PageObject
include PageObject::PageFactory
page_section(:menu_tabs, MainTabs, :id => 'mainMenu')
end
The clicking of the menu would change to:
page.menu_tabs.select_menu_item('First')
(or you could continue to define a #select_menu_item method in LandingPage to avoid downstream changes)

POST method in ruby does not insert data into the table

I just started to learn programming. I study the book Jump start Sinatra by Darren Johnson.
I did everything as stated in the book, but insert a new entry in the table at me is not working. I click on the button "Save Song" but nothing happens.
At the same time modify existing records I can.
My main.rb
require 'sinatra'
require 'sinatra/reloader' if development?
require 'slim'
require 'sass'
require './song'
set :public_folder, 'public'
set :views, 'views'
get('/styles.css'){ scss :styles }
get '/' do
slim :home
end
get '/about' do
#title = "All About This Website"
slim :about
end
get '/contact' do
slim :contact
end
not_found do
slim :not_found
end
My song.rb
require 'dm-core'
require 'dm-migrations'
configure do
DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/development.db")
end
class Song
include DataMapper::Resource
property :id, Serial
property :title, String
property :lyrics, Text
property :length, Integer
property :released_on, Date
def released_on=date
super Date.strptime(date, '%m/%d/%Y')
end
end
DataMapper.finalize
get '/songs' do
#songs = Song.all
slim :songs
end
get '/songs/new' do
#song = Song.new
slim :new_song
end
get '/songs/:id' do
#song = Song.get(params[:id])
slim :show_song
end
post '/songs' do
song = Song.create(params[:song])
redirect to("/songs/#{song.id}")
end
get '/songs/:id/edit' do
#song = Song.get(params[:id])
slim :edit_song
end
put '/songs/:id' do
song = Song.get(params[:id])
song.update(params[:song])
redirect to("/songs/#{song.id}")
end
My views/song_form.slim
label for="title" Title:
input#title type="text" name="song[title]" value="#{#song.title}"
label for="length" Length:
input#length type="number" name="song[length]" value="#{#song.length}"
label for="released_on" Date(mm/dd/yyyy):
input#released_on type="text" name="song[released_on]" value="#{#song.released_on.strftime("%m/%d/%Y") if #song.released_on}"
label for="lyrics" Lyrics:
textarea#lyrics name="song[lyrics]" == #song.lyrics
input type="submit" value="Save Song"
My views/edit_song.slim
h1 Edit Song
form method="POST" action="/songs/#{#song.id}"
input type="hidden" name="_method" value="PUT"
== slim :song_form
When I try to add a new table record in IRB:
irb(main):001:0> require './song'
NoMethodError: undefined method `get' for main:Object
from /media/kamrenov/other/work/sinatra/song.rb:21:in `<top (required)>'
from /home/kamrenov/.rbenv/versions/2.2.1/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
from /home/kamrenov/.rbenv/versions/2.2.1/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
from (irb):1
from /home/kamrenov/.rbenv/versions/2.2.1/bin/irb:11:in `<main>'

Ruby not breaking out of while loop

I'm trying to get this to loop while a specific element exists on the page. The code runs and grabs the urls I want, however, when the next button is no longer on the page it wont break out of the loop and throws the following error.
/Users/someone/.rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/rspec-expectations-3.2.0/lib/rspec/matchers.rb:926:in `method_missing': undefined method `each' for nil:NilClass (NoMethodError)
from /something/something/something.rb:30:in `block in <top (required)>'
from /something/something/something.rb:28:in `open'
from /something/something/something.rb:29:in `<top (required)>'
from -e:1:in `load'
from -e:1:in `<main>'</code>
Brand new to Ruby, so please be gentle ;)
require 'capybara/poltergeist'
require 'capybara/dsl'
require 'csv'
require 'rspec'
include RSpec::Matchers
include Capybara::DSL
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app,timeout: 60, :phantomjs_options => ['--debug=no', '--load-images=yes', '--ignore-ssl-errors=yes', '--ssl-protocol=TLSv1'], :debug => false)
end
Capybara.default_driver = :poltergeist
Capybara.javascript_driver = :poltergeist
Capybara.default_wait_time = 20
Capybara.ignore_hidden_elements = true
Capybara.current_session.driver.resize(1200, 1000)
visit('site.com')
while page.find(:xpath, 'html/body/div[4]/div[6]/div[1]/div[2]/div[2]/div[1]/div[2]/button[1]') do
page.find(:xpath, 'html/body/div[4]/div[6]/div[1]/div[2]/div[2]/div[1]/div[2]/button[1]').click
urls = page.all('.author-name>a').map { |a| a['href'] }.uniq
puts urls
end
puts urls
f = File.open("profiles.txt", "a") do |f|
urls.each { |element| f.puts(element) }
end

Why is Mechanize returning "undefined method 'value=' for nil:NilClass" when trying to set a password?

I wrote a script with Mechanize to scrape some links, which later I will write code to put into an Excel file.
For now I can't authenticate past the first page. I keep getting an undefined method value= for nil:NilClass when attempting to set the password in the form and haven't been able to find any information on it.
I don't even have the method value= in my code so I don't understand what is going on. The code runs fine for the username, but once I enter the password and hit enter I get the error:
users.rb:11:in `block (2 levels) in <main>': undefined method `value=' for nil:NilClass (NoMethodError)
from (eval):23:in `form_with'
from formity_users.rb:7:in `block in <main>'
from /home/codelitt/.rvm/gems/ruby-2.0.0-p247/gems/mechanize-2.7.1/lib/mechanize.rb:433:in `get'
from formity_users.rb:5:in `<main>'
This is my users.rb script:
require 'rubygems'
require 'mechanize'
a = Mechanize.new
a.get('https://www.example.com') do |page|
#Enter information into forms
logged_in = page.form_with(:id => 'frmLogin') do |f|
puts "Username?"
f.field_with(:name => "LoginCommand.EmailAddress").value = gets.chomp
puts "Password?"
f.field_with(:name => "Login.Password").value = gets.chomp
end.click_button
#Click drop down
admin_page = logged_in.click.link_with(:text => /Admin/)
#Click Users and enter user admin section
user_admin = admin_page.click.link_with(:text => /Users/)
#Scrape and print links for now
user_admin.links.each do |link|
text = link.text.strip
next unless text.length > 0
puts text
end
end
I think your error is coming from
f.field_with(:name => "Login.Password")
which seems to be nil. For username, I see that you have specified input name LoginCommand.EmailAddress and for password input name is Login.Password.
I'd expect anybody who has written this markup to use consistent names. Maybe you should look that the underlying html to see you're using correct field names in your code.

Can the description mentioned code using Selenium-driver be implemented in mechanize?

Could anyone help me by giving small tips mentioning how the below can be written in Mechanize? I am totally new to the Gem Mechanize.
require "rubygems"
require "selenium-webdriver"
driver = Selenium::WebDriver.for :firefox
driver.get "https://www.example.com/"
element = driver.find_element :name => "username"
element.send_keys "#####"
element = driver.find_element :name => "password"
element.send_keys "******"
element.submit
element = driver.find_element(:name, "btnHome")
element.click
element=driver.find_element(:link, "Empdetals")
#print element.attribute(:href)
element.click
element = driver.find_element :name => "search.empdirectory"
element.send_keys "#######"
element = driver.find_element :name => "btnSearch"
element.click
driver.current_url
ERROR When I tried the 'mechanzie` version provided by #Prakash
D:\Ruby script>ruby gmail.rb
C:/Ruby193/lib/ruby/gems/1.9.1/gems/net-http-persistent-2.8/lib/net/http/persist
ent/ssl_reuse.rb:70:in `connect': SSL_connect returned=1 errno=0 state=SSLv3 rea
d server certificate B: certificate verify failed (OpenSSL::SSL::SSLError)
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/net-http-persistent-2.8/lib/net
/http/persistent/ssl_reuse.rb:70:in `block in connect'
from C:/Ruby193/lib/ruby/1.9.1/timeout.rb:54:in `timeout'
from C:/Ruby193/lib/ruby/1.9.1/timeout.rb:99:in `timeout'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/net-http-persistent-2.8/lib/net
/http/persistent/ssl_reuse.rb:70:in `connect'
from C:/Ruby193/lib/ruby/1.9.1/net/http.rb:755:in `do_start'
from C:/Ruby193/lib/ruby/1.9.1/net/http.rb:750:in `start'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/net-http-persistent-2.8/lib/net
/http/persistent.rb:628:in `start'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/net-http-persistent-2.8/lib/net
/http/persistent.rb:570:in `connection_for'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/net-http-persistent-2.8/lib/net
/http/persistent.rb:926:in `request'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/mechanize-2.5.1/lib/mechanize/h
ttp/agent.rb:258:in `fetch'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/mechanize-2.5.1/lib/mechanize.r
b:407:in `get'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/mechanize-2.5.1/lib/mechanize.r
b:306:in `click'
from gmail.rb:6:in `block in <main>'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/mechanize-2.5.1/lib/mechanize.r
b:409:in `get'
from gmail.rb:4:in `<main>'
D:\Ruby script>
Yes, mechanize gem can be used to automate any interaction with a website, including logging into a site by submitting the userid/password and clicking on submit button/link, etc.
Unlike selenium-webdriver which makes direct calls to a browser, mechanize itself acts as a browser.
Do checkout the EXAMPLES page on mechanize documentation to learn to how mechanize can be used. The second example - with RubyForge - shows how to login to a site and work with the resultant page.
For a quick overview of how to work with mechanize check out RailsCasts episode on mechanize
Here is an example code for starting at http://www.google.com, clicking on 'Gmail' text, signing into Gmail, and listing the links within the page:
require 'mechanize'
a = Mechanize.new
a.get('http://www.google.com') do |page|
# Click the Gmail link
gmail_login_page = a.click(page.link_with(:text => "Gmail"))
# Submit the login form
gmail_page = gmail_login_page.form_with( :action => 'https://accounts.google.com/ServiceLoginAuth' ) do |f|
f.Email = "<username>#gmail.com"
f.Passwd = "**********"
end.click_button
# List all the links in the personal gmail page
gmail_page.links.each do |link|
text = link.text.strip
next unless text.length > 0
puts text
end
end
Hope it helps in getting started with Mechanize and explore it further!

Resources