How to set FirefoxDriver as the driver for Geb - geb

This seems to work:
#Grapes([
#Grab("org.codehaus.geb:geb-core:0.7.2"),
#Grab("org.seleniumhq.selenium:selenium-htmlunit-driver:2.25.0"),
#Grab("org.seleniumhq.selenium:selenium-support:2.25.0"),
#Grab("org.seleniumhq.selenium:selenium-firefox-driver:2.25.0")
])
import geb.Browser
import org.openqa.selenium.firefox.FirefoxDriver
Browser.drive() {
go "http://www.google.com"
}
But how do I use FirefoxDriver instead of HtmlUnitDriver? This just starts Firefox but all the drive instructions are executed in HtmlUnitDriver...
#Grapes([
#Grab("org.codehaus.geb:geb-core:0.7.2"),
#Grab("org.seleniumhq.selenium:selenium-htmlunit-driver:2.25.0"),
#Grab("org.seleniumhq.selenium:selenium-support:2.25.0"),
#Grab("org.seleniumhq.selenium:selenium-firefox-driver:2.25.0")
])
import geb.Browser
import org.openqa.selenium.firefox.FirefoxDriver
def browser = new Browser(driver: new FirefoxDriver())
browser.drive {
go "http://www.google.com"
}

Use a configuration script as outlined here: http://www.gebish.org/manual/0.7.0/configuration.html

We have done following configuration in the GebConfig.groovy to register FireFoxDriver with Geb.
driver = {
def firefoxDriver = new FirefoxDriver()
SharedResources.instance.browser = firefoxDriver
firefoxDriver.manage().window().maximize()
firefoxDriver
}
Hope that helps

Try this:
Browser.drive(new FirefoxDriver()) {
// firefox
}

Related

