Selenium webdriver with Ruby : Use existing session id - ruby

I am new to selenium web driver and currently working with the Ruby programming language. I currently have a scenario where I need to execute multiple ruby scripts with the selenium web driver but they have to use the same browser session. I am following the documentation provided in the following link: https://github.com/SeleniumHQ/selenium/wiki/Ruby-Bindings
Currently, my code looks like the following.
require 'selenium-webdriver'
# ---------------------------------------------------------
url = "http://localhost:4444/wd/hub"
driver1 = Selenium::WebDriver.for :remote, url: url, desired_capabilities: :firefox
driver1.get "http://www.msn.com"
puts driver1.title
# store the session id
sessionid = driver1.session_id
# ---------------------------------------------------------
# Try using the existing session id from driver1
driver2 = Selenium::WebDriver.for :remote, url: url, desired_capabilities: :firefox
# The below statement gives error on assignment
driver2.session_id = sessionid
driver2.get "http://www.yahoo.com"
I read this post Can Selenium interact with an existing browser session? and tried to follow the steps provided here unable to use an existing web-driver / browser session.
Has anyone successfully reused the existing session with selenium-webdriver along with Ruby? Kindly let me know what is being missed in this code snippet.
I was able to get this done in python.
from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
executor_url = "http://localhost:4444/wd/hub"
# Create a desired capabilities object as a starting point.
capabilities = DesiredCapabilities.FIREFOX.copy()
capabilities['platform'] = "WINDOWS"
capabilities['version'] = "10"
# ------------------------ STEP 1 --------------------------------------------------
# driver1 = webdriver.Firefox()
driver1 = webdriver.Remote(command_executor=executor_url, desired_capabilities=capabilities)
driver1.get('http://google.com/')
url = driver1.command_executor._url
print(driver1.command_executor._url)
print(driver1.session_id)
print(driver1.title)
# Serialize the session id in a file
session_id = driver1.session_id
# ------------------ END OF STEP 1 --------------------------------------------------
# Pass the session id from step 1 to step 2
# ------------------------ STEP 2 --------------------------------------------------
def attach_to_session(executor_url, session_id):
original_execute = WebDriver.execute
def new_command_execute(self, command, params=None):
if command == "newSession":
# Mock the response
return {'success': 0, 'value': None, 'sessionId': session_id}
else:
return original_execute(self, command, params)
# Patch the function before creating the driver object
WebDriver.execute = new_command_execute
temp_driver = webdriver.Remote(command_executor=executor_url)
# Replace the patched function with original function
WebDriver.execute = original_execute
return temp_driver
# read the session id from the file
driver2 = attach_to_session(executor_url, session_id)
driver2.get('http://msn.com/')
print(driver2.command_executor._url)
print(driver2.session_id)
print(driver2.title)
driver2.close()

