Selenium Webdriver connection pooling - selenium

I have my application automated, which has some 70+ scripts and runs against Selenium Grid which is open to other applications too.
My question is, is there any connection pooling api for WebDriver? so that i can re use webdriver objects efficiently across my scripts. I don't want my scripts wait for IE slots and fail because of time out errors if they cannot get one.
Also, i beleive it would enhance the performance of scripts execution.
Thanks.

Our tests are very small and so fast that the webdrivers took longer to instantiate than the tests. So we pooled the webdrivers, like #premganz suggested, but using Apache Commons Pool. We considered writing our own webdriver list-managed pool but found using the well-established Apache Pool was simple to implement, robust and scalable. Our tests run over 80 WebDrivers concurrently.
Example WebdriverFactory:
public class WebdriverFactory extends BasePooledObjectFactory<RemoteWebDriver> {
private FirefoxOptions firefoxOptions = new FirefoxOptions();
public WebdriverFactory(boolean headless, int implicit_timeout_seconds) {
super();
firefoxOptions.setHeadless(headless)
.setPageLoadStrategy(PageLoadStrategy.EAGER)
.setLogLevel(FirefoxDriverLogLevel.ERROR);
}
#Override
public RemoteWebDriver create() {
FirefoxDriver webDriver = new FirefoxDriver(firefoxOptions);
webDriver.manage()
.timeouts()
.implicitlyWait(implicit_timeout_seconds, TimeUnit.SECONDS);
return webDriver;
}
/**
* Use the default PooledObject implementation.
*/
#Override
public PooledObject<RemoteWebDriver> wrap(RemoteWebDriver webDriver) {
return new DefaultPooledObject<>(webDriver);
}
/**
* When a webdriver is returned to the pool, clean it up.
*/
#Override
public void passivateObject(PooledObject<RemoteWebDriver> webDriver) {
WebDriver driver = webDriver.getObject();
try {
// close all tabs except the first
String originalHandle = driver.getWindowHandle();
for(String handle : driver.getWindowHandles()) {
if (!handle.equals(originalHandle)) {
driver.switchTo().window(handle);
driver.close();
}
}
driver.switchTo().window(originalHandle);
} catch (Exception e) {
// ...
} finally {
// ensure session data is not re-used
driver.manage().deleteAllCookies();
}
}
#Override
public boolean validateObject(PooledObject<RemoteWebDriver> webDriver) {
return true;
}
#Override
public void activateObject(PooledObject<RemoteWebDriver> webDriver) throws Exception {
}
}

I agree that WebDriver pooling could enhance performance of the application. On the other hand, if you are using selenium webdriver, the driver becomes stateful making it less reusable. I did a logic something like this:
Create a Driver factory that wraps a linked list of size say 10 (which implements a list and a queue).
When asked for an instance provide the middle (i==5) one from the list
Use another thread to recycle the drivers in the queue, removing ones from the head and adding new ones to the tail.
This way you can implement a constantly recycled pool and your code does not have to block on driver.create or driver.quit.

Related

WebDriverWait Selenium approach