Chrome browser version - 72.0.3626.121 not opening with selenium

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import init.Constants;
public class TestSelenium {
private static WebDriver driver;
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir")+Constants.getChromeDriver());
driver = new ChromeDriver();
driver.get("https://www.google.com");
}
}
I am getting the error as below
Starting ChromeDriver 2.46.628402 (536cd7adbad73a3783fdc2cab92ab2ba7ec361e1) on port 45163
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.
The chrome browser is opening but the url is not coming up.
I am using
Chrome driver - 72.0.3626.69
WebDriver - 3.0
You can use bonigarcia dependency for your automation. Then you don't need to keep chromedriver.exe or setting up system variables. It will do all the configurations automatically for all the platforms and all the browsers as well.
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>3.3.0</version>
</dependency>
Below is a sample class to get chrome browser instance. You can modify this class as per your requirement.
import io.github.bonigarcia.wdm.*;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class DriverFactory {
public static WebDriver getDriver() {
WebDriverManager.chromedriver().setup();
return new ChromeDriver();
}
}
I have tested this with Selenium 3.14.0 and Chrome Version 73.0.3683.86 (Official Build) (64-bit)
You mentioned using Chrome driver - 72.0.3626.69 but error shows Starting ChromeDriver 2.46.628402. Check if you have correct chrome driver.
The possible reasons:
Old selenium (download 3.14.xx from https://www.seleniumhq.org/download/)
older chrome driver (consider update to the latest chromedriver https://chromedriver.storage.googleapis.com/index.html?path=73.0.3683.68/)
Chrome browser version mismatch (check the browser version and chromedriver compatibility at https://sites.google.com/a/chromium.org/chromedriver/downloads/version-selection)
Older Java version (latest Java version 11.0.2)
it does not open because you have not specify the path of the chromedriver.exe file
please find the below code snippet.
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class TestChrome {
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver", "path of the exe file\\chromedriver.exe");
// Initialize browser
WebDriver driver = new ChromeDriver();
// Open facebook
driver.get("http://www.facebook.com");
// Maximize browser
driver.manage().window().maximize();
}
}
Try to first set the Chrome driver path before calling the Chrome driver.
System.setProperty("webdriver.chrome.driver", "path of the exe file\\chromedriver.exe");
driver = new ChromeDriver();
driver.get("https://www.google.com");
Try to set chrome options:
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.addArguments("--whitelist-ip *");
chromeOptions.addArguments("--proxy-server='direct://'");
chromeOptions.addArguments("--proxy-bypass-list=*");
WebDriver driver = new ChromeDriver(chromeOptions);
Step 1: Check your browser version with your webdriver version on this page: https://chromedriver.chromium.org/downloads
Step 2: If after followed above step till you have the same issue then follows the below method:
public class TestSelenium {
private static WebDriver driver;
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver","user.dir");
driver = new ChromeDriver();
driver.get("https://www.google.com");
}
}

Page load strategy for Chrome driver (Updated till Selenium v3.12.0)

I'm using Chrome browser for testing WebApp.
Sometimes pages loaded after very long time. I needed to stop downloading or limit their download time.
In FireFox I know about PAGE_LOAD_STRATEGY = "eager".
Is there something similar for chrome?
P.S.: driver.manage().timeouts().pageLoadTimeout() works, but after that any treatment to Webdriver throws TimeOutException.
I need to get the current url of the page after stopping its boot.
ChromeDriver 77.0 (which supports Chrome version 77) now supports eager as pageLoadStrategy.
Resolved issue 1902: Support eager page load strategy [Pri-2]
From the Webdriver specs:
For commands that cause a new document to load, the point at which the command returns is determined by the session’s page loading strategy.
When Page Loading takes too much time and you need to stop downloading additional subresources (images, css, js etc) you can change the pageLoadStrategy through the webdriver.
As of this writing, pageLoadStrategy supports the following values :
normal
This stategy causes Selenium to wait for the full page loading (html content and subresources downloaded and parsed).
eager
This stategy causes Selenium to wait for the DOMContentLoaded event (html content downloaded and parsed only).
none
This strategy causes Selenium to return immediately after the initial page content is fully received (html content downloaded).
By default, when Selenium loads a page, it follows the normal pageLoadStrategy.
Here is the code block to configure pageLoadStrategy() through both an instance of DesiredCapabilities Class and ChromeOptions Class as follows : :
Using DesiredCapabilities Class :
package demo; //replace by your own package name
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
public class A_Chrome_DCap_Options {
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver", "C:\\Utility\\BrowserDrivers\\chromedriver.exe");
DesiredCapabilities dcap = new DesiredCapabilities();
dcap.setCapability("pageLoadStrategy", "normal");
ChromeOptions opt = new ChromeOptions();
opt.merge(dcap);
WebDriver driver = new ChromeDriver(opt);
driver.get("https://www.google.com/");
System.out.println(driver.getTitle());
driver.quit();
}
}
Using ChromeOptions Class :
package demo; //replace by your own package name
import org.openqa.selenium.PageLoadStrategy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
public class A_Chrome_Options_test {
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver", "C:\\Utility\\BrowserDrivers\\chromedriver.exe");
ChromeOptions opt = new ChromeOptions();
opt.setPageLoadStrategy(PageLoadStrategy.NORMAL);
WebDriver driver = new ChromeDriver(opt);
driver.get("https://www.google.com/");
System.out.println(driver.getTitle());
driver.quit();
}
}
Note : pageLoadStrategy values normal, eager and none is a requirement as per WebDriver W3C Editor's Draft but pageLoadStrategy value as eager is still a WIP (Work In Progress) within ChromeDriver implementation. You can find a detailed discussion in “Eager” Page Load Strategy workaround for Chromedriver Selenium in Python
References:
WebDriver navigation
WebDriver page load strategies
WhatWG Document readyStateChange / readiness
For Selenium 4 and Python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.page_load_strategy = 'none'
driver = webdriver.Chrome(options=options)
driver.get("http://www.google.com")
driver.quit()
For more details can be found here https://www.selenium.dev/documentation/webdriver/capabilities/shared/#none
In C#, since PageLoadStrategy.Eager doesn't seem to work for Chrome, I just wrote it myself with a WebDriverWait. Set the PageLoadStrategy to none and then doing this will basically override it:
new WebDriverWait(_driver, TimeSpan.FromSeconds(20))
.Until(d =>
{
var result = ((IJavaScriptExecutor) d).ExecuteScript("return document.readyState");
return result.Equals("interactive") || result.Equals("complete");
});
You just add in your chrome driver as a parameter and the TimeSpan is set to a max of 20 seconds in my case. So it will wait a max of 20 seconds for the page to be interactive or complete
Try using explicit wait . Visit this link. It might be helpful
Try this code as well:
WebDriver driver = new FirefoxDriver();
String startURL = //a starting url;
String currentURL = null;
WebDriverWait wait = new WebDriverWait(driver, 10);
foo(driver,startURL);
/* go to next page */
if(driver.findElement(By.xpath("//*[#id='someID']")).isDisplayed()){
String previousURL = driver.getCurrentUrl();
driver.findElement(By.xpath("//*[#id='someID']")).click();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
ExpectedCondition e = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return (d.getCurrentUrl() != previousURL);
}
};
wait.until(e);
currentURL = driver.getCurrentUrl();
System.out.println(currentURL);
}
I hope your problem will be resolved using above code

