How to run scripts in a specific browser with Maven

mvn test is the Maven command for running test scripts in command prompt (or Jenkins).

It runs all test scripts from the test class in the browser defined in the project.

But what if you would like to specify the browser name as a parameter of the command?

Such as

mvn test -Dbrowser=chrome

or

mvn test -Dbrowser=firefox

How can this be done?

There are 3 parts to it.

 

Create a custom driver class

The custom driver class should implement the WebDriver interface and all its methods.

Its constructor has browser name as parameter and it creates the appropriate web driver.

 

import java.util.List;
import java.util.Set;

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.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;

public class Driver implements WebDriver {

WebDriver driver;
String browserName;

public Driver(String browserName) {
  this.browserName = browserName;

  if (browserName.equalsIgnoreCase("chrome"))
   this.driver = new ChromeDriver();

  if (browserName.equalsIgnoreCase("firefox"))
   this.driver = new FirefoxDriver();

  if (browserName.equalsIgnoreCase("ie"))
   this.driver = new InternetExplorerDriver();

}

public void close() {
  this.driver.close();

}

public WebElement findElement(By arg0) {
  return this.driver.findElement(arg0);
}

public List<WebElement> findElements(By arg0) {
  return this.driver.findElements(arg0);
}

public void get(String arg0) {
  this.driver.get(arg0);

}

public String getCurrentUrl() {
  return this.driver.getCurrentUrl();
}

public String getPageSource() {
  return this.driver.getPageSource();
}

public String getTitle() {
  return this.driver.getTitle();
}

public String getWindowHandle() {
  return this.driver.getWindowHandle();
}

public Set<String> getWindowHandles() {
  return this.driver.getWindowHandles();
}

public Options manage() {
  return this.driver.manage();
}

public Navigation navigate() {
  return this.driver.navigate();
}

public void quit() {
  this.driver.quit();
}

public TargetLocator switchTo() {
  return this.driver.switchTo();
}

 

Read the browser property from Maven command

The maven command looks like

mvn test -Dbrowser=chrome

Browser is a system property that can be read in the setUp() method of the test class:

String browserName = getParameter("browser");

 

Create the driver based on the browser name

This is done as well in the setUp() method of the test class:

 

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestsMaven {

 Driver driver;

 @Before
 public void setUp() {
  String browserName = getParameter("browser");
  driver = new Driver(browserName);
 }

 @After
 public void tearDown() {
  driver.quit();
 }

 private String getParameter(String name) {
  String value = System.getProperty(name);
  if (value == null)
     throw new RuntimeException(name + " is not a parameter!");

  if (value.isEmpty())
    throw new RuntimeException(name + " is empty!");

  return value;
 }

 @Test
 public void test1() {
  driver.get("http://www.vpl.ca");
 }

}

}

 

You can now execute the maven command in command prompt so that the tests run in a specific browser.

Advertisements

Correct and incorrect ways of creating page object classes

Let’s say that you want to automate test scenarios for the login page of a web site.

The login page has 3 elements:

– username textbox

– password textbox

– sign in button

 

login

 

Some of the test cases to be automated for this page are

  1. user can sign in with correct username and password
  2. user cannot sign in if username or password are incorrect
  3. password is masked
  4. user can create a new account

 

In this article, we will focus on the first test case only.

Since the test cases uses 2 pages (login page and the page the user sees after a successful sign in), we will need 2 page object classes:

  1. LoginPage class
  2. MainPage class

One way of implementing the LoginPage.java class is

public class LoginPage {

private WebDriver driver;

private WebDriverWait wait;

private By userNameLocator = By.id("userNameId");

private By passwordLocator = By.id("passwordId");

private By signInLocator   = By.id("signInId");

 

public LoginPage(WebDriver driver) {

   this.driver = driver;

   this.wait = new WebDriverWait(driver, 30);

}

public void clickUserName() {

   WebElement userName = findElement(userNameLocator);

   userName.click();

}

public void clickPassword() {

   WebElement password = findElement(passwordLocator);

   password.click();

}

public void clickSignIn() {

   WebElement signIn = findElement(signInLocator);

   signIn.click();

}

public void typeUserName(String value) {

   WebElement userName = findElement(userNameLocator);

   userName.sendKeys(value);

}

public void typePassword(String value) {

   WebElement password = findElement(passwordLocator);

   password.sendKeys(value);

}

private WebElement findElement(By locator) {

  return

  wait.until(visibilityOfElementLocated(locator));

}

 

The LoginPage class has multiple methods for clicking elements and typing text into them.

Using this LoginPage class, we can now build a test script (JUNIT):

@Test

public void testSuccessfullLogin() {

  LoginPage loginPage = new LoginPage(driver);

  loginPage.clickUserName();

  loginPage.typeUserName("admin");

  loginPage.clickPassword();

  loginPage.typePassword("abcdef");

  loginPage.clickSignIn();

  MainPage mainPage = new MainPage(driver);

  assertTrue(mainPage.isDisplayed() == true);

}

 

Building a page object class like this is not correct.

It is not correct because what we do is creating an API that interacts with HTML elements.

For a page that has only 3 elements, we have 5 methods.

Imagine how many methods you will need for a page with 100 elements.

 

The correct approach for page object classes is explained in the following link:

https://martinfowler.com/bliki/PageObject.html

We should not create page object classes and APIs that interact with HTML elements.

Instead, we should create page classes and APIs that interacts with the site similar with how a user does it.

 

 

pageobject

 

See below the LoginPage class changed to interact with the site:

public class LoginPage {

private WebDriver driver;

private WebDriverWait wait;

private By userNameLocator = By.id("userNameId");

private By passwordLocator = By.id("passwordId");

private By signInLocator = By.id("signInId");

 

public LoginPage(WebDriver driver) {

 this.driver = driver;

 this.wait = new WebDriverWait(driver, 30);

}

public void signInWith(String userName, String password) {

 WebElement userName = findElement(userNameLocator);

 userName.click();

 userName.sendKeys(value);

 WebElement password = findElement(passwordLocator);

 password.click();

 password.sendKeys(value);

 WebElement signIn = findElement(signInLocator);

 signIn.click();

}

private WebElement findElement(By locator) {

  return

  wait.until(visibilityOfElementLocated(locator));

}

}

The class has now 1 method only instead of 5.

This method is about interacting with the site like a user by signing in.

Using the LoginPage class, the test script becomes

@Test

public void testSuccessfullLogin() {

  LoginPage loginPage = new LoginPage(driver);

  loginPage.signInWith("admin", "abcdef");

  MainPage mainPage = new MainPage(driver); 

  assertTrue(mainPage.isDisplayed() == true);

}

 

The test script is significantly shorter now.

It also looks like English and is similar to a test case.

We should always aim to

  1.  making the test scripts as short as possible
  2.  moving code from the test script to the page object class
  3.  not using any webdriver object or method in the test scripts
  4.  use only page objects and page methods in the test scripts
  5.  not creating any methods that interact with an element in the page object classes
  6.  keep page object classes short (less than 250 lines of code)
  7.  do not create methods that include in their names the following words: click, type, getText, etc as these are most probably interacting with single elements