Do Cross Browser Test Automation Like A PRO - Part 2


Part 1 showed how to run a test script in a local browser.

In Part 2, we  change the code so that the test script runs in multiple local browsers.

See below how each class changes.





TEST CLASS


The test class needs the following changes:
  • @RunWith(value = Parameterized.class) annotation is added before the class so that the class can have test scripts with parameters
  • browserName member is added as parameter of the test script; it uses the @Parameter annotation
  • the public static Collection object data () specifies the values that the browserName parameter can take
  • the Driver.initialize(browserName) method uses the browserName parameter 


package TESTS;
import static org.junit.Assert.*;
import java.net.MalformedURLException;
import java.util.Arrays;
import java.util.Collection;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import FRAMEWORK.Driver;
import FRAMEWORK.HomePage;
import FRAMEWORK.ResultsPage;

@RunWith(value = Parameterized.class)
public class TestScripts_LocalBrowsers {                  

@Parameter
public String browserName;   

@Parameters
public static Collection object data () {
     
Object[][] data = {{"Firefox"}, {"Chrome"}, {"InternetExplorer"}};

return Arrays.asList(data);   

} 

@Before
public void setUp() throws MalformedURLException 
{   

Driver.initialize(browserName); 

}

@After
public void tearDown()
{   

Driver.getDriver().quit();  

}

@Test
public void testResultsInfo() throws InterruptedException
{        

ResultsPage results = (new HomePage()).search();    
     
assertTrue(results.isKeywordDisplayed() == true);                     

assertTrue(results.resultsCount() > 0);             

}   

}



DRIVER CLASS


The driver class needs the following changes:
  • a new initialize(browser) method is added; the new method uses a parameter for the browserName
  • the initialize(browser) method creates the browser driver that corresponds to the browser name



package FRAMEWORK;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.Platform;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.remote.DesiredCapabilities;

public class Driver { 

private static WebDriver driver;  

public static WebDriver getDriver()
{

return driver;

}

public static void initialize() 
{      

driver = getFirefoxDriver();

}

public static void quit() 
{      

getDriver().quit();

}

public static void initialize(String browser) throws MalformedURLException
{      

if (browser.equalsIgnoreCase("Chrome")) 
{

driver = getChromeDriver();
return;

}

if (browser.equalsIgnoreCase("InternetExplorer"))
{

driver = getInternetExplorerDriver();
return;

}

if (browser.equalsIgnoreCase("Firefox"))
{

driver = getFirefoxDriver();
return;

}

throw new NoSuchElementException("Invalid browser name");

}   

private static WebDriver getChromeDriver()
{

System.setProperty("webdriver.chrome.driver", 
"C:\\Selenium\\BrowserDrivers\\chromedriver.exe");

return  new ChromeDriver(); 

}

private static WebDriver getFirefoxDriver()
{    

return new FirefoxDriver();

}

private static WebDriver getInternetExplorerDriver()
{  

System.setProperty("webdriver.ie.driver", 
"C:\\Selenium\\BrowserDrivers\\IEDriverServer.exe");

return  new InternetExplorerDriver();     

}      

}



HOME PAGE CLASS


The home page class has only one change.

It uses By locators instead of String locators.

It uses By.id and By.name when possible.


package FRAMEWORK;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

public class HomePage {

By searchMenuItemLocator = By.id("search-cta");
By searchTextBoxLocator  = By.id("searchinput");
By searchButtonLocator   = By.name("simplesearch");  

WebDriver driver; 
WebDriverWait wait;               

public HomePage()
{  

this.driver = Driver.getDriver();
wait = new WebDriverWait(driver, 10);

driver.get(Settings.siteUrl);

wait.until(ExpectedConditions.titleIs(Settings.homePageTitle));

}   

public ResultsPage search()
{

wait.until(ExpectedConditions.
elementToBeClickable(searchMenuItemLocator)).
click();

wait.until(ExpectedConditions.
elementToBeClickable(searchTextBoxLocator)).
sendKeys(Settings.keyword);

wait.until(ExpectedConditions.
elementToBeClickable(searchButtonLocator)).
click();    

return new ResultsPage();  

}     

}



RESULTS PAGE CLASS


The results page class has only one change.

It uses By locators instead of String locators.

It uses By.id and By.name when possible.


package FRAMEWORK;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

public class ResultsPage { 

By searchKeywordLocator = By.xpath("//h2[@class='product-search']/a"); 
By resultsCountLocator  = By.xpath("(//div[@class='resultshits'])[1]");

WebDriver driver; 
WebDriverWait wait; 

public ResultsPage()
{ 

this.driver = Driver.getDriver();
wait = new WebDriverWait(driver, 10);

wait.until(ExpectedConditions.titleIs(Settings.resultsPageTitle));

}    

public Boolean isKeywordDisplayed()
{ 

return wait.until(ExpectedConditions.
visibilityOfElementLocated(searchKeywordLocator)).
isDisplayed(); 

}    

public int resultsCount()
{     

WebElement resultCountElement = wait.until(ExpectedConditions.
visibilityOfElementLocated(resultsCountLocator));

return Integer.parseInt(extractValue(resultCountElement.getText(), Settings.resultsCountRegEx, 3)); 

}

public String extractValue(String textValue, String regEx, int position)
{ 

String result = "";

Pattern pattern = Pattern.compile(regEx);

Matcher matcher = pattern.matcher(textValue);

if (matcher.find())

result = matcher.group(position); 

return result;

} 

}


Part 3 will change the code more so that the test script runs in a cloud Selenium Grid.


If you have any questions about how the code works or any difficulties running it, please post them in the Comments section.



Share this

2 Responses to "Do Cross Browser Test Automation Like A PRO - Part 2"

  1. On the TEST page:

    public class TestScripts_LocalBrowsers {

    @Parameter
    public String browserName;

    @Parameters // On this line I get error, "@Parameters not applicable to type"
    public static Collection object data () { //On this line, "invalid method declaration; return type required"

    Object[][] data = {{"Firefox"}, {"Chrome"}, {"InternetExplorer"}};

    return Arrays.asList(data); // Here I get, "Cannot return a value from a method with a void result type".
    }

    ReplyDelete
  2. When adding @Parameters to my test class, I get an error: The annotation @Parameterized.Parameters is disallowed for this location. This pis probably because you have used illegal syntax at Collection data. Did you test your code before you published this?

    ReplyDelete