Testing webpages with Selenium for beginners

Oct 14 2013 by Lars M. Hansen

 Selenium WebDriver is a tool for testing functionality of web pages. Essentially, the program you write simulates what a end user would do on the web page; basically, clicking on various elements on your webpage. The Selenium suite is available for Java and C#, and I'll be using Java for this article.

For the purpose of this article and code samples, I'm going to show how to write the test for a simple login page. The login page only has three elements we care really care about at the point; the username field, password field, and the "login" button. The plan here is quite simple: Open the page, type in the user name, type in the password, then click the "login" button, and make sure that we got past the login page and on to the next page of your site. 

We're going to start with creating a new class, and we'll simply call it "login", and define a couple of variables we'll be using within the test.

public class Login {
  private static WebDriver webdriver;
  private static Dimension winSize;
  

I know, I know, everyone uses "driver" for the variable name for the WebDriver type. But, I'll use "driver" later on, and I don't like to have global and local variables with the same name.

The next step is to create the function that will launch the testing. For this, we use the @Test keyword to define the function that will start when the code is launched as a unit test. This basically replaces the main() function of a regular program. This part of the program will just launch the web browser, call the actual test function, then report the result of the test.

@Test
public void loginTest() {
  boolean testOK;

  webdriver = new FirefoxDriver(); // launch the Firefox browser for this test
  winSize = webdriver.manage().window().getSize(); // store initial size of window
  webdriver.manage().window().maximize(); // Maximize the browser (optional)

  // login() does the actual testing, returning true/false
  testOK = login(webdriver, "jdoe", "Password123!");

  if(testOK) {
    System.out.println("Test of login successful");
  } else {
    System.out.println("Failed to log in to site");
  }
}

The above piece is fairly simple, and documented inline. I'm creating a new browser instance, saving the window size so I can restore it later, then I maximize the window. I've had trouble with getting some elements to work 100% if the window isn't maximized, so I've gotten in the habit of maximizing the windows now. The we call the login() function with the username, password as well as a reference to the webdriver as the argument. Setting it up like this will allow me to call this same login() function from other classes so I can integrate this function into a larger test suite.

Now onto the login function, which will do all the testing. First, we'll validate the input, then open the page we're going to test, and test that the page is actually opened.

public static boolean login(WebDriver driver, String userName, String pwd) {
  WebElement uname = null;
  WebElement password = null;
  if (userName == null || userName.isEmpty()) return false;
  if (pwd == null || pwd.isEmpty()) return false;

  driver.get("http://qaserver.localdomain.local");

  WebDriverWait pageLoaded = new WebDriverWait(driver, 30);
  try {
    uname = pageLoaded.until(ExpectedConditions.presenceOfElementLocated(By.id("username")));
  } catch (Exception e) {
    // failed to locate element.
    System.out.println("Unable to locate Username Element. Page not loaded(?)");
    return false;
  } 

Not a lot going on here yet. First we just check to make sure that the username and passwords have values, and we return with a fail condition. The next step is actually loading the web page.

The next part of the above code  is where many go wrong with their "101" stuff. They just assume that things are there. Don't assume. Prepare for something not going right, and have a plan for what to do if it does. Using WebDriverWait, we can have the code wait for a given timeout value (here: 30 seconds) for a required condition to be true. In this case, we're using ExpectedConditions.presenceOfElementLocated() as the condition, and this will be true once the field with the ID "username" can be located on the page. Should the element not be present in 30 seconds, then it'll raise an exception, hence it is wrapped in a try/catch so we can handle the exception without there being a crash.

  uname.clear();
  uname.sendKeys(userName);

  try {
    password = driver.findElement(By.id("password"));
  } catch (Exception e) {
    // failed to locate element
    System.out.println("Failed to locate password element.");
    return false;
  }

  password.clear();
  password.sendKeys(pwd);

Above, we're just entering the username and password. We don't do another WebDriverWait here, because we know the page is loaded. But, we still have to test to make sure we successfully locate the element, because one of the web developers may have changed the id or something other foolish ...

   WebElement button = null;
  try {
    button = driver.findElement(By.id("login"));
  } catch (Exception e) {
    // can't locate the login button
    System.out.println("Failed to locate login button");
    return false;
  }

  button.click();

Again, we're doing the same thing. Attempting to locate an element with a specific ID, catching any errors and returning a fail condition if there are errors. And, if everything did go well, we click the button. This should start the login process, and possibly take you to a different page.

Since the login part is likely something that you'll need to do over and over every time you're testing anything (as you may have to log back in to the site for every test), it would make sense to put as much of any repeating code into this function as possible, including the waiting for the next/main page to load. In order to do this, we just need to know an ID from the main page that will be displayed after everything else is loaded. For instance, if you have any grids that needs to fill with data once you've logged in, grabbing an ID from that might be handy, as they will likely take the longest to load.

  // wait for main page to fully load
  WebDriverWait loginWait = new WebDriverWait(driver, 30);

  try {
    WebElement mainPage = loginWait.until(expectedConditions.presenceOfElementLocated(By.id("row0")));
  } catch (Exception e) {
    System.out.println("Doesn't appear to be able to load main page");
    return false;
  }

  // If we get all the way here, everything is fine!
  return true;
}

So, there you have it; making sure that everything is present before we interact with it. Failure to doing so will inevitably break your code as soon as one of the developers changes something without thinking how it'll impact your code.

There is one final piece; the @After function, to clean up after our test session. I usually just close the browser at the end, but very often put in temporary pieces in the @After that'll keep the browser open, as I may have to poke around in the page source to find the ID's or elements I need to look for next.

@After
public void tearDown() {
  System.out.println("Test finished, closing down");
  webdriver.manage().window().setSize(winSize);
  webdriver.quit();
}

This just prints out the confirmation that the test has completed, then resets the window size to the original size, and then closes the browser used by the test. That last line is usually commented out until there are no more //todo's in the code.

Happy testing.

1999 - 2013 Lars M. Hansen