Regarding the WebDriverWait data type, I am assuming that only one instance is needed of such data type, which means I could potentially create a wrapper and allow only one instance creation by using a singleton pattern approach.
At the present time I used thread.sleep and basically everywhere I need that function to be called I am extending from the class which probably not the best approach. Also of course I should be using WebDriverWait instead of thread. What should the approach be?
So far I created a page object with web elements and a separate service for the logic itself, so now I need also WebDriverWait in every service since it’s a necessary operation.
A cookie window that gets popped up once customer opened the page:
/**
* acceptCookies -> clickable
* cookieBanner -> just to identify that cookie component showed up.
* PageFactory -> will initialize every WebElement variable with a reference to a corresponding element on the actual web page.
*/
public class CookieModal {
WebDriver driver;
#FindBy(css = ".cookie-accept-all")
public WebElement acceptCookies;
public CookieModal(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
}
Then I separated the service (actions):
public class CookieService {
private final CookieModal cookieModal;
public CookieService(WebDriver driver) {
this.cookieModal = new CookieModal(driver);
}
public void acceptCookies() {
cookieModal.acceptCookies.click();
}
}
This must be changed to WebDriverWait, but I also think extending from AbstractPage in every page object is not necessary. Is my structure OK and how should I initialise WebDriverWait?
public class AbstractPage {
// This is not good as thread sleep is not dynamic and you
// have to specify time yourself change to webdriver wait
private AbstractPage microsleep(Integer milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (Throwable e) {
String error = String.format("Unable to put thread to sleep (requested %d milliseconds).", milliseconds);
throw new RuntimeException(error, e);
}
return this;
}
public AbstractPage emulateWaitingUser() {
return microsleep(800);
}
public AbstractPage sleep(Integer seconds) {
return microsleep(1000 * seconds);
}
Selenium supports integrating explicit waits into page objects. This is achieved by using a special way of how you initialize your page. In your example you are doing this:
PageFactory.initElements(driver, this);
which involves some basic default way. However, you can add more complexity here, but you get a more effective architecture at the same time.
You can extend the AjaxElementLocator class where you will override isElementUsable method in the way that would involve any sort of condition and waits. Then you will be initializing your page(s) with that locator through a dedicated LocatorFactory. Some example of how to use all that classes you can find here.
WebDriverWait is commonly used with the ExpectedConditions class. In that case, you cannot just wait for 800 ms. You need to wait until a condition is met. For example, wait until page title is displayed, or wait until loader icon is not visible, wait until login button is clickable, etc.
That means if you wish to instantiate a wait in an abstract method, you will need to add an unknown (and non-abstract) wait condition. You could just instantiate a general wait object and then add a condition when it is known, but it seems a bit incomplete.
Another idea that comes to my mind is declaring WebDriverWait as a field in Cookie Service class and pass it to its methods.

Setting up selenium webdriver for parallel execution

I am trying to execute a large suite of selenium tests via xUnit console runner in parallel.
These have executed and I see 3 chrome windows open, however the first send key commands simply executes 3 times to one window, resulting in test failure.
I have registered my driver in an objectcontainer before each scenario as below:
[Binding]
public class WebDriverSupport
{
private readonly IObjectContainer _objectContainer;
public WebDriverSupport(IObjectContainer objectContainer)
{
_objectContainer = objectContainer;
}
[BeforeScenario]
public void InitializeWebDriver()
{
var driver = GetWebDriverFromAppConfig();
_objectContainer.RegisterInstanceAs<IWebDriver>(driver);
}
And then call the driver in my specflow step defintions as:
_driver = (IWebDriver)ScenarioContext.Current.GetBindingInstance(typeof(IWebDriver));
ScenarioContext.Current.Add("Driver", _driver);
However this has made no difference and it seems as if my tests are trying to execute all commands to one driver.
Can anyone advise where I have gone wrong ?
You shouldn't be using ScenarioContext.Current in a parallel execution context. If you're injecting the driver through _objectContainer.RegisterInstanceAs you will receive it through constructor injection in your steps class' constructor, like so:
public MyScenarioSteps(IWebDriver driver)
{
_driver = driver;
}
More info:
https://github.com/techtalk/SpecFlow/wiki/Parallel-Execution#thread-safe-scenariocontext-featurecontext-and-scenariostepcontext
https://github.com/techtalk/SpecFlow/wiki/Context-Injection
In my opinion this is horribly messy.
This might not be an answer, but is too big for a comment.
why are you using the IObjectContainer if you are just getting it from the current scenario context and not injecting it via the DI mechanism? I would try this:
[Binding]
public class WebDriverSupport
{
[BeforeScenario]
public void InitializeWebDriver()
{
var driver = GetWebDriverFromAppConfig();
ScenarioContext.Current.Add("Driver",driver);
}
}
then in your steps:
_driver = (IWebDriver)ScenarioContext.Current.Get("Driver");
As long as GetWebDriverFromAppConfig returns a new instance you should be ok...

LeanFT and Selenium Compatibility?

I would like to know if Selenium and LeanFT can play nicely together. I don't know if anyone has tried to do this yet, but I think if it can work, LeanFT can provide some supplementary benefits to the selenium framework.
As I understand it currently, the limitations of Selenium are:
Selenium MUST open the initial browser to recognize it
Selenium MUST open all popups to recognize them.
Selenium WebDriver may become stale while waiting for non-Selenium procedures.
I have attempted the object flow UML for both HP's suggested model and my own idea of how this might work.
The Control flow would be something like:
#Before -> globalSetup (LeanFT init)
#BeforeClass -> testSetup (LeanFT init)
#BeforeClass -> getSeleniumDriver (Selenium)
#Test -> some selenium procedures
/**** To prevent Selenium from dying. ****/
#Test -> new Thread -> run leanFTsnippet1()
#Test -> resume selenium final steps..
#After -> reporting, closing Webdriver
Here is some of my current code from an example Test Class.
#BeforeClass
public static void beforeLFTClass() throws Exception {
globalSetup(CoreFunctionality.class);
}
#AfterClass
public static void afterLFTClass() throws Exception {
globalTearDown();
}
#Test
public void runLeanFtThread() {
// put selenium code here
// ...
// begin leanft part of test
Thread leanftThread = new Thread( new Runnable() {
#Override
public void run() {
try {
test();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
leanftThread.start();
try {
leanftThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void test() throws Exception {
//Starting Browser
Browser browser = BrowserFactory.attach(new BrowserDescription.Builder().title(driver.getTitle()).build());
Assert.assertEquals(browser.getTitle(), driver.getTitle());
}
Anyways, its a pretty interesting problem. Would really love to see what you guys think.
Thanks!
They indeed play nicely together. I have been using them in my scripts and I like to utilize the powers of each tool. What I have done is create a LeanFT test template and add the Selenium libraries to it.
Here is a sample code:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using HP.LFT.SDK;
using HP.LFT.SDK.Web;
using Search_Regression_Test;
using TestAutomationReporting;
using UnifiedFramework;
using System.Configuration;
using System.Diagnostics;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using Selenium = OpenQA.Selenium;
namespace Search_Regression_Test
{
[TestClass]
public class LeanFtTest : UnitTestClassBase<LeanFtTest>
{
static IBrowser browser;
static IWebDriver chromeDriver;
[ClassInitialize]
public static void ClassInitialize(TestContext context)
{
GlobalSetup(context);
ChromeOptions CO = new ChromeOptions();
CO.AddExtension(#"C:\Program Files (x86)\HP\LeanFT\Installations\Chrome\Agent.crx");
chromeDriver = new ChromeDriver(CO);
chromeDriver.Manage().Window.Maximize();
browser = BrowserFactory.Attach(new BrowserDescription
{
Type = BrowserType.Chrome
});
.... and so on.
The new Version of LeanFT (14) even brings some explicit Selenium-integration: You can select Selenium as your automation SDK in the project creation wizard, there is a Selenium-specific Object Identification Center, and some additional locators and utilities. Full story here: LeanFT for Selenium.
I'm not entirely sure why this question doesn't have an accepted answer yet, but I'm going to take a stab at answering this with a sample that highlights once more that LeanFT and Selenium are playing nicely together
It's written in Java. Probably it can be optimized a bit, but it should clearly show how you can achieve simultaneous interaction with the same browser.
(The Java Project was created from LeanFT templates. UnitTestClassBase class comes from there. It basically initializes LeanFT and the reporter behind the scenes. To get around it if you don't want to use it you'd have to call SDK.init(), Reporter.init(), Reporter.generateReport() and SDK.cleanup() as needed - check the docs for details)
The AUT used is advantage shopping: http://advantageonlineshopping.com/
package com.demo;
import static org.junit.Assert.*;
import java.io.File;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.Keys;
import org.openqa.selenium.chrome.*;
import org.openqa.selenium.firefox.*;
import org.openqa.selenium.remote.DesiredCapabilities;
import com.hpe.leanft.selenium.By;
import com.hp.lft.report.Reporter;
import com.hp.lft.report.Status;
import com.hp.lft.sdk.web.*;
import com.hp.lft.verifications.Verify;
public class SeleniumTest extends UnitTestClassBase {
private ChromeDriver chromeDriver;
private Browser browser;
public SeleniumTest() {
System.setProperty("webdriver.chrome.driver",this.getClass().getResource("/chromedriver.exe").getPath());
}
#BeforeClass
public static void setUpBeforeClass() throws Exception {
instance = new SeleniumTest();
globalSetup(SeleniumTest.class);
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
globalTearDown();
}
#Before
public void setUp() throws Exception {
// SELENIUM: Construct and launch the browser with LeanFT agent
ChromeOptions options = new ChromeOptions();
File paths = new File("C:\\Program Files (x86)\\HP\\LeanFT\\Installations\\Chrome\\Agent.crx");
options.addExtensions(paths);
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(ChromeOptions.CAPABILITY, options);
chromeDriver = new ChromeDriver(options);
}
#After
public void tearDown() throws Exception {
// LEANFT: close the browser opened by selenium
browser.close();
}
#Test
public void test() throws Exception {
// SELENIUM: Go to the Advantage shopping website and maximize it
chromeDriver.get("http://156.152.164.67:8080/#/");
chromeDriver.manage().window().maximize();
// LEANFT: Attach to the browser
browser = BrowserFactory.attach(new BrowserDescription.Builder()
.type(BrowserType.CHROME).openTitle(" Advantage Shopping")
.build());
// LEANFT: Click on tablets button
browser.describe(WebElement.class, new WebElementDescription.Builder()
.className("categoryCell").tagName("DIV").innerText("TABLETS Shop Now ").build()).click();
// SELENIUM: Expand the display section after it was seen
(new WebDriverWait(chromeDriver, 10))
.until(new ExpectedCondition<org.openqa.selenium.WebElement>(){
#Override
public org.openqa.selenium.WebElement apply(org.openqa.selenium.WebDriver d) {
return d.findElement(By.cssSelector("h4#accordionAttrib0"));
}}).click();
// LEANFT: select the preferred display size, click the preferred tablet and add the tablet to the cart
browser.describe(CheckBox.class, new CheckBoxDescription.Builder()
.type("checkbox").role("").accessibilityName("").tagName("INPUT").name("").index(1).build()).set(true);
browser.describe(Image.class, new ImageDescription.Builder()
.alt("").type(com.hp.lft.sdk.web.ImageType.NORMAL).tagName("IMG").index(1).build()).click();
browser.describe(Button.class, new ButtonDescription.Builder()
.buttonType("submit").tagName("BUTTON").name("ADD TO CART").build()).click();
// SELENIUM: go to cart
chromeDriver.get("http://156.152.164.67:8080/#/shoppingCart");
// LEANFT: checkout
browser.describe(Button.class, new ButtonDescription.Builder()
.buttonType("submit").tagName("BUTTON").name("CHECKOUT ($1,009.00)").build()).click();
// SELENIUM: Register as a new user after the button was seen
(new WebDriverWait(chromeDriver, 10))
.until(new ExpectedCondition<org.openqa.selenium.WebElement>(){
#Override
public org.openqa.selenium.WebElement apply(org.openqa.selenium.WebDriver d) {
return d.findElement(By.xpath("//DIV[#id=\"newClient\"]/DIV[1]/SEC-FORM[1]/SEC-SENDER[1]/BUTTON[#role=\"button\"][1]"));
}}).click();
// LEANFT: fill in the user name and email
String username = "U" + Calendar.getInstance().getTimeInMillis(); // unique name each time
browser.describe(EditField.class, new EditFieldDescription.Builder()
.type("text").tagName("INPUT").name("userName").build()).setValue(username);
browser.describe(EditField.class, new EditFieldDescription.Builder()
.type("text").tagName("INPUT").name("userEmail").build()).setValue("myuser_email#emailsite.org");
// SELENIUM: Set password and confirm password
chromeDriver.findElementByXPath("//SEC-VIEW/DIV[normalize-space()=\"*Password\"]/INPUT[1]").sendKeys("Password1");
chromeDriver.findElementByXPath("//SEC-VIEW/DIV[normalize-space()=\"*Confirm password\"]/INPUT[1]").sendKeys("Password1");
// LEANFT: check the 'I agree' checkbox and register, then click on next shipping details.
browser.describe(CheckBox.class, new CheckBoxDescription.Builder()
.type("checkbox").tagName("INPUT").name("registrationAgreement").build()).set(true);
browser.describe(Button.class, new ButtonDescription.Builder()
.buttonType("button").tagName("BUTTON").name("REGISTER").build()).click();
browser.describe(Button.class, new ButtonDescription.Builder()
.buttonType("submit").tagName("BUTTON").name("NEXT").build()).click();
// SELENIUM: confirm the user name and pass
chromeDriver.findElementByXPath("//DIV[#id=\"paymentMethod\"]/DIV/DIV/SEC-FORM/SEC-VIEW/DIV[normalize-space()=\"*SafePay username\"]/INPUT[1]").sendKeys(username);
chromeDriver.findElementByXPath("//DIV[#id=\"paymentMethod\"]/DIV/DIV/SEC-FORM/SEC-VIEW/DIV[normalize-space()=\"*SafePay password\"]/INPUT[1]").sendKeys("Password1");
// LEANFT: click "Pay now" and confirm payment was done
browser.describe(Button.class, new ButtonDescription.Builder()
.buttonType("button").role("button").accessibilityName("").tagName("BUTTON").name("PAY NOW").index(0).build()).click();
Verify.isTrue(
browser.describe(WebElement.class, new WebElementDescription.Builder()
.tagName("SPAN").innerText("Thank you for buying with Advantage").build())
.exists());
}
}

In Selenium, What is the command to "wait until the page loading stops"

How to make the WebDriver wait until the page loading stops completely.
Means, it waits and checks whether entire page has been loaded or not, then only it proceeds with the next line execution.
The biggest problem is that there is no generic, one-size-fits-all solution that will work for even a majority of users. The concept of "when is my page finished loading" is rendered nearly meaningless in today's dynamic, AJAX-heavy, JavaScript-dependent web. One can wait for the browser to determine network traffic is complete, but that doesn't take JavaScript execution into account. One could define "complete" as the page's onload event having fired, but that overlooks the possibility of the page using setTimeout(). Furthermore, none of these definitions take frames or iframes into account.
When it comes to Selenium, there are a couple of factors to consider. Remember that the Selenium RC API is 10 years old. When it was designed and developed, the architecture of typical web pages made a method like waitForPageToLoad practical. The WebDriver API, on the other hand, recognizes the current reality. Individual driver implementations usually will try to wait for a page load during an explicit page navigation (e.g., driver.get()), but this wait will be a "best effort", and is not a guarantee. Please note that navigation caused by user interaction (e.g., element.click()) will be less likely to fully wait, because such interactions are asynchronous, and thus inherently have race conditions.
The correct approach for WebDriver is to wait for the element you want to interact with to appear on the subsequent page. This is best accomplished with a WebDriverWait or a similar construct. You might find some of these other constructs in the support library, mainly in those dealing with the Page Object pattern. You could also try setting the implicit wait timeout in your driver instance, but I believe using it obscures intent.
That's actually the default behavior of Selenium - it waits until all requests are complete before going on to the next line of code.
There is a design pattern provided through the Selenium support library SlowLoadableComponent that would do what you want: https://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/support/ui/SlowLoadableComponent.html. The gist is that you write your page object to extend SlowLoadableComponent. You will have to provide implementations for two abstract methods in SlowLoadableComponent: load() and isLoaded()
TheisLoaded() method should check everything you need to consider your page 'loaded'. The load() method performs the actions necessary to load your page object. You specify a load timeout for your page object (I do this through the page object's constructor). When you invoke the get() method on your page object, which is inherited from SlowLoadableComponent, it will call isLoaded(). If your page object is not loaded, it will then call load() to load your page object. It will continue to do this until your page object is loaded or until your timeout expires.
You will have to define yourself what it means for your page object to be loaded, however. There is no out of the box way for Selenium to determine if your particular page object is loaded or not because these determinations are so context-sensitive. For example, consider a page object representing the login page for a web app. It is 'loaded' if the username and password entry text boxes and the submit login button are visible. This does not apply to a page object representing some other page in a web app. You have to custom tailor the 'is loaded' criteria for any given page object.
Here is a simple example. Basic abstract loadable object:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.SlowLoadableComponent;
import org.openqa.selenium.support.ui.SystemClock;
public abstract class AbstractLoadableComponent<T extends AbstractLoadableComponent<T>> extends SlowLoadableComponent<T> {
public static final int DEFAULT_TIMEOUT_IN_SECONDS = 30;
private final WebDriver driver;
private final int timeoutInSeconds;
public AbstractLoadableComponent(final WebDriver driver, final int timeoutInSeconds) {
super(new SystemClock(), timeoutInSeconds);
this.driver = driver;
this.timeoutInSeconds = timeoutInSeconds;
this.load();
}
public final WebDriver getDriver() {
return driver;
}
public final int getTimeoutInSeconds() {
return timeoutInSeconds;
}
#Override
protected void load() {
PageFactory.initElements(getDriver(), this);
}
}
Basic abstract page object:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.SlowLoadableComponent;
public abstract class AbstractPage<T extends AbstractPage<T>> extends AbstractLoadableComponent<T> {
private final String url;
public AbstractPage(final WebDriver driver) {
this(driver, driver.getCurrentUrl(), DEFAULT_TIMEOUT_IN_SECONDS);
}
public AbstractPage(final WebDriver driver, final String url) {
this(driver, url, DEFAULT_TIMEOUT_IN_SECONDS);
}
public AbstractPage(final WebDriver driver, final String url, final int timeoutInSeconds) {
super(driver, timeoutInSeconds);
this.url = url;
}
public final String getUrl() {
return url;
}
#Override
protected void load() {
super.load();
if(url != null) {
getDriver().get(url);
}
}
}
Basic concrete page object class for a login page:
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import static org.testng.Assert.assertTrue;
public final class LoginPage extends AbstractPage<LoginPage> {
#FindBy(how = How.ID, using = "username")
private WebElement usernameBox;
#FindBy(how = How.ID, using = "password")
private WebElement passwordBox;
#FindBy(how = How.NAME, using = "login")
private WebElement loginButton;
public LoginPage(final WebDriver driver) {
this(driver, driver.getCurrentUrl(), DEFAULT_TIMEOUT_IN_SECONDS);
}
public LoginPage(final WebDriver driver, final String url) {
this(driver, url, DEFAULT_TIMEOUT_IN_SECONDS);
}
public LoginPage(final WebDriver driver, final String url, final int timeoutInSeconds) {
super(driver, url, timeoutInSeconds);
}
#Override
protected final void isLoaded() throws Error {
try {
assertTrue(usernameBox.isDisplayed(), "Username text box is not displayed");
assertTrue(passwordBox.isDisplayed(), "Password text box is not displayed");
assertTrue(loginButton.isDisplayed(), "Login button is not displayed");
} catch(NoSuchElementException nsee) {
throw new Error(nsee);
}
}
}
driver.manage.implicitlywait(3, TimeUnit.Seconds) will hep.

Is it possible to start few seleniums for one selenium server?

Is this valid code?
selenium = new DefaultSelenium("localhost", 4444, "*iehta",
"http://www.google.com/");
selenium.start();
...
selenium.stop();
...
selenium.start();
...
selenium.stop();
There's nothing wrong with having multiple browsers open (what you call "seleniums"). In fact, it's the only way you can test certain applications. Imagine an application that has an administrative UI and an end-user UI, where you make changes on the admin side and verify their effects on the user side. You can either write your test to jump back and forth between the two on the same browser session, or you can open two browsers, one for each aspect of the application. The former is the usual technique, but the latter is much cleaner.
And why do you think it shouldn't be safe? unless it works ok it's fine, If it doesn't than recreate the DefaultSelenium object again, it won't slow down your code anyway
You should usually keep start() and stop() as you set up and tear down methods. While using TestNG you can annonate then with #BeforeClass and #AfterClass annonations. Hence browser would be launched and shut down only before and after a test method in a class.
b/w did you support Selenium Proposal on area51 - http://area51.stackexchange.com/proposals/4693/selenium
This proposal is backed by SeleniumHQ and we need more users to commit to it to make it see day of light.
That was my fault.
Unexpected behaviour caused by this code and occurs because I stop selenium two times (selenium object never become null):
public class SeleniumController {
private static Selenium selenium;
public static Selenium startNewSelenium(){
// if already exists stop it and replace with new one
if(selenium != null){
selenium.stop();
}
selenium = createNewSelenium(getCurContext());
return selenium;
}
public static void stopSelenium() {
if(selenium != null){
selenium.stop();
}
}
private static Selenium createNewSelenium(TestContext testContext){
TestProperties testProps = new TestProperties(testContext);
ExtendedSelenium selenium = new ExtendedSelenium("localhost", RemoteControlConfiguration.DEFAULT_PORT,
testProps.getBrowser(), testProps.getServerUrl());
selenium.start();
selenium.useXpathLibrary("javascript-xpath");
selenium.allowNativeXpath("false");
return selenium;
}
}
The correct class code is:
public class SeleniumController {
private static Selenium selenium;
public static Selenium startNewSelenium(){
// if already exists stop it and replace with new one
stopSelenium();
selenium = createNewSelenium(getCurContext());
return selenium;
}
public static void stopSelenium() {
if(selenium != null){
selenium.stop();
selenium = null;
}
}
private static Selenium createNewSelenium(TestContext testContext){
TestProperties testProps = new TestProperties(testContext);
ExtendedSelenium selenium = new ExtendedSelenium("localhost", RemoteControlConfiguration.DEFAULT_PORT,
testProps.getBrowser(), testProps.getServerUrl());
selenium.start();
selenium.useXpathLibrary("javascript-xpath");
selenium.allowNativeXpath("false");
return selenium;
}
}