Why can't PhantomJS/Poltergeist pull up this website correctly? - ruby

I'm using Capybara to navigate a web page. The url look like this:
http://www.myapp.com/page/ABCXYZ?page=<x>
The page has a paginated table on it. Passing a page number to it will paginate the table appropriately.
However, when using the poltergeist driver, the page parameter is always ignored.
Using the selenium driver is not an option because it's a hassle to get it to run headless, it doesn't want to run more than one time (gives "connection refused" error on localhost).
This looks like an encoding issue, but I'm not sure where exactly in the stack that the issue lies.
class Verifier
class << self
include Capybara::DSL
Capybara.default_driver = :poltergeist
Capybara.default_wait_time = 10
def parse_table(header)
xpath = '//*[#id="products"]/table[3]/tbody/tr/td/div[4]/div/table'
table = find(:xpath, xpath)
rows = []
table.all("tr").each do |row|
product_hash = {}
row.all("td").each_with_index do |col,idx|
product_hash[header[idx]] = col.text
end
rows << product_hash
end
rows
end
def pages
page.find(".numberofresults").text.gsub(" Products","").split(" ").last.to_i/25
end
def import(item)
visit "http://www.myapp.com/page/#{item}"
header = parse_header
apps = parse_vehicles(header)
pages.times do |pagenumber|
url = "http://www.myapp.com/page/#{item}?page=#{pagenumber+1}" # This is the problem
end
end
end
That url in the last loop? It is processes as if the pagenumber is not present. When I change the driver to :selenium, this whole thing works. So it's not a Capybara issue as far as I can see.

Related

Execute code whenever page is navigated

I am looking for a way to detect whenever the current page is navigated in selenium so I can execute some code. I know in C# and Java there are events for this, but I cannot seem to find them in ruby. Can anyone point me in the right direction?
Here's an example, from the doc:
class NavigationListener < Selenium::WebDriver::Support::AbstractEventListener
def initialize(log)
#log = log
end
def before_navigate_to(url, driver)
#log.info "navigating to #{url}"
end
def after_navigate_to(url, driver)
#log.info "done navigating to #{url}"
end
end
listener = NavigationListener.new(logger)
driver = Selenium::WebDriver.for :firefox, :listener => listener
It's probably incomplete but it's a start.

What to set app_host to for Capybara

