In our previous post, Selenium Java: An Intelligent Example Part 1, we described how to manage Technical Debt and the importance of using a Page Model. We also gave an overview of the classes used in this example project. In this post, we will be getting into the code. We will demonstrate how everything ties together and how you could build a similar project to test your application.
BasePage
The BasePage class is at the center of it all. It is an abstract class that all page model classes inherit from. Through inheritance, the BasePage will provide page model objects with common resources and behaviors such as:
- WebDriverResource
- Parent and Local window handles
- Method for getting a new instance of a page object by its class name
- Method for quitting when you are all done and ready to clean up
- Method for setting up your window handles and wait conditions
Creating a new Page Model object
BasePage.getInstance() provides a way to create page model objects by class name rather than having to “new them up”. This practice is preferred given that it puts initialization code in one place making it easier to extend and to modify.
... public static <C extends BasePage> C getInstance(Class<C> clazz){ C page = PageFactory.initElements(wdResource.driver, clazz); wdResource.wait.until(page.ready()); return page; } ...
This method uses Generics to determine both the return type and the class that is passed in as a parameter. In this fashion you can pass in the name of any class that extends BasePage, and the method will return an instance of it initialized with a WebDriverResource after waiting for any expected conditions to be met. Each child class of BasePage can declare these expected conditions by overriding the ready method. We will dive more into this in our next post.
Window Handling
Each browser tab or new page is accessed through a window handle maintained by your WebDriver object. As you open new tabs or pages, additional handles are added to the driver object. By default, the BasePage.ready() sets the parent and local window handles for that page model and calls driver.switchTo() in order to change the driver’s focus to the local window handle. This conveniently switches the driver’s focus to any newly opened tab or window. If a new tab or window is not opened, then the driver’s focus does not change.
... public ExpectedCondition<?> ready(){ // set parent and local Window Handles then switch to local handle parentWindowHandle = wdResource.driver.getWindowHandle(); List<String> handlesList = new ArrayList<>(wdResource.driver.getWindowHandles()); localWindowHandle = handlesList.get(handlesList.size() - 1); wdResource.driver.switchTo().window(localWindowHandle); // this is the default case with no wait so return null return null; } ...
Quitting
BasePage.quit() closes all browser windows opened by the driver. This method can be overridden in the event you need to clean anything else up that is related to a specific page.
... public static void quit(){ wdResource.driver.quit(); } ...
WebDriverResource
WebDriverResource uses a Singleton pattern to insure that only one instance is ever created even though its getInstance() method is called at the creation of every page model. WebDriverResource class is like a tool bag that is provided to all page models by the BasePage through inheritance. It provides us with our WebDriver and our WebDriverWait objects.
... public static WebDriverResource getInstance() { if(instance == null){ instance = new WebDriverResource(); } return instance; } ...
The WebDriverResource’s constructor will read configuration information in from a JSON file then use this information to create instances of both the WebDriver and the WebDriverWait objects.
... private WebDriverResource() { // lets get the browser info from the JSON config file. String browserName= ""; String baseURL = ""; int waitTimeOut = 0; try { JSONParser parser = new JSONParser(); JSONObject jsonObject = (JSONObject)parser.parse(new FileReader("./src/config.json")); JSONObject pageInfo = (JSONObject)jsonObject.get("pageInfo"); browserName = pageInfo.get("browserName").toString(); baseURL = pageInfo.get("baseURL").toString(); waitTimeOut = Integer.parseInt(pageInfo.get("waitTimeOut").toString()); } catch(Exception ex){ System.out.println(ex.getMessage()); ex.printStackTrace(); } driver = BrowserFactory.getDriver(browserName); wait = new WebDriverWait(driver, waitTimeOut); driver.get(baseURL); } ...
BrowserFactory
The BrowserFactory is a simple class that provides a method for us to construct a WebDriver with a string. In this example we are setup to support multiple WebDrivers, but we will default to Firefox in the case that we cannot find a match.
... public static WebDriver getDriver(String browser){ WebDriver driver; switch (browser.toLowerCase()) { case "firefox": driver = new FirefoxDriver(); break; case "ie": driver = new InternetExplorerDriver(); break; case "safari": driver = new SafariDriver(); break; case "chrome": driver = new ChromeDriver(); break; default: driver = new FirefoxDriver(); } // end switch return driver; } ...
What is next?
In our final post we will look at the Page Model objects in detail. We will see how to find web elements on the page and how to use them. We will also see how to override the page’s ready method to perform intelligent waits. You can find the example project out on GitHub at: Selenium Example Project.