I was able to solve this issue by using the following code patch.
class RemoteWebDriver < Selenium::WebDriver::Driver
def initialize(bridge)
#bridge = bridge
end
end
class RemoteBridge < Selenium::WebDriver::Remote::Bridge
def self.handshake(**opts)
capabilities = opts.delete(:desired_capabilities) { Capabilities.new }
#session_id = opts.delete(:session_id)
Selenium::WebDriver::Remote::W3C::Bridge.new(capabilities, #session_id, **opts)
end
end
caps = Selenium::WebDriver::Remote::Capabilities.firefox()
remote_bridge = RemoteBridge.handshake(url: <YOUR_REMOTE_WEB_DRIVER_URL>, desired_capabilities: caps, session_id: <YOUR_SESSION_ID>)
remote_web_driver = RemoteWebDriver.new(remote_bridge)

Related

Unable to upload and image in googledrive using goolge ruby API

I am first time using Google APIs. I am unable to upload any file in Google Drive. I tried below complete code.
require 'google/apis/drive_v2'
require 'google/api_client/client_secrets'
# I downloaded 'client_secrets.json' file from 'https://console.developers.google.com/projectselector/apis/library' and put in lib folder
CLIENT_SECRETS_FILE = "client_secrets.json"
client_secrets_filepath = File.expand_path(CLIENT_SECRETS_FILE ,"#{File.dirname(__FILE__)}/../../lib/")
CLIENT_SECRETS = Google::APIClient::ClientSecrets.load(client_secrets_filepath)
authorization = CLIENT_SECRETS.to_authorization
Drive = Google::Apis::DriveV2
#drive = Drive::DriveService.new
#drive.authorization = authorization
file_path = File.expand_path(#ScreenShot_dir)+'/'+"imageName" +'.png'
metadata = Drive::File.new(title: 'My document')
metadata = #drive.insert_file(metadata, upload_source: file_path, content_type: 'image/png')
It is not uploading the file in drive but giving an error like "missing authorization code".
my client_secrets.json look like below:
{"installed":{
"client_id":"<some digits>.apps.googleusercontent.com",
"project_id":"<projectname>","auth_uri":"https://accounts.google.com/o/oauth2/auth",
"token_uri":"https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
"client_secret":"<secret key>",
"redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}
I am not sure what I am missing in it. Appreciate any help on this issue.
"missing authorization code"
Means that you have not properly authenticated your code.
You should check the Ouath2 documentation for the client library. Get one of the samples there working then you should be able to alter it for Drive without to much trouble.
# AdSense Management API command-line sample.
require 'google/apis/adsense_v1_4'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/installed_app'
require 'google/api_client/auth/storage'
require 'google/api_client/auth/storages/file_store'
require 'logger'
require 'json'
CREDENTIAL_STORE_FILE = "#{$0}-oauth2.json"
# Handles authentication and loading of the API.
def setup
log_file = File.open('adsense.log', 'a+')
log_file.sync = true
logger = Logger.new(log_file)
logger.level = Logger::DEBUG
adsense = Google::Apis::AdsenseV1_4::AdSenseService.new
# Stores auth credentials in a file, so they survive multiple runs
# of the application. This avoids prompting the user for authorization every
# time the access token expires, by remembering the refresh token.
# Note: FileStorage is not suitable for multi-user applications.
storage = Google::APIClient::Storage.new(
Google::APIClient::FileStore.new(CREDENTIAL_STORE_FILE))
adsense.authorization = storage.authorize
if storage.authorization.nil?
client_secrets = Google::APIClient::ClientSecrets.load
# The InstalledAppFlow is a helper class to handle the OAuth 2.0 installed
# application flow, which ties in with Stroage to store credentials
# between runs.
flow = Google::APIClient::InstalledAppFlow.new(
:client_id => client_secrets.client_id,
:client_secret => client_secrets.client_secret,
:scope => ['https://www.googleapis.com/auth/adsense.readonly']
)
adsense.authorization = flow.authorize(storage)
end
return adsense
end
# Generates a report for the default account.
def generate_report(adsense)
report = adsense.generate_report(start_date: '2011-01-01', end_date: '2011-08-31',
metric: %w(PAGE_VIEWS AD_REQUESTS AD_REQUESTS_COVERAGE
CLICKS AD_REQUESTS_CTR COST_PER_CLICK
AD_REQUESTS_RPM EARNINGS),
dimension: %w(DATE),
sort: %w(+DATE))
# Display headers.
report.headers.each do |header|
print '%25s' % header.name
end
puts
# Display results.
report.rows.each do |row|
row.each do |column|
print '%25s' % column
end
puts
end
end
if __FILE__ == $0
adsense = setup()
generate_report(adsense)
end

How to write a hash to work with a two parameter splat

I am trying to pass some additional options to a Selenium web driver for running JavaScript tests using Teaspoon. I am unable to get it to recognize the opts.
My config code:
client = Selenium::WebDriver::Remote::Http::Default.new
client.timeout = 180 # 3 mins instead of the default 60 seconds
config.driver_options = HashWithIndifferentAccess.new(client_driver: [:firefox, {http_client: client}])
Given the library code that uses my config options:
driver = ::Selenium::WebDriver.for(driver_options[:client_driver])
where the ::Selenium::WebDriver.for function is defined as:
def self.for(*args)
WebDriver::Driver.for(*args)
end
where WebDriver::Driver.for is defined as:
def for(browser, opts = {})
listener = opts.delete(:listener)
bridge = case browser
when :firefox, :ff
Firefox::Bridge.new(opts)
when :remote
Remote::Bridge.new(opts)
when :ie, :internet_explorer
IE::Bridge.new(opts)
when :chrome
Chrome::Bridge.new(opts)
when :android
Android::Bridge.new(opts)
when :iphone
IPhone::Bridge.new(opts)
when :opera
Opera::Bridge.new(opts)
when :phantomjs
PhantomJS::Bridge.new(opts)
when :safari
Safari::Bridge.new(opts)
else
raise ArgumentError, "unknown driver: #{browser.inspect}"
end
bridge = Support::EventFiringBridge.new(bridge, listener) if listener
new(bridge)
end
How do I pass in a (string, hash) for (browser, opts)? With what I have tried, the whole hash [:firefox, {http_client: client}] gets passed into the browser variable.

GitHub Archive - Issues with retrieving data with ranges

I am trying to retrieve data from [GitHub Archive]: https://www.githubarchive.org/ and is having trouble retrieving data when I add a range. It works when I use http://data.githubarchive.org/2015-01-01-15.json.gz, but getting a `open_http': 404 Not Found (OpenURI::HTTPError) message when using http://data.githubarchive.org/2015-01-01-{0..23}.json.gz.
Using curl http://data.githubarchive.org/2015-01-01-{0..23}.json.gz seems to be working.
Basically, my goal is to write a program to retrieve the top 42 most active repositories over a certain time range.
Here's my code, please let me know I'm using the API incorrectly or code issues.
require 'open-uri'
require 'zlib'
require 'yajl'
require 'pry'
require 'date'
events = Hash.new(0)
type = 'PushEvent'
after = '2015-01-01T13:00:00Z'
before = '2015-01-02T03:12:14-03:00'
f_after_time = DateTime.parse(after).strftime('%Y-%m-%d-%H')
f_after_time = DateTime.parse(before).strftime('%Y-%m-%d-%H')
base = 'http://data.githubarchive.org/'
# query = '2015-01-01-15.json.gz'
query = '2015-01-01-{0..23}.json.gz'
url = base + query
uri = URI.encode(url)
gz = open(uri)
js = Zlib::GzipReader.new(gz).read
Yajl::Parser.parse(js) do |event|
if event['type'] == type
if event['repository']
repo_name = event['repository']['url'].gsub('https://github.com/', '')
events[repo_name] +=1
elsif event['repo'] #to account for older api
repo_name = event['repo']['url'].gsub('https://github.com/', '')
events[repo_name] +=1
end
end
end
# Sort events based on # of events and return top 42 repos
sorted_events = events.sort_by {|_key, value| value}.reverse.first(42)
sorted_events.each { |e| puts "#{e[0]} - #{e[1]} events" }
I believe brackets are not allowed in URL, so maybe you should try urlencoding it?

Ruby 2.2.0 Google Drive OAuth refresh

I am trying to setup a command line backup app in ruby which accesses Google Drive using Oauth. I have set everything up in the account, created my Client ID and Secret. I seem to remember doing this before but cannot find the code. I used this answer before I think: Ruby google_drive gem oAuth2 saving
I have made a class to handle the Google Drive stuff then there is the applications main file which if given "hard" as an argument will do the initial setup where you have to copy and paste the link into the web browser in order to get a code which you can then paste into the CLI to get the initial access token and refresh token. This works and following these steps my list method (when not commented out) correctly lists everything in Google Drive. When I do the initial setup I am manually copying the access and refresh tokens to .access_token and .refresh_token, these are loading in the code fine.
What is not working, is refreshing the token which I understand I need to do otherwise it will expire, meaning I will have to go through the initial setup again which is obviously a pain (and not suitable for a CRON job). I am getting the following error when I run #auth.refresh!
/home/user/.rvm/gems/ruby-2.2.0/gems/signet-0.6.0/lib/signet/oauth_2/client.rb:947:in `fetch_access_token': Authorization failed. Server message: (Signet::AuthorizationError)
{
"error" : "invalid_grant"
}
from /home/user/.rvm/gems/ruby-2.2.0/gems/signet-0.6.0/lib/signet/oauth_2/client.rb:964:in `fetch_access_token!'
from /home/user/.rvm/gems/ruby-2.2.0/gems/signet-0.6.0/lib/signet/oauth_2/client.rb:981:in `refresh!'
from /home/user/Development/BackupBadger/Sources/Mechanisms/GoogleDriveMechanism.rb:62:in `connect'
from BackupBadger.rb:9:in `<main>'
I have had a look to see what it might be but am for the moment stuck on why this error is triggering when I can seemingly authenticate (since I can list all files on the drive)
My main file
$root=File.join('/home/user/Development/BackupBadger')
$sources=File.join($root,'Sources')
require File.join($sources,'Mechanisms','GoogleDriveMechanism.rb')
badger = BackupBadger::GoogleDriveMechanism.new
if ARGV[0] == "hard" then
badger.hard_setup
else
badger.connect
#badger.list
end
My class Google Drive
module BackupBadger
require 'google/api_client'
require 'google_drive'
require 'pp'
require File.join($sources,'Mechanism.rb')
class GoogleDriveMechanism
def initialize()
#client = Google::APIClient.new(
:application_name => 'Backup Badger',
:application_version => '0.0.1'
)
#access_token_path = File.join($root,'.access_token')
#refresh_token_path = File.join($root,'.refresh_token')
#auth = nil
#access_token = File.open(#access_token_path, "rb").read
#refresh_token = File.open(#refresh_token_path, "rb").read
#session = nil
#client_id = 'CLIENT_ID'
#client_secret = 'CLIENT_SECRET'
#redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'
#scope = "https://www.googleapis.com/auth/drive " +
"https://spreadsheets.google.com/feeds/"
end
# Call this to do the initial setup, which requires pasting a url into a web broswer
def hard_setup
#auth = #client.authorization
#auth.client_id = #client_id
#auth.client_secret = #client_secret
#auth.scope = #scope
#auth.redirect_uri = #redirect_uri
print("1. Open this page:\n%s\n\n" % #auth.authorization_uri)
print("2. Enter the authorization code shown in the page: ")
#auth.code = $stdin.gets.chomp
#auth.fetch_access_token!
#access_token = #auth.access_token
system'clear'
print "Save your access token\n\n"
print #access_token
print "\nSave your refresh token\n\n"
print #auth.refresh_token
end
def connect
#auth = #client.authorization
#auth.client_id = #client_id
#auth.client_secret = #client_secret
#auth.scope = #scope
#auth.redirect_uri = #redirect_uri
#auth.refresh_token = #refresh_token
puts #access_token
puts #refresh_token
# Error is here
#auth.refresh!
#refresh_token = #auth.refresh_token
#access_token = #auth.access_token
File.write(#refresh_token_path, #refresh_token) if #refresh_token
File.write(#access_token_path, #access_token) if #access_token
puts #access_token
puts #refresh_token
end
def list
#session = GoogleDrive.login_with_oauth(#access_token)
for file in #session.files
p file.title
end
end
end
end
If the tl;dr is simply "how do I use a refresh token to get a new access token", then the answer is https://developers.google.com/accounts/docs/OAuth2WebServer#refresh
I won't paste the code coz it's likely to change, but in essence you simply POST to a Google URL and the JSON response is a shiny new access token.

selenium-webdriver / ruby / rspec2 - start IE with clean session or clear cookies or private browsing

I'm using selenium-webdriver with ruby and rspec2.
I have a lot of web test automation for which I need to use IE and I need to run each test with a clean session (specifically cookies cleared).
In this case selenium-webdriver is using InternetExplorerDriver (IEDriverServer.exe) for which the documentation indicates:
There are 2 solutions for problem with cookies (and another session
items) shared between multiple instances of InternetExplorer.
The first is to start your InternetExplorer in private mode. After
that InternetExplorer will be started with clean session data and will
not save changed session data at quiting. To do so you need to pass 2
specific capabilities to driver: ie.forceCreateProcessApi with true
value and ie.browserCommandLineSwitches with -private value. Be note
that it will work only for InternetExplorer 8 and newer, and Windows
Registry HKLM_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Main path should contain key TabProcGrowth with 0 value.
The second is to clean session during InternetExplorer starting. For
this you need to pass specific ie.ensureCleanSession capability with
true value to driver. This clears the cache for all running instances
of InternetExplorer, including those started manually.
My question is simply this:
Can anybody give an example of how this would be done in Ruby / Rspec2.
For example, I currently have:
before(:each) do
#driver = Selenium::WebDriver.for :internet_explorer
#driver.manage.window.maximize
#base_url = "https://www.example.com/"
#accept_next_alert = true
#driver.manage.timeouts.implicit_wait = 30
#verification_errors = []
end
How can I pass such IE parameters to the IE driver using Ruby / Rspec?
Thanks very much for your help.
I know this post a month old but just in case anyone still need it.
after I did some research I finally can start fresh IEDriver without any session or cookies for every each of the test. Here is the code:
before(:each) do
caps = Selenium::WebDriver::Remote::Capabilities..internet_explorer('ie.ensureCleanSession' => true, 'ie.browserCommandLineSwitches' => 'private')
#driver = Selenium::WebDriver.for(:internet_explorer, :desired_capabilities => caps)
#driver.manage.window.maximize
#base_url = "https://www.example.com/"
#accept_next_alert = true
#driver.manage.timeouts.implicit_wait = 30
end
Good luck!
You could add
before(:each) do
#driver = Selenium::WebDriver.for :internet_explorer
#driver.manage.window.maximize
#base_url = "https://www.example.com/"
#accept_next_alert = true
#driver.manage.timeouts.implicit_wait = 30
#verification_errors = []
#driver.manage.delete_all_cookies
end
From the gem docs http://rubydoc.info/gems/selenium-webdriver/0.0.28/Selenium/WebDriver/Options
--- edited ---
It looks like there might be a bug in the Selenium IE driver that doesn't delete cookies https://code.google.com/p/selenium/issues/detail?id=5101

Resources