How to Share same selenium Driver between step definitions

1 min


660
1 comment, 660 points
Share same selenium Driver between step definitions
Share same selenium Driver between step definitions

How to Share same selenium Driver between step definitions

I had the chance to work in couple of Java automation environments and I always tried to improve the way selenium is used and properly share same selenium Driver between step definitions.

Imagine you have a Java Selenium project with Cucumber jvm to run your functional tests against your app. And the whole idea of a page object pattern is to create our testing code maintainable, reusable and  Page Factory is an optimized way to create object repository in POM concept

Using Selenium webdriver you’ll have to share the driver instance between your step definitions. Imagine a feature file that defines couple of steps: one to navigate to a page, another to click on an element  and another to assert something. If all steps happen to be defined in separate files, the first step definition will use its driver to navigate to the page. By the time the second step definition runs the click action its driver it hasn’t navigated to the page (since those actions went to the other driver) and the test fails.

Solution

Using pico-container as a dependency you can share same selenium Driver between step definitions.

Assuming you have a BrowserFactory that looks something like this:

package automation.ui;

import org.openqa.selenium.WebDriver;

class BrowserFactory {

    public static WebDriver getBrowser() throws Throwable {
        String desiredBrowserName = System.getProperty("browser", "firefox");
        WebDriver desiredBrowser = null;

        switch(desiredBrowserName) {
            case "ie":
                desiredBrowser = IEBrowser.buildIEBrowser();
                break;
            case "chrome":
                desiredBrowser = ChromeBrowser.buildChromeBrowser();
                break;
            case "firefox":
                desiredBrowser = FirefoxBrowser.buildFirefoxBrowser();
                break;
            default:
                //work out what to do when a browser isn't needed
                break;
        }
        return desiredBrowser;
    }
}

A  very slightly modified version of SharedDriver from cucumber-jvm :

import cucumber.api.Scenario;
import cucumber.api.java.After;
import cucumber.api.java.Before;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.support.events.EventFiringWebDriver;

import java.util.concurrent.TimeUnit;

import static automation.ui.BrowserFactory.getBrowser;

    private static final Thread CLOSE_THREAD = new Thread() {
        @Override
        public void run() {
            REAL_DRIVER.close();
        }
    };

    static {
        Runtime.getRuntime().addShutdownHook(CLOSE_THREAD);
        try {
            REAL_DRIVER = getBrowser();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            throw new Error(throwable);
        }
    }

    public SharedDriver() {

        super(REAL_DRIVER);
        REAL_DRIVER.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    }

    @Override
    public void close() {
        if (Thread.currentThread() != CLOSE_THREAD) {
            throw new UnsupportedOperationException("You shouldn't close this WebDriver. It's shared and will close when the JVM exits.");
        }
        super.close();
    }

    @Before
    public void deleteAllCookies() {
        manage().deleteAllCookies();
    }

    @After
    public void embedScreenshot(Scenario scenario) {
        try {
            byte[] screenshot = getScreenshotAs(OutputType.BYTES);
            scenario.embed(screenshot, "image/png");
        } catch (WebDriverException somePlatformsDontSupportScreenshots) {
            System.err.println(somePlatformsDontSupportScreenshots.getMessage());
        }
    }
}
SharedDriver

And now our PicoDependencyInjector class :

package automation.support;

import automation.ui.SharedDriver;
import cucumber.runtime.java.picocontainer.PicoFactory;

public class PicoDependencyInjector extends PicoFactory {

    public PicoDependencyInjector() {
        addClass(SharedDriver.class);
    }
}
PicoDependencyInjector

So here we use pico-container as a dependency injection framework to use with cucumber-jvm.

And our Page class and Step definitions class will look something like this :

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

import java.util.concurrent.TimeUnit;

public class GoogleSearchPage {
	private final String url = "http://www.google.co.uk/";
	private final WebDriver driver;

	@FindBy(css = "#lst-ib")
	private WebElement searchField;

	@FindBy(css = "button[name='btnG']")
	private WebElement searchButton;

	public GoogleSearchPage(WebDriver commonDriver) {
		driver = commonDriver;
		driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
		PageFactory.initElements(driver, this);
	}

	public void load() {
		driver.get(url);
	}

	public void searchFor(String searchString) {
		searchField.clear();
		searchField.sendKeys(searchString + "\n");
		searchButton.click();
	}
}
PageClass
Step definition class:
public class GoogleSteps {
	private final GoogleSearchPage googleSearchPage;
	private final GoogleSearchResultsPage googleSearchResultsPage;
	
	private final Logger logger = LoggerFactory.getLogger(GoogleSteps.class);

	public GoogleSteps(GoogleSearchPage commonGoogleSearchPage, GoogleSearchResultsPage commonGoogleSearchResultsPage) {
		googleSearchPage = commonGoogleSearchPage;
		googleSearchResultsPage = commonGoogleSearchResultsPage;
	}

	@Given("^I am using Google$")
	public void i_am_using_Google() throws Throwable {
		logger.info("Loading page");
		googleSearchPage.load();
		logger.debug("Loaded page");
	}

	@When("^I search for (.*)$")
	public void i_search_for_search_term(String searchTerm) throws Throwable {
		googleSearchPage.searchFor(searchTerm);
	}

	@Then("^I am shown search results for (.*)$")
	public void i_am_shown_search_results_for_search_term(String searchTerm) throws Throwable {
		assertThat(googleSearchResultsPage.firstHitTitle().toLowerCase(), containsString(searchTerm));
	}
}
Steps

Maven dependency :

<dependency>
    <groupId>info.cukes</groupId>
    <artifactId>cucumber-picocontainer</artifactId>
    <version>1.2.3</version>
    <scope>test</scope>
</dependency>

We will cover in a different topic how to build a project with cucumber jvm from scratch , till then hope this will help.

Happy testing!


Like it? Share with your friends!

660
1 comment, 660 points

What's Your Reaction?

cute cute
0
cute
scary scary
0
scary
wtf wtf
0
wtf
geek geek
0
geek
WIN WIN
0
WIN
Love Love
0
Love
OMG OMG
1
OMG
Angry Angry
0
Angry
Lol Lol
0
Lol
Test engineer

One Comment

Your email address will not be published. Required fields are marked *

Choose A Format
Trivia quiz
Story