Unable to take screenshot of CEF application using Selenium

I am using Selenium to automate the CEF application. I am successfully able to perform operations like click etc. But not able to take the screenshot using Selenium driver. As it is very much required feature for automation. How can I do this?
I'm using the following:
CEF application - sample application provided by CEF
selenium jar - selenium-server-standalone-3.0.1
cef_binary_3.2924.1564.g0ba0378_windows64_client
chromedriver
Find the below code:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.OutputType;
public class Example {
public static void main(String[] args) {
// Path to the ChromeDriver executable.
System.setProperty("webdriver.chrome.driver", "D:/CEFTesting/chromedriver.exe");
// Path to the CEF executable.
ChromeOptions options = new ChromeOptions();
options.setBinary("D:/CEFTesting/cef_binary_3.2924.1564.g0ba0378_windows64_client/Release/cefclient.exe");
WebDriver driver = new ChromeDriver(options);
driver.get("http://www.google.com/xhtml");
sleep(3000); // Let the user actually see something!
WebElement searchBox = driver.findElement(By.name("q"));
searchBox.sendKeys("ChromeDriver");
searchBox.submit();
sleep(5000); // Let the user actually see something!
String screenshotBase64 = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BASE64);
System.out.println(screenshotBase64);
sleep(5000); // Let the user actually see something!
driver.quit();
}
}
I am facing the error.
I'm using the following:
CEF application - Sample application provided by CEF (link - https://bitbucket.org/chromiumembedded/cef/wiki/UsingChromeDriver.md)
selenium jar - selenium-server-standalone-3.0.1
cef_binary_3.2924.1564.g0ba0378_windows64_client
chromedriver
Here is the code:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.OutputType;
public class Example {
public static void main(String[] args) {
// Path to the ChromeDriver executable.
System.setProperty("webdriver.chrome.driver", "D:/CEFTesting/chromedriver.exe");
// Path to the CEF executable.
ChromeOptions options = new ChromeOptions();
options.setBinary("D:/CEFTesting/cef_binary_3.2924.1564.g0ba0378_windows64_client/Release/cefclient.exe");
WebDriver driver = new ChromeDriver(options);
driver.get("http://www.google.com/xhtml");
sleep(3000); // Let the user actually see something!
WebElement searchBox = driver.findElement(By.name("q"));
searchBox.sendKeys("ChromeDriver");
searchBox.submit();
sleep(5000); // Let the user actually see something!
String screenshotBase64 = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BASE64);
System.out.println(screenshotBase64);
sleep(5000); // Let the user actually see something!
driver.quit();
}
}