My tests attempt to visit webpages and verify that certain elements exist on the pages. For example, it visits http://foo.com/homepage.html and checks for a logo image, then visits http://bar.com/store/blah.html and checks that certain text appears on the page. My goal is to visit Kerberos authenticated webpages.
I found Kerberos code as below:
Main file
uri = URI.parse(Capybara.app_host)
kerberos = Kerberos.new(uri.host)
#kerberos_token = kerberos.encoded_token
kerberos.rb file
class Kerberos
def initialize(host)
#host = host
#credentials = AuthGss::Negotiate.new("HTTP##{#host}")
#credentials.cache = ENV['KRB5CCNAME'] if ENV['KRB5CCNAME']
#token = #credentials.step("")
end
def encoded_token
Base64.encode64(#token).gsub(/\n/,"")
end
end
It utilizes Capybara.app_host value. I can't figure out what to set the Capybara.app_host value to. I can't figure out what it does. I have Capybara.run_server = false. Can someone help me understand how to use Capybara.app_host and how this relates to Kerberos authentication?
The Capybara docs show an example of using a remote host. app_host is the base host of your web application:
Capybara.current_driver = :selenium
Capybara.run_server = false
Capybara.app_host = 'http://www.google.com'
visit('/users') # goes to http://www.google.com/users
I was confused about app_host, but after a dig around in the Capybara source code it seems like it doesn't actually do very much. In fact, it only seems to be used at one place in the Capybara source code:
if url_relative && Capybara.app_host
url = Capybara.app_host + url
url_relative = false
end
Basically, if you pass a relative URL like /posts/1/edit to a method like visit, Capybara will visit the URL "#{Capybara.app_host}/posts/1/edit`. So the following two snippets of code are equivalent:
# 1:
Capybara.app_host = "https://stackoverflow.com"
visit "/questions/19991349"
# 2:
visit "https://stackoverflow.com/questions/19991349"
By default RSpec sets app_host to http://localhost, which is why you can write code like before { visit edit_post_path(1) } when using Capybara and Rails straight out of the box, and you don't have to write localhost every time.

Save page with css, js and images using watir

How can I save page with all its content using watir-webdriver?
browser.html save only browser's elements. If I open file where I dumped browser.html there is no styling.
Also browser.html doesn't save iframes. I can loop through iframes and save them separately, but they will be separated from the main page.
I record only htmls for now, maybe later I'll save screenshots, because there is no simple way to dump whole page with its css and images.
require 'fileutils'
class Recorder
attr_reader :request, :counter, :browser
# request should contain w(login_id start_time)
def initialize(request)
#request, #counter = request, 1
# Settings class contains my configs (enable recording, paths, etc.)
FileUtils.mkpath(path) if Settings.recorder.record and !File.exists?(path)
end
def record(hash)
return unless Settings.recorder.record
#browser = hash["browser"]
record_html(hash)
record_frames(hash)
#counter += 1
end
private
# hash should contain (method_name browser)
def record_html(hash)
File.open("#{path}#{generate_file_name(hash)}", "w") do |file|
file.write("<!--#{browser.url}-->\n")
file.write(browser.html)
end
end
def record_frames(hash)
browser.frames.each_with_index do |frame, index|
File.open("#{path}#{generate_file_name(hash, index + 1)}", "w") do |file|
file.write("<!--#{browser.url}-->\n")
file.write(frame.html)
end
end
end
def path
"#{Settings.recorder.path}/#{request["login_id"]}/#{request["start_time"]}/"
end
def generate_file_name(hash, frame=nil)
return "#{counter}-#{hash["method_name"]}.html" if frame.nil?
"#{counter}-frame#{frame}-#{hash["method_name"]}.html"
end
end
I don't know about Watir but for those who might want to save a page (including CSS and JavaScript that are directly in the page) using Selenium WebDriver (which Watir wraps around), the easiest way is to use the page_source method (of the WebDriver class). As its name suggests, it gives so whole source. Then it's just a matter of saving to a new file, like so :
driver = Selenium::WebDriver.for(:firefox)
driver.get(URL_of_page_to_save)
file = File.new(filename, "w")
file.puts(driver.page_source)
file.close
It won't save the JavaScript or CSS inside other files though.

Ruby Threads with Watir

I have several classes written that govern how I want to handle several websites, with similar methods in both (ie. login, refresh). Each class opens up its own WATIR browser instance.
class Site1
def initialize
#ie = Watir::Browser.new
end
def login
#ie.goto "www.blah.com"
end
end
a sample of code in the main with no threads is as follows
require 'watir'
require_relative 'site1'
agents = []
agents << Site1.new
agents.each{ |agent|
agent.login
}
This works fine, but doesnt move onto the next agent until the current one has finished logging in. I would like to incorporate multithreading to handle this, but cant seem to get it to work.
require 'watir'
require_relative 'site1'
agents = []; threads = []
agents << Site1.new
agents.each{ |agent|
threads << Thread.new(agent){ agent.login }
}
threads.each { |t| t.join }
this gives me the error: unknown property or method: navigate. HRESULT error code:0x8001010e. The application called an interface that was marshalled for a different thread.
does anyone know how to fix this, or how to implement a similar functionality?
Not really sure on this, but here is a swing using threads.
require 'thread'
threads = [] # Setting an array to store threaded commands
c_thread = Thread.new do # Start a new thread
login # Call our command in the thread
end
threads << c_thread

DELAYED_JOB Update_attribute in delayed job is not working, table not updated

I has been wanted to do the Delayed::Job which to do the fbLikes ( I post a lot on StackOverFlow but still haven't solve the problem yet) My table n database have name, id, fbLikes, fbId, url.
Here is my steps for the program.
[Home Page]company list -> Create a Company[Insert A company infos] ->Save fbId, name, id, url BUT NOT FBLIKES -> redirect to HomePage [after_save Update the fbLikes for the previous added company]
I not sure whether my delayed job is working or not because my fbLikes in my model is still blank and not updated with latest fbLikes.I not sure is there a better way to do this.
For "rake jobs:work" there is no background work display in the console.
[MODEL company.rb]
require "delayed_job"
require "count_job.rb"
after_save :fb_likes
def fb_likes
Delayed::Job.enqueue(CountJob.new(self.id))
end
[lib/count_job.rb]
require 'net/http'
require 'company.rb'
class CountJob < Struct.new(:id)
def perform
#company = Company.find(id)
uri = URI("http://graph.facebook.com/#{#company.fbId}")
data = Net::HTTP.get(uri)
#company.fbLikes= JSON.parse(data)['likes']
#company.save!
end
end
[MODEL company.rb]
require "delayed_job"
require "count_job.rb"
after_save :fb_likes
def fb_likes
Delayed::Job.enqueue(CountJob.new(self.id))
end
[lib/count_job.rb]
require 'net/http'
require 'company.rb'
class CountJob < Struct.new(:id)
def perform
#company = Company.find(id)
uri = URI("http://graph.facebook.com/#{#company.fbId}")
data = Net::HTTP.get(uri)
#company.fbLikes= JSON.parse(data)['likes']
#company.save!
end
end

Resources