How to click Allow on Show Notifications popup using Selenium Webdriver

I'm trying to login to Facebook. After a successful login, I get a browser popup:
How with the webdriver can I click Allow and proceed forward?
Please Follow below steps :
A) USING JAVA :
For Old Chrome Version (<50):
//Create a instance of ChromeOptions class
ChromeOptions options = new ChromeOptions();
//Add chrome switch to disable notification - "**--disable-notifications**"
options.addArguments("--disable-notifications");
//Set path for driver exe
System.setProperty("webdriver.chrome.driver","path/to/driver/exe");
//Pass ChromeOptions instance to ChromeDriver Constructor
WebDriver driver =new ChromeDriver(options);
For New Chrome Version (>50):
//Create a map to store preferences
Map<String, Object> prefs = new HashMap<String, Object>();
//add key and value to map as follow to switch off browser notification
//Pass the argument 1 to allow and 2 to block
prefs.put("profile.default_content_setting_values.notifications", 2);
//Create an instance of ChromeOptions
ChromeOptions options = new ChromeOptions();
// set ExperimentalOption - prefs
options.setExperimentalOption("prefs", prefs);
//Now Pass ChromeOptions instance to ChromeDriver Constructor to initialize chrome driver which will switch off this browser notification on the chrome browser
WebDriver driver = new ChromeDriver(options);
For Firefox :
WebDriver driver ;
FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("permissions.default.desktop-notification", 1);
DesiredCapabilities capabilities=DesiredCapabilities.firefox();
capabilities.setCapability(FirefoxDriver.PROFILE, profile);
driver = new FirefoxDriver(capabilities);
driver.get("http://google.com");
B) USING PYTHON :
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
option = Options()
option.add_argument("--disable-infobars")
option.add_argument("start-maximized")
option.add_argument("--disable-extensions")
# Pass the argument 1 to allow and 2 to block
option.add_experimental_option(
"prefs", {"profile.default_content_setting_values.notifications": 1}
)
driver = webdriver.Chrome(
chrome_options=option, executable_path="path-of-driver\chromedriver.exe"
)
driver.get("https://www.facebook.com")
C) USING C#:
ChromeOptions options = new ChromeOptions();
options.AddArguments("--disable-notifications"); // to disable notification
IWebDriver driver = new ChromeDriver(options);
import unittest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.chrome.options import Options
from selenium import webdriver
import time
class SendMsgSkype(unittest.TestCase):
#classmethod
def setUpClass(cls):
options = Options()
options.add_argument("--disable-notifications")
cls.driver = webdriver.Chrome("./chromedriver.exe", chrome_options=options)
cls.driver.implicitly_wait(5)
cls.driver.maximize_window()
cls.driver.get("https://web.skype.com/ru/")
It works for me.
More details here: http://nullege.com/codes/show/src#t#a#TardyParty-HEAD#oxbiz.py/21/selenium.webdriver.Chrome
This not an alert box, so you can't handle it using Alert, this is a chrome browser notification, To Switch off this browser notification you need to create chrome preference map with chrome option as below :
//Create prefs map to store all preferences
Map<String, Object> prefs = new HashMap<String, Object>();
//Put this into prefs map to switch off browser notification
prefs.put("profile.default_content_setting_values.notifications", 2);
//Create chrome options to set this prefs
ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("prefs", prefs);
//Now initialize chrome driver with chrome options which will switch off this browser notification on the chrome browser
WebDriver driver = new ChromeDriver(options);
//Now do your further steps
Hope it helps..:)
The one and only working solution I've come across so far is this:
from selenium.webdriver.chrome.options import Options
chrome_options = webdriver.ChromeOptions()
prefs = {"profile.default_content_setting_values.notifications": 2}
chrome_options.add_experimental_option("prefs", prefs)
driver = webdriver.Chrome(chrome_options=chrome_options)
no answer has been accepted yet, this following code works for me
ruby, rspec, capybara
Capybara.register_driver :selenium_chrome do |app|
prefs = {"profile.managed_default_content_settings.notifications" => 2,}
caps = Selenium::WebDriver::Remote::Capabilities.chrome(chrome_options: { prefs: prefs })
Capybara::Selenium::Driver.new(app, browser: :chrome, desired_capabilities: caps)
end
Capybara.javascript_driver = :selenium_chrome
try {
// Check the presence of alert
Alert alert = driver.SwitchTo().Alert();
// if present consume the alert
alert.Accept();
} catch (NoAlertPresentException ex) {
//code to do if not exist.
}
Facebook authentication window displays an overlay that covers the continue as [username] button.
This makes the continue button un-clickable. To circumvent that problem, you can hide those layers programmatically using JavaScript (not recommended) using this code (don't do this).
// DO NOT USE THIS CODE.
function forceClickSetup(targetSelector) {
return browser.selectorExecute("div",
function(divs, targetSelector) {
var button = document.querySelector(targetSelector);
for(var i = 0; i < divs.length; i++) {
if(!divs[i].contains(button)) {
divs[i].remove();
}
}
return i;
}, targetSelector);
}
Or instead, you can dismiss the notifications dialog, after which facebook will uncover the continue button. But before wildly hitting Escape at the browser, first make sure that the continue button has been shown.
// USE THIS CODE.
browser.waitForVisible("[name=__CONFIRM__]");
browser.keys("Escape"); // Dismiss "notifications" dialog box.
var confirmButtonSelector = "[name=__CONFIRM__]";
This solution is really Matthijs' (see comments above)
if you play with Ruby and Capybara try this code
Capybara.register_driver :chrome_no_image_popup_maximize do |app|
# 2: disable, other than 2 means enable it
preferences = {
"profile.managed_default_content_settings.notifications" => 2,
"profile.managed_default_content_settings.images" => 2,
"profile.managed_default_content_settings.popups" => 2
}
caps = Selenium::WebDriver::Remote::Capabilities.chrome(
'chromeOptions' => {
'prefs' => preferences,
}
)
args = [ "--start-maximized" ]
Capybara::Selenium::Driver.new(app, {:browser => :chrome, :desired_capabilities => caps, :args => args})
end
Capybara.default_driver = :chrome_no_image_popup_maximize
Capybara.javascript_driver = :chrome_no_image_popup_maximize

Can Selenium interact with an existing browser session?

Does anybody know if Selenium (WebDriver preferably) is able to communicate with and act through a browser that is already running before launching a Selenium Client?
I mean if Selenium is able to comunicate with a browser without using the Selenium Server (with could be an Internet Explorer launched manually for example).
This is a duplicate answer
**Reconnect to a driver in python selenium ** This is applicable on all drivers and for java api.
open a driver
driver = webdriver.Firefox() #python
extract to session_id and _url from driver object.
url = driver.command_executor._url #"http://127.0.0.1:60622/hub"
session_id = driver.session_id #'4e167f26-dc1d-4f51-a207-f761eaf73c31'
Use these two parameter to connect to your driver.
driver = webdriver.Remote(command_executor=url,desired_capabilities={})
driver.close() # this prevents the dummy browser
driver.session_id = session_id
And you are connected to your driver again.
driver.get("http://www.mrsmart.in")
This is a pretty old feature request: Allow webdriver to attach to a running browser . So it's officially not supported.
However, there is some working code which claims to support this: https://web.archive.org/web/20171214043703/http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/.
This snippet successfully allows to reuse existing browser instance yet avoiding raising the duplicate browser. Found at Tarun Lalwani's blog.
from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebDriver
# executor_url = driver.command_executor._url
# session_id = driver.session_id
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
driver = webdriver.Remote(command_executor=executor_url, desired_capabilities={})
driver.session_id = session_id
# Replace the patched function with original function
WebDriver.execute = original_execute
return driver
bro = attach_to_session('http://127.0.0.1:64092', '8de24f3bfbec01ba0d82a7946df1d1c3')
bro.get('http://ya.ru/')
It is possible. But you have to hack it a little, there is a code
What you have to do is to run stand alone server and "patch" RemoteWebDriver
public class CustomRemoteWebDriver : RemoteWebDriver
{
public static bool newSession;
public static string capPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestFiles", "tmp", "sessionCap");
public static string sessiodIdPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestFiles", "tmp", "sessionid");
public CustomRemoteWebDriver(Uri remoteAddress)
: base(remoteAddress, new DesiredCapabilities())
{
}
protected override Response Execute(DriverCommand driverCommandToExecute, Dictionary<string, object> parameters)
{
if (driverCommandToExecute == DriverCommand.NewSession)
{
if (!newSession)
{
var capText = File.ReadAllText(capPath);
var sidText = File.ReadAllText(sessiodIdPath);
var cap = JsonConvert.DeserializeObject<Dictionary<string, object>>(capText);
return new Response
{
SessionId = sidText,
Value = cap
};
}
else
{
var response = base.Execute(driverCommandToExecute, parameters);
var dictionary = (Dictionary<string, object>) response.Value;
File.WriteAllText(capPath, JsonConvert.SerializeObject(dictionary));
File.WriteAllText(sessiodIdPath, response.SessionId);
return response;
}
}
else
{
var response = base.Execute(driverCommandToExecute, parameters);
return response;
}
}
}
From here, if the browser was manually opened, then remote debugging can be used:
Start chrome with
chrome --remote-debugging-port=9222
Or with optional profile
chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\selenium\ChromeProfile"
Then:
Java:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
//Change chrome driver path accordingly
System.setProperty("webdriver.chrome.driver", "C:\\selenium\\chromedriver.exe");
ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("debuggerAddress", "127.0.0.1:9222");
WebDriver driver = new ChromeDriver(options);
System.out.println(driver.getTitle());
Python:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
#Change chrome driver path accordingly
chrome_driver = "C:\chromedriver.exe"
driver = webdriver.Chrome(chrome_driver, chrome_options=chrome_options)
print driver.title
Inspired by Eric's answer, here is my solution to this problem for selenium 3.7.0. Compared with the solution at http://tarunlalwani.com/post/reusing-existing-browser-session-selenium/, the advantage is that there won't be a blank browser window each time I connect to the existing session.
import warnings
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.remote.errorhandler import ErrorHandler
from selenium.webdriver.remote.file_detector import LocalFileDetector
from selenium.webdriver.remote.mobile import Mobile
from selenium.webdriver.remote.remote_connection import RemoteConnection
from selenium.webdriver.remote.switch_to import SwitchTo
from selenium.webdriver.remote.webdriver import WebDriver
# This webdriver can directly attach to an existing session.
class AttachableWebDriver(WebDriver):
def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
desired_capabilities=None, browser_profile=None, proxy=None,
keep_alive=False, file_detector=None, session_id=None):
"""
Create a new driver that will issue commands using the wire protocol.
:Args:
- command_executor - Either a string representing URL of the remote server or a custom
remote_connection.RemoteConnection object. Defaults to 'http://127.0.0.1:4444/wd/hub'.
- desired_capabilities - A dictionary of capabilities to request when
starting the browser session. Required parameter.
- browser_profile - A selenium.webdriver.firefox.firefox_profile.FirefoxProfile object.
Only used if Firefox is requested. Optional.
- proxy - A selenium.webdriver.common.proxy.Proxy object. The browser session will
be started with given proxy settings, if possible. Optional.
- keep_alive - Whether to configure remote_connection.RemoteConnection to use
HTTP keep-alive. Defaults to False.
- file_detector - Pass custom file detector object during instantiation. If None,
then default LocalFileDetector() will be used.
"""
if desired_capabilities is None:
raise WebDriverException("Desired Capabilities can't be None")
if not isinstance(desired_capabilities, dict):
raise WebDriverException("Desired Capabilities must be a dictionary")
if proxy is not None:
warnings.warn("Please use FirefoxOptions to set proxy",
DeprecationWarning)
proxy.add_to_capabilities(desired_capabilities)
self.command_executor = command_executor
if type(self.command_executor) is bytes or isinstance(self.command_executor, str):
self.command_executor = RemoteConnection(command_executor, keep_alive=keep_alive)
self.command_executor._commands['GET_SESSION'] = ('GET', '/session/$sessionId') # added
self._is_remote = True
self.session_id = session_id # added
self.capabilities = {}
self.error_handler = ErrorHandler()
self.start_client()
if browser_profile is not None:
warnings.warn("Please use FirefoxOptions to set browser profile",
DeprecationWarning)
if session_id:
self.connect_to_session(desired_capabilities) # added
else:
self.start_session(desired_capabilities, browser_profile)
self._switch_to = SwitchTo(self)
self._mobile = Mobile(self)
self.file_detector = file_detector or LocalFileDetector()
self.w3c = True # added hardcoded
def connect_to_session(self, desired_capabilities):
response = self.execute('GET_SESSION', {
'desiredCapabilities': desired_capabilities,
'sessionId': self.session_id,
})
# self.session_id = response['sessionId']
self.capabilities = response['value']
To use it:
if use_existing_session:
browser = AttachableWebDriver(command_executor=('http://%s:4444/wd/hub' % ip),
desired_capabilities=(DesiredCapabilities.INTERNETEXPLORER),
session_id=session_id)
self.logger.info("Using existing browser with session id {}".format(session_id))
else:
browser = AttachableWebDriver(command_executor=('http://%s:4444/wd/hub' % ip),
desired_capabilities=(DesiredCapabilities.INTERNETEXPLORER))
self.logger.info('New session_id : {}'.format(browser.session_id))
It appears that this feature is not officially supported by selenium. But, Tarun Lalwani has created working Java code to provide the feature. Refer - http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/
Here is the working sample code, copied from the above link:
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.remote.*;
import org.openqa.selenium.remote.http.W3CHttpCommandCodec;
import org.openqa.selenium.remote.http.W3CHttpResponseCodec;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Collections;
public class TestClass {
public static RemoteWebDriver createDriverFromSession(final SessionId sessionId, URL command_executor){
CommandExecutor executor = new HttpCommandExecutor(command_executor) {
#Override
public Response execute(Command command) throws IOException {
Response response = null;
if (command.getName() == "newSession") {
response = new Response();
response.setSessionId(sessionId.toString());
response.setStatus(0);
response.setValue(Collections.<String, String>emptyMap());
try {
Field commandCodec = null;
commandCodec = this.getClass().getSuperclass().getDeclaredField("commandCodec");
commandCodec.setAccessible(true);
commandCodec.set(this, new W3CHttpCommandCodec());
Field responseCodec = null;
responseCodec = this.getClass().getSuperclass().getDeclaredField("responseCodec");
responseCodec.setAccessible(true);
responseCodec.set(this, new W3CHttpResponseCodec());
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else {
response = super.execute(command);
}
return response;
}
};
return new RemoteWebDriver(executor, new DesiredCapabilities());
}
public static void main(String [] args) {
ChromeDriver driver = new ChromeDriver();
HttpCommandExecutor executor = (HttpCommandExecutor) driver.getCommandExecutor();
URL url = executor.getAddressOfRemoteServer();
SessionId session_id = driver.getSessionId();
RemoteWebDriver driver2 = createDriverFromSession(session_id, url);
driver2.get("http://tarunlalwani.com");
}
}
Your test needs to have a RemoteWebDriver created from an existing browser session. To create that Driver, you only need to know the "session info", i.e. address of the server (local in our case) where the browser is running and the browser session id. To get these details, we can create one browser session with selenium, open the desired page, and then finally run the actual test script.
I don't know if there is a way to get session info for a session which was not created by selenium.
Here is an example of session info:
Address of remote server : http://localhost:24266. The port number is different for each session.
Session Id : 534c7b561aacdd6dc319f60fed27d9d6.
All the solutions so far were lacking of certain functionality.
Here is my solution:
public class AttachedWebDriver extends RemoteWebDriver {
public AttachedWebDriver(URL url, String sessionId) {
super();
setSessionId(sessionId);
setCommandExecutor(new HttpCommandExecutor(url) {
#Override
public Response execute(Command command) throws IOException {
if (command.getName() != "newSession") {
return super.execute(command);
}
return super.execute(new Command(getSessionId(), "getCapabilities"));
}
});
startSession(new DesiredCapabilities());
}
}
Javascript solution:
I have successfully attached to existing browser session using this function
webdriver.WebDriver.attachToSession(executor, session_id);
Documentation can be found here.
I got a solution in python, I modified the webdriver class bassed on PersistenBrowser class that I found.
https://github.com/axelPalmerin/personal/commit/fabddb38a39f378aa113b0cb8d33391d5f91dca5
replace the webdriver module /usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py
Ej. to use:
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
runDriver = sys.argv[1]
sessionId = sys.argv[2]
def setBrowser():
if eval(runDriver):
webdriver = w.Remote(command_executor='http://localhost:4444/wd/hub',
desired_capabilities=DesiredCapabilities.CHROME,
)
else:
webdriver = w.Remote(command_executor='http://localhost:4444/wd/hub',
desired_capabilities=DesiredCapabilities.CHROME,
session_id=sessionId)
url = webdriver.command_executor._url
session_id = webdriver.session_id
print url
print session_id
return webdriver
Use Chrome's built in remote debugging. Launch Chrome with remote debugging port open. I did this on OS X:
sudo nohup /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 &
Tell Selenium to use the remote debugging port:
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument('--remote-debugging-port=9222')
driver = webdriver.Chrome("./chromedriver", chrome_options=options)
I'm using Rails + Cucumber + Selenium Webdriver + PhantomJS, and I've been using a monkey-patched version of Selenium Webdriver, which keeps PhantomJS browser open between test runs. See this blog post: http://blog.sharetribe.com/2014/04/07/faster-cucumber-startup-keep-phantomjs-browser-open-between-tests/
See also my answer to this post: How do I execute a command on already opened browser from a ruby file
Solution using Python programming language.
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, existing_session_id)
driver2.get('http://msn.com/')
print(driver2.command_executor._url)
print(driver2.session_id)
print(driver2.title)
driver2.close()
# ------------------ END OF STEP 2 --------------------------------------------------
After trying most of these solutions, this solution has worked for me the best. Thanks to #Ahmed_Ashour.
For those who are struggling with this problem, here are a few tips to make your life a bit easier:
1- use a driver manager instead of a manually installed driver (to avoid compatibility issues)
from webdriver_manager.chrome import ChromeDriverManager
driver = webdriver.Chrome(ChromeDriverManager().install(),options=chrome_options)
2- Make sure to close the running chrome instance before starting the new one with the debugging port
chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\selenum\ChromeProfile"
This is pretty easy using the JavaScript selenium-webdriver client:
First, make sure you have a WebDriver server running. For example, download ChromeDriver, then run chromedriver --port=9515.
Second, create the driver like this:
var driver = new webdriver.Builder()
.withCapabilities(webdriver.Capabilities.chrome())
.usingServer('http://localhost:9515') // <- this
.build();
Here's a complete example:
var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder()
.withCapabilities(webdriver.Capabilities.chrome())
.usingServer('http://localhost:9515')
.build();
driver.get('http://www.google.com');
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');
driver.findElement(webdriver.By.name('btnG')).click();
driver.getTitle().then(function(title) {
console.log(title);
});
driver.quit();