Total Pageviews

Featured Post

Excel tips and tricks

Things to Remember Borders can be used with the shortcut key Alt + H + B, which will directly take us to the Border option. Giving a border...

Monday, November 2, 2015

Seliniumweb driver Automation-notes

Selinium

Wait in selinium:

Before Selenium 2.6

WebDriverWait wait = new WebDriverWait(driver, 5); // wait for max of 5 seconds

ExpectedCondition<Boolean> resultsAreDisplayed = new ExpectedCondition<Boolean>() { // expected condition: element "pg" is displayed

    public Boolean apply(WebDriver arg0) {
        return driver.findElement(By.id("pg")).isDisplayed();
    }
};

wait.until(resultsAreDisplayed);

Selenium 2.6 & beyond

You can still use the code in the example above in 2.6, but the ExpectedConditions class has convenient helper methods to do a lot of the work for you (http://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html).
WebDriverWait wait = new WebDriverWait(driver, 5); // wait for max of 5 seconds
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("pg")));
As you can see, not only is WebDriverWait more readable then Thread.sleep (because the colleague reading your code will actually be able to tell what it is you’re waiting for), but it will also only wait until your expected condition happens before continuing to your next line of code – meaning the test only takes as long as it needs.
So put Thread.Sleep to err… sleep, and give WebDriverWait a try.

package org.openqa.selenium.example;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
public class Example  {
    public static void main(String[] args) {
        // Create a new instance of the html unit driver
        // Notice that the remainder of the code relies on the interface, 
        // not the implementation.
        WebDriver driver = new HtmlUnitDriver();

        // And now use this to visit Google
        driver.get("http://www.google.com");

        // Find the text input element by its name
        WebElement element = driver.findElement(By.name("q"));

        // Enter something to search for
        element.sendKeys("Cheese!");

        // Now submit the form. WebDriver will find the form for us from the element
        element.submit();

        // Check the title of the page
        System.out.println("Page title is: " + driver.getTitle());

        driver.quit();
    }
}
we could use any of:
WebElement element;
element = driver.findElement(By.id("passwd-id"));
element = driver.findElement(By.name("passwd"));
element = driver.findElement(By.xpath("//input[@id='passwd-id']"));

Filling In Forms

We've already seen how to enter text into a textarea or text field, but what about the other elements? You can "toggle" the state of checkboxes, and you can use "setSelected" to set something like an OPTION tag selected. Dealing with SELECT tags isn't too bad:
WebElement select = driver.findElement(By.xpath("//select"));
List<WebElement> allOptions = select.findElements(By.tagName("option"));
for (WebElement option : allOptions) {
    System.out.println(String.format("Value is: %s", option.getAttribute("value")));
    option.click();
}
This will find the first "SELECT" element on the page, and cycle through each of it's OPTIONs in turn, printing out their values, and selecting each in turn. As you can see, this isn't the most efficient way of dealing with SELECT elements. WebDriver's support classes come with one called "Select", which provides useful methods for interacting with these.
Once you've finished filling out the form, you probably want to submit it. One way to do this would be to find the "submit" button and click it:
driver.findElement(By.id("submit")).click();  // Assume the button has the ID "submit" :)
Alternatively, WebDriver has the convenience method "submit" on every element. If you call this on an element within a form, WebDriver will walk up the DOM until it finds the enclosing form and then calls submit on that. If the element isn't in a form, then the "NoSuchElementException" will be thrown:
element.submit();

Drag And Drop

You can use drag and drop, either moving an element by a certain amount, or on to another element:
WebElement element = driver.findElement(By.name("source"));
WebElement target = driver.findElement(By.name("target"));
(new Actions(driver)).dragAndDrop(element, target).perform();

Moving Between Windows and Frames

It's rare for a modern web application not to have any frames or to be constrained to a single window. WebDriver supports moving between named windows using the "switchTo" method:
driver.switchTo().window("windowName");
All calls to driver will now be interpreted as being directed to the particular window. But how do you know the window's name? Take a look at the javascript or link that opened it:
<a href="somewhere.html" target="windowName">Click here to open a new window</a>
Alternatively, you can pass a "window handle" to the "switchTo().window()" method. Knowing this, it's possible to iterate over every open window like so:
for (String handle : driver.getWindowHandles()) {
  driver.switchTo().window(handle);
}
You can also swing from frame to frame (or into iframes):
driver.switchTo().frame("frameName");
It's possible to access subframes by chaining switchTo() calls, and you can specify the frame by its index too. That is:
driver.switchTo().frame("frameName")
      .switchTo().frame(0)
      .switchTo().frame("child");
would go to the frame named "child" of the first subframe of the frame called "frameName". All frames are evaluated as if from currently switched to frame. To get back to the top level, call:
driver.switchTo().defaultContent();

Navigation: History and Location

Earlier, we covered navigating to a page using the "get" command (driver.get("http://www.example.com")) As you've seen, WebDriver has a number of smaller, task-focused interfaces, and navigation is a useful task. Because loading a page is such a fundamental requirement, the method to do this lives on the main WebDriver interface, but it's simply a synonym to:
driver.navigate().to("http://www.example.com");
To reiterate: "navigate().to()" and "get()" do exactly the same thing. One's just a lot easier to type than the other!
The "navigate" interface also exposes the ability to move backwards and forwards in your browser's history:
driver.navigate().forward();
driver.navigate().back();
Please be aware that this functionality depends entirely on the underlying browser. It's just possible that something unexpected may happen when you call these methods if you're used to the behaviour of one browser over another.

Cookies

Before we leave these next steps, you may be interested in understanding how to use cookies. First of all, you need to be on the domain that the cookie will be valid for:
// Go to the correct domain
driver.get("http://www.example.com");
// Now set the cookie. This one's valid for the entire domain
Cookie cookie = new Cookie("key", "value");
driver.manage().addCookie(cookie);
// And now output all the available cookies for the current URL
Set<Cookie> allCookies = driver.manage().getCookies();
for (Cookie loadedCookie : allCookies) {
    System.out.println(String.format("%s -> %s", loadedCookie.getName(), loadedCookie.getValue()));
}

Page Objects

Within your web app's UI there are areas that your tests interact with. A Page Object simply models these as objects within the test code. This reduces the amount of duplicated code and means that if the UI changes, the fix need only be applied in one place.

Implementation Notes

PageObjects can be thought of as facing in two directions simultaneously. Facing towards the developer of a test, they represent the servicesoffered by a particular page. Facing away from the developer, they should be the only thing that has a deep knowledge of the structure of the HTML of a page (or part of a page) It's simplest to think of the methods on a Page Object as offering the "services" that a page offers rather than exposing the details and mechanics of the page. As an example, think of the inbox of any web-based email system. Amongst the services that it offers are typically the ability to compose a new email, to choose to read a single email, and to list the subject lines of the emails in the inbox. How these are implemented shouldn't matter to the test.
Because we're encouraging the developer of a test to try and think about the services that they're interacting with rather than the implementation,PageObjects should seldom expose the underlying WebDriver instance. To facilitate this, methods on the PageObject should return otherPageObjects. This means that we can effectively model the user's journey through our application. It also means that should the way that pages relate to one another change (like when the login page asks the user to change their password the first time they log into a service, when it previously didn't do that) simply changing the appropriate method's signature will cause the tests to fail to compile. Put another way, we can tell which tests would fail without needing to run them when we change the relationship between pages and reflect this in the PageObjects.
One consequence of this approach is that it may be necessary to model (for example) both a successful and unsuccessful login, or a click could have a different result depending on the state of the app. When this happens, it is common to have multiple methods on the PageObject:
public class LoginPage {
    public HomePage loginAs(String username, String password) {
        // ... clever magic happens here
    }
    
    public LoginPage loginAsExpectingError(String username, String password) {
        //  ... failed login here, maybe because one or both of the username and password are wrong
    }
    
    public String getErrorMessage() {
        // So we can verify that the correct error is shown
    }
}
The code presented above shows an important point: the tests, not the PageObjects, should be responsible for making assertions about the state of a page. For example:
public void testMessagesAreReadOrUnread() {
    Inbox inbox = new Inbox(driver);
    inbox.assertMessageWithSubjectIsUnread("I like cheese");
    inbox.assertMessageWithSubjectIsNotUnread("I'm not fond of tofu");
}
could be re-written as:
public void testMessagesAreReadOrUnread() {
    Inbox inbox = new Inbox(driver);
    assertTrue(inbox.isMessageWithSubjectIsUnread("I like cheese"));
    assertFalse(inbox.isMessageWithSubjectIsUnread("I'm not fond of tofu"));
}
Of course, as with every guideline there are exceptions, and one that is commonly seen with PageObjects is to check that the WebDriver is on the correct page when we instantiate the PageObject. This is done in the example below.
Finally, a PageObject need not represent an entire page. It may represent a section that appears many times within a site or page, such as site navigation. The essential principle is that there is only one place in your test suite with knowledge of the structure of the HTML of a particular (part of a) page.

Summary

  • The public methods represent the services that the page offers
  • Try not to expose the internals of the page
  • Generally don't make assertions
  • Methods return other PageObjects
  • Need not represent an entire page
  • Different results for the same action are modelled as different methods

Example

public class LoginPage {
    private final WebDriver driver;

    public LoginPage(WebDriver driver) {
        this.driver = driver;

        // Check that we're on the right page.
        if (!"Login".equals(driver.getTitle())) {
            // Alternatively, we could navigate to the login page, perhaps logging out first
            throw new IllegalStateException("This is not the login page");
        }
    }

    // The login page contains several HTML elements that will be represented as WebElements.
    // The locators for these elements should only be defined once.
        By usernameLocator = By.id("username");
        By passwordLocator = By.id("passwd");
        By loginButtonLocator = By.id("login");

    // The login page allows the user to type their username into the username field
    public LoginPage typeUsername(String username) {
        // This is the only place that "knows" how to enter a username
        driver.findElement(usernameLocator).sendKeys(username);

        // Return the current page object as this action doesn't navigate to a page represented by another PageObject
        return this;    
    }

    // The login page allows the user to type their password into the password field
    public LoginPage typePassword(String password) {
        // This is the only place that "knows" how to enter a password
        driver.findElement(passwordLocator).sendKeys(password);

        // Return the current page object as this action doesn't navigate to a page represented by another PageObject
        return this;    
    }

    // The login page allows the user to submit the login form
    public HomePage submitLogin() {
        // This is the only place that submits the login form and expects the destination to be the home page.
        // A seperate method should be created for the instance of clicking login whilst expecting a login failure. 
        driver.findElement(loginButtonLocator).submit();

        // Return a new page object representing the destination. Should the login page ever
        // go somewhere else (for example, a legal disclaimer) then changing the method signature
        // for this method will mean that all tests that rely on this behaviour won't compile.
        return new HomePage(driver);    
    }

    // The login page allows the user to submit the login form knowing that an invalid username and / or password were entered
    public LoginPage submitLoginExpectingFailure() {
        // This is the only place that submits the login form and expects the destination to be the login page due to login failure.
        driver.findElement(loginButtonLocator).submit();

        // Return a new page object representing the destination. Should the user ever be navigated to the home page after submiting a login with credentials 
        // expected to fail login, the script will fail when it attempts to instantiate the LoginPage PageObject.
        return new LoginPage(driver);   
    }

    // Conceptually, the login page offers the user the service of being able to "log into"
    // the application using a user name and password. 
    public HomePage loginAs(String username, String password) {
        // The PageObject methods that enter username, password & submit login have already defined and should not be repeated here.
        typeUsername(username);
        typePassword(password);
        return submitLogin();
    }
}

Design Patterns and Development Strategies

Over time, projects tend to accumulate large numbers of tests. As the total number of tests increases, it becomes harder to make changes to the codebase --- a single "simple" change may cause numerous tests to fail, even though the application still works properly. Sometimes these problems are unavoidable, but when they do occur you want to be up and running again as quickly as possible. The following design patterns and strategies have been used before with WebDriver to help making tests easier to write and maintain. They may help you too.
  • DomainDrivenDesign: Express your tests in the language of the end-user of the app.
  • PageObjects: A simple abstraction of the UI of your web app.
  • LoadableComponent: Modeling PageObjects as components.
  • BotStyleTests: Using a command-based approach to automating tests, rather than the object-based approach that PageObjects encourage
  • AcceptanceTests: Use coarse-grained UI tests to help structure development work.
  • RegressionTests: Collect the actions of multiple AcceptanceTests into one place for ease of maintenance.
If your favourite pattern has been left out, please leave a comment on this page, and we'll try and include it. Also, please remember that these are just suggestions: in order to use WebDriver you don't need to follow these patterns and strategies, and it's likely that not all of them will be useful to you. Just use the ones that you like!

Locating Dynamic Elements

As was described earlier in the Types of Tests section, a dynamic element is a page element whose identifer varies with each instance of the page. For example,
<a class="button" id="adminHomeForm" onclick="return oamSubmitForm('adminHomeForm',
    'adminHomeForm:_ID38');" href="#">View Archived Allocation Events</a>
This HTML anchor tag defines a button with an ID attribute of “adminHomeForm”. It’s a fairly complex anchor tag when compared to most HTML tags, but it is still a static tag. The HTML will be the same each time this page is loaded in the browser. Its ID remains constant with all instances of this page. That is, when this page is displayed, this UI element will always have this Identifier. So, for your test script to click this button you simply need to use the following Selenium command.
click       adminHomeForm
Or, in Selenium 1.0

selenium.click("adminHomeForm");
Your application, however, may generate HTML dynamically where the identifier varies on different instances of the webpage. For instance, HTML for a dynamic page element might look like this.
<input type="checkbox" value="true" id="addForm:_ID74:_ID75:0:_ID79:0:checkBox"
    name="addForm:_ID74:_ID75:0:_ID79:0:checkBox"/>
This defines a checkbox. Its ID and name attributes (both addForm:_ID74:_ID75:0:_ID79:0:checkBox) are dynamically generated values. In this case, using a standard locator would look something like the following.
click       addForm:_ID74:_ID75:0:_ID79:0:checkBox
Or, again in Selenium-RC

selenium.click("addForm:_ID74:_ID75:0:_ID79:0:checkBox");
Given the dynamically generated Identifier, this approach would not work. The next time this page is loaded the Identifier will be a different value from the one used in the Selenium command and therefore, will not be found. The click operation will fail with an “element not found” error.
To correct this, a simple solution would be to just use an XPath locator rather than trying to use an ID locator. So, for the checkbox you can simply use
click       //input
Or, if it is not the first input element on the page (which it is likely not) try a more detailed XPath statement.
click       //input[3]
Or
click       //div/p[2]/input[3]
If however, you do need to use the ID to locate the element, a different solution is needed. You can capture this ID from the website before you use it in a Selenium command. It can be done like this.

String[] checkboxids  = selenium.getAllFields(); // Collect all input IDs on page.

for(String checkboxid:checkboxids) {
    if(checkboxid.contains("addForm")) {
        selenium.click(checkboxid);
    }
}
This approach will work if there is only one check box whose ID contains the text ‘addForm’.

Locating Ajax Elements

As was presented in the Types of Tests subsection above, a page element implemented with Ajax is an element that can be dynamically refreshed without having to refresh the entire page. The best way to locate and verify an Ajax element is to use the Selenium 2.0 WebDriver API. It was specifically designed to address testing of Ajax elements where Selenium 1 has some limitations.
In Selenium 2.0 you use the waitFor() method to wait for a page element to become available. The parameter is a By object which is how WebDriver implements locators. This is explained in detail in the WebDriver chapters.
To do this with Selenium 1.0 (Selenium-RC) a bit more coding is involved, but it isn’t difficult. The approach is to check for the element, if it’s not available wait for a predefined period and then again recheck it. This is then executed with a loop with a predetermined time-out terminating the loop if the element isn’t found.
Let’s consider a page which brings a link (link=ajaxLink) on click of a button on page (without refreshing the page). This could be handled by Selenium using a for loop.

// Loop initialization.
for (int second = 0;; second++) {

     // If loop reached 60 seconds then break the loop.
     if (second >= 60) break;

     // Search for element "link=ajaxLink" and if available then break loop.
     try { if (selenium.isElementPresent("link=ajaxLink")) break; } catch (Exception e) {}

     // Pause for 1 second.
     Thread.sleep(1000);

}
This certainly isn’t the only solution. Ajax is a common topic in the user forum and we recommend searching previous discussions to see what others have done.

Wrapping Selenium Calls

As with any programming, you will want to use utility functions to handle code that would otherwise be duplicated throughout your tests. One way to prevent this is to wrap frequently used selenium calls with functions or class methods of your own design. For example, many tests will frequently click on a page element and wait for page to load multiple times within a test.

selenium.click(elementLocator);
selenium.waitForPageToLoad(waitPeriod);
Instead of duplicating this code you could write a wrapper method that performs both functions.

/**
 * Clicks and Waits for page to load.
 *
 * param elementLocator
 * param waitPeriod
 */
public void clickAndWait(String elementLocator, String waitPeriod) {
        selenium.click(elementLocator);
        selenium.waitForPageToLoad(waitPeriod);
}

‘Safe Operations’ for Element Presence

Another common usage of wrapping Selenium methods is to check for presence of an element on a page before carrying out some operation. This is sometimes called a ‘safe operation’. For instance, the following method could be used to implement a safe operation that depends on an expected element being present.

/**
 * Selenum-RC -- Clicks on an element only if it is available on a page.
 *
 * param elementLocator
 */
public void safeClick(String elementLocator) {
        if(selenium.isElementPresent(elementLocator)) {
                selenium.click(elementLocator);
        } else {
                // Using the TestNG API for logging
                Reporter.log("Element: " + elementLocator + ", is not available on a page - "
                                +selenium.getLocation());
        }
}
This example uses the Selenium 1 API but Selenium 2 also supports this.

/**
 * Selenium-WebDriver -- Clicks on an element only if it is available on a page.
 *
 * param elementLocator
 */
public void safeClick(String elementLocator) {
        WebElement webElement = getDriver().findElement(By.XXXX(elementLocator));
        if(webElement != null) {
                selenium.click(webElement);
        } else {
                // Using the TestNG API for logging
                Reporter.log("Element: " + elementLocator + ", is not available on a page - "
                                + getDriver().getUrl());
        }
}
In this second example ‘XXXX’ is simply a placeholder for one of the multiple location methods that can be called here.
Using safe methods is up to the test developer’s discretion. Hence, if test execution is to be continued, even in the wake of missing elements on the page, then safe methods could be used, while posting a message to a log about the missing element. This, essentially, implements a ‘verify’ with a reporting mechanism as opposed to an abortive assert. But if an element must be available on a page in order to be able to carry out further operations (i.e. login button on home page of a portal) then this safe method technique should not be used.

UI Mapping

A UI Map is a mechanism that stores all the locators for a test suite in one place for easy modification when identifiers or paths to UI elements change in the AUT. The test script then uses the UI Map for locating the elements to be tested. Basically, a UI map is a repository of test script objects that correspond to UI elements of the application being tested.
What makes a UI map helpful? Its primary purpose is making test script management much easier. When a locator needs to be edited, there is a central location for easily finding that object, rather than having to search through test script code. Also, it allows changing the Identifier in a single place, rather than having to make the change in multiple places within a test script, or for that matter, in multiple test scripts.
To summarize, a UI Map has two significant advantages
  • Using a centralized location for UI objects instead of having them scattered throughout the script. This makes script maintenance more efficient.
  • Cryptic HTML Identifiers and names can be given more human-readable names improving the readability of test scripts.
Consider the following, difficult to understand, example (in Java).

public void testNew() throws Exception {
             selenium.open("http://www.test.com");
             selenium.type("loginForm:tbUsername", "xxxxxxxx");
             selenium.click("loginForm:btnLogin");
             selenium.click("adminHomeForm:_activitynew");
             selenium.waitForPageToLoad("30000");
             selenium.click("addEditEventForm:_IDcancel");
             selenium.waitForPageToLoad("30000");
             selenium.click("adminHomeForm:_activityold");
             selenium.waitForPageToLoad("30000");
}
This script would be hard to follow for anyone not familiar with the AUT’s page source. Even regular users of the application might have difficulties in understanding what this script does. A better script could be:

public void testNew() throws Exception {
             selenium.open("http://www.test.com");
             selenium.type(admin.username, "xxxxxxxx");
             selenium.click(admin.loginbutton);
             selenium.click(admin.events.createnewevent);
             selenium.waitForPageToLoad("30000");
             selenium.click(admin.events.cancel);
             selenium.waitForPageToLoad("30000");
             selenium.click(admin.events.viewoldevents);
             selenium.waitForPageToLoad("30000");
}
Now, using some comments and whitespace along with the UI Map identifiers makes a very readable script.

public void testNew() throws Exception {

             // Open app url.
             selenium.open("http://www.test.com");

             // Provide admin username.
             selenium.type(admin.username, "xxxxxxxx");

             // Click on Login button.
             selenium.click(admin.loginbutton);

             // Click on Create New Event button.
             selenium.click(admin.events.createnewevent);
             selenium.waitForPageToLoad("30000");

             // Click on Cancel button.
             selenium.click(admin.events.cancel);
             selenium.waitForPageToLoad("30000");

             // Click on View Old Events button.
             selenium.click(admin.events.viewoldevents);
             selenium.waitForPageToLoad("30000");
}
There are various ways a UI Map can be implemented. One could create a class or struct which only stores public String variables each storing a locator. Alternatively, a text file storing key value pairs could be used. In Java, a properties file containing key/value pairs is probably the best method.
Consider a properties file prop.properties which assigns as ‘aliases’ reader-friendly identifiers for UI elements from the previous example.
admin.username = loginForm:tbUsername
admin.loginbutton = loginForm:btnLogin
admin.events.createnewevent = adminHomeForm:_activitynew
admin.events.cancel = addEditEventForm:_IDcancel
admin.events.viewoldevents = adminHomeForm:_activityold
The locators will still refer to HTML objects, but we have introduced a layer of abstraction between the test script and the UI elements. Values are read from the properties file and used in the Test Class to implement the UI Map. For more on Java properties files refer to the following link.

Page Object Design Pattern

Page Object is a Design Pattern which has become popular in test automation for enhancing test maintenance and reducing code duplication. A page object is an object-oriented class that serves as an interface to a page of your AUT. The tests then use the methods of this page object class whenever they need to interact with the UI of that page. The benefit is that if the UI changes for the page, the tests themselves don’t need to change, only the code within the page object needs to change. Subsequently all changes to support that new UI are located in one place.
The Page Object Design Pattern provides the following advantages
1. There is a clean separation between test code and page specific code such as locators (or their use if you’re using a UI Map) and layout.
2. There is a single repository for the services or operations offered by the page rather than having these services scattered throughout the tests.
In both cases this allows any modifications required due to UI changes to all be made in one place. Useful information on this technique can be found on numerous blogs as this ‘test design pattern’ is becoming widely used. We encourage the reader who wishes to know more to search the internet for blogs on this subject. Many have written on this design pattern and can provide useful tips beyond the scope of this user guide. To get you started, though, we’ll illustrate page objects with a simple example.
First, consider an example, typical of test automation, that does not use a page object.

/***
 * Tests login feature
 */
public class Login {

        public void testLogin() {
                selenium.type("inputBox", "testUser");
                selenium.type("password", "my supersecret password");
                selenium.click("sign-in");
                selenium.waitForPageToLoad("PageWaitPeriod");
                Assert.assertTrue(selenium.isElementPresent("compose button"),
                                "Login was unsuccessful");
        }
}
There are two problems with this approach.
  1. There is no separation between the test method and the AUT’s locators (IDs in this example); both are intertwined in a single method. If the AUT’s UI changes its identifiers, layout, or how a login is input and processed, the test itself must change.
  2. The ID-locators would be spread in multiple tests, in all tests that had to use this login page.
Applying the page object techniques, this example could be rewritten like this in the following example of a page object for a Sign-in page.

/**
 * Page Object encapsulates the Sign-in page.
 */
public class SignInPage {

        private Selenium selenium;

        public SignInPage(Selenium selenium) {
                this.selenium = selenium;
                if(!selenium.getTitle().equals("Sign in page")) {
                        throw new IllegalStateException("This is not sign in page, current page is: "
                                        +selenium.getLocation());
                }
        }

        /**
         * Login as valid user
         *
         * @param userName
         * @param password
         * @return HomePage object
         */
        public HomePage loginValidUser(String userName, String password) {
                selenium.type("usernamefield", userName);
                selenium.type("passwordfield", password);
                selenium.click("sign-in");
                selenium.waitForPageToLoad("waitPeriod");

                return new HomePage(selenium);
        }
}
and page object for a Home page could look like this.

/**
 * Page Object encapsulates the Home Page
 */
public class HomePage {

        private Selenium selenium;

        public HomePage(Selenium selenium) {
                if (!selenium.getTitle().equals("Home Page of logged in user")) {
                        throw new IllegalStateException("This is not Home Page of logged in user, current page" +
                                        "is: " +selenium.getLocation());
                }
        }

        public HomePage manageProfile() {
                // Page encapsulation to manage profile functionality
                return new HomePage(selenium);
        }

        /*More methods offering the services represented by Home Page
        of Logged User. These methods in turn might return more Page Objects
        for example click on Compose mail button could return ComposeMail class object*/

}
So now, the login test would use these two page objects as follows.

/***
 * Tests login feature
 */
public class TestLogin {

        public void testLogin() {
                SignInPage signInPage = new SignInPage(selenium);
                HomePage homePage = signInPage.loginValidUser("userName", "password");
                Assert.assertTrue(selenium.isElementPresent("compose button"),
                                "Login was unsuccessful");
        }
}
There is a lot of flexibility in how the page objects may be designed, but there are a few basic rules for getting the desired maintainability of your test code.
Page objects themselves should never make verifications or assertions. This is part of your test and should always be within the test’s code, never in an page object. The page object will contain the representation of the page, and the services the page provides via methods but no code related to what is being tested should be within the page object.
There is one, single, verification which can, and should, be within the page object and that is to verify that the page, and possibly critical elements on the page, were loaded correctly. This verification should be done while instantiating the page object. In the examples above, both the SignInPage and HomePage constructors check that the expected page is available and ready for requests from the test.
A page object does not necessarily need to represent an entire page. The Page Object design pattern could be used to represent components on a page. If a page in the AUT has multiple components, it may improve maintainability if there is a separate page object for each component.
There are other design patterns that also may be used in testing. Some use a Page Factory for instantiating their page objects. Discussing all of these is beyond the scope of this user guide. Here, we merely want to introduce the concepts to make the reader aware of some of the things that can be done. As was mentioned earlier, many have blogged on this topic and we encourage the reader to search for blogs on these topics.

Data Driven Testing

Data Driven Testing refers to using the same test (or tests) multiple times with varying data. These data sets are often from external files i.e. .csv file, text file, or perhaps loaded from a database. Data driven testing is a commonly used test automation technique used to validate an application against many varying inputs. When the test is designed for varying data, the input data can expand, essentially creating additional tests, without requiring changes to the test code.
In Python:
The Python script above opens a text file. This file contains a different search string on each line. The code then saves this in an array of strings, and iterates over the array doing a search and assert on each string.
This is a very basic example, but the idea is to show that running a test with varying data can be done easily with a programming or scripting language. Additionally, this is a well-known topic among test automation professionals including those who don’t use Selenium so searching the internet on “data-driven testing” should reveal many blogs on this topic.

Database Validation

Another common type of testing is to compare data in the UI against the data actually stored in the AUT’s database. Since you can also do database queries from a programming language, assuming you have database support functions, you can use them to retrieve data and then use the data to verify what’s displayed by the AUT is correct.
Consider the example of a registered email address to be retrieved from a database and then later compared against the UI. An example of establishing a DB connection and retrieving data from the DB could look like this.
In Java:

// Load Microsoft SQL Server JDBC driver.
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");

// Prepare connection url.
String url = "jdbc:sqlserver://192.168.1.180:1433;DatabaseName=TEST_DB";

// Get connection to DB.
public static Connection con =
DriverManager.getConnection(url, "username", "password");

// Create statement object which would be used in writing DDL and DML
// SQL statement.
public static Statement stmt = con.createStatement();

// Send SQL SELECT statements to the database via the Statement.executeQuery
// method which returns the requested information as rows of data in a
// ResultSet object.

ResultSet result =  stmt.executeQuery
("select top 1 email_address from user_register_table");

// Move cursor from default position to first row of result set.
result.next();

// Fetch value of "email_address" from "result" object.
String emailaddress = result.getString("email_address");

// Use the emailAddress value to login to application.
driver.findElement(By.id, "userID").sendKeys(emailaddress);
driver.findElement(By.id, "password").sendKeys(secretPassword);
driver.findElement(By.id, "loginButton").click();
WebElement element = driver.findElement(By.xpath, "//*[contains(.,'Welcome back ')]");
Assert.assertTrue(element.getText().contains(emailaddress), "Unable to log in for user" + emailaddress)
This is a simple Java example of data retrieval from a database.

Selenium-Grid

Note: We are currently working on this chapter. Presently we have introductory info here for people completely new to Selnium-Grid. Over the next few months we hope to provide useful examples and illustrations to thoroughly explain how to use Selenium-Grid.

Quick Start

If you’re already experienced in Selenium test automation you may simply need a quick-start to get up and running. This chapter has much information geared to many skill levels, but may be too much if you’re looking for just a quick reference to quickly try things out. For a quick-start, refer to the Selenium-Grid articles in the Selenium Wiki.

What is Selenium-Grid?

Selenium-Grid allows you run your tests on different machines against different browsers in parallel. That is, running multiple tests at the same time against different machines running different browsers and operating systems. Essentially, Selenium-Grid support distributed test execution. It allows for running your tests in a distributed test execution environment.

When to Use It

Generally speaking, there’s two reasons why you might want to use Selenium-Grid.
  • To run your tests against multiple browsers, multiple versions of browser, and browsers running on different operating systems.
  • To reduce the time it takes for the test suite to complete a test pass.
Selenium-Grid is used to speed up the execution of a test pass by using multiple machines to run tests in parallel. For example, if you have a suite of 100 tests, but you set up Selenium-Grid to support 4 different machines (VMs or separate physical machines) to run those tests, your test suite will complete in (roughly) one-fourth the time as it would if you ran your tests sequentially on a single machine. For large test suites, and long-running test suite such as those performing large amounts of data-validation, this can be a significant time-saver. Some test suites can take hours to run. Another reason to boost the time spent running the suite is to shorten the turnaround time for test results after developers check-in code for the AUT. Increasingly software teams practicing Agile software development want test feedback as immediately as possible as opposed to wait overnight for an overnight test pass.
Selenium-Grid is also used to support running tests against multiple runtime environments, specifically, against different browsers at the same time. For example, a ‘grid’ of virtual machines can be setup with each supporting a different browser that the application to be tested must support. So, machine 1 has Internet Explorer 8, machine 2, Internet Explorer 9, machine 3 the latest Chrome, and machine 4 the latest Firefox. When the test suite is run, Selenium-Grid receives each test-browser combination and assigns each test to run against its required browser.
In addition, one can have a grid of all the same browser, type and version. For instance, one could have a grid of 4 machines each running 3 instances of Firefox 12, allowing for a ‘server-farm’ (in a sense) of available Firefox instances. When the suite runs, each test is passed to Selenium-Grid which assigns the test to the next available Firefox instance. In this manner one gets test pass where conceivably 12 tests are all running at the same time in parallel, significantly reducing the time required to complete a test pass.
Selenium-Grid is very flexible. These two examples can be combined to allow multiple instances of each browser type and version. A configuration such as this would provide both, parallel execution for fast test pass completion and support for multiple browser types and versions simultaneously.

Selenium-Grid 2.0

Selenium-Grid 2.0 is the latest release as of the writing of this document (5/26/2012). It is quite different from version 1 of Selenium-Grid. In 2.0 Selenium-Grid was merged with the Selenium-RC server. Now, you only need to download a single .jar file to get the remote Selenium-RC-Server and Selenium-Grid all in one package.

Selenium-Grid 1.0

Version 1 was the first general release of Selenium-Grid. If you are new to Selenium-Grid you should use version 2. It’s been updated and has new features, and supports Selenium-WebDriver. Legacy test systems may still be using version 1 however. Information on Selenium-Grid version 1 may be found at the Selenium-Grid website.

How Selenium-Grid Works–With a Hub and Nodes

A grid consists of a single hub, and one or more nodes. Both are started using the selenium-server.jar executable. We’ve listed some examples in the following sections of this chapter.
The hub receives a test to be executed along with information on which browser and ‘platform’ (i.e. WINDOWS, LINUX, etc) where the test should be run. It ‘knows’ the configuration of each node that has been ‘registered’ to the hub. Using this information it selects an available node that has the requested browser-platform combination. Once a node has been selected, Selenium commands initiated by the test are sent to the hub, which passes them to the node assigned to that test. The node runs the browser, and executes the Selenium commands within that browser against the application under test.
diagram illustrates this. Refer to the second diagram on this page (the first one is illustrating Selenium-RC). The second diagram was for Selenium-Grid 1, however it still applies and is a good illustration of what we’re describing here. The only difference is one of terminology. Replace the term ‘Selenium Remote Control’ with ‘Selenium-Grid node’ the diagram will match our description for Selenium-Grid 2.

Installation

Installation is simple. Download the Selenium-Server jar file from the SeleniumHq website’s download page. You want the link under the section “Selenium-Server (formerly Selenium-RC)”.

CSS

Cascading Style Sheet (CSS) class attributes can be used in a number of ways for element location.
First, you're able to directly use the class attribute itself as a locator. Secondly, you can use JQuery-style selectors to find your elements.
CSS class attribute values don't have to be unique. They rarely are since they're intended to provide reusability of style definitions. That said, sometimes they're unique1 enough to be used for the particular test you're building.
The Input field we've been looking at above doesn't contain a class attribute, so we'll use the Login title of the modal that pops up for an example:
CSS locators are nearly as fast as IDs when resolving in all browsers, so you don't have to worry about speed impacts when rolling along with them.

CSS Selectors

CSS selectors enable you locate an element based on JQuery-like selector patterns. These selectors create a unique locator by piecing together values, element types, locations, and similar other items.
Below is a snippet showing the same C# code we used earlier for demonstrating IDs, but this time using CSS selectors:
browser.FindElement(
    By.CssSelector("a[id^='login']"))
    .Click();
browser.FindElement(
    By.CssSelector("label[for='username']+input"))
    .SendKeys("testuser");
browser.FindElement(
    By.CssSelector("label[for='password']+input"))
    .SendKeys("abc123");
browser.FindElement(
    By.CssSelector("input[value='Log in']"))
    .Click();
CSS selectors are fast to resolve, very flexible, and are fairly understandable to read. Unfortunately CSS selectors can only walk down the DOM; they can't be used to move from one part of the DOM up and over to another area.
For that you'll need our next locator type: XPath.

XPath

XPath may be one of the most abused, misunderstood, and outright hated technologies created in modern times. Perhaps ever. It contends with SharePoint and bad opera for the top place on my personal list of all things hated.
XPath is an extraordinarily powerful tool that enables you to inspect values of elements; navigate up, across, and down the DOM; and to create extremely powerful locator strategies.
It can also be extremely brittle and high-maintenance if poorly used. Additionally, XPath is the slowest locator strategy for all browsers, especially Internet Explorer.
Overly brittle XPath locators are those which rely on starting too high in the DOM, or which rely on risky indexing. Returning to our username input field, a poorly formed XPath might look like this:
/html/body/div[3]/div[2]/form/div[2]/input
Two main problems impact this XPath: it starts from the document's root HTML element, and it uses fixed indexes to select which specific element from a group to use, e.g. div[3]/div[2]. This means nearly any change to the document's structure will break the locator and cause the test to fail.
Instead of that messy XPath, let's start from the input field we need, and look up and around the DOM for something unique that's close by. The text label with Username will serve well for us! From there we can move up one level, over to the sibling input label and back down. We can now use a much simpler, much more flexible XPath of:
//label[text()='Username']/../input
This locator also shows XPath's ability to walk up, over, and down the DOM to create complex locators.
XPath is a tool. Used with careful thought it's a great tool. Used with reckless abandon it's a recipe for lots of pain.

Text Content

There are cases where you'll want to avoid fixed locators all together and instead think of querying objects on the page to retrieve information you need. I find myself doing this regularly when working with table or grid tests.
If you're building a test that checks if you can properly retrieve data from a grid row, then you don't want that test reliant on the specific order or number of the row in the grid. In this case it makes a lot of sense to avoid locators, and instead get rows from the table that match a particular criteria.
Using the table below, imagine a test whose purpose is to verify that clicking the Edit link on Jayne Cobb's row pulls up an editing grid with the proper values pre-populated. I wouldn't want this test to be dependent on the location of Jayne Cobb in the grid, nor would I want the test to fail if the Edit link changes columns.
There are a number of approaches for this. I could use an XPath query to return a collection of the table's rows and iterate through that. I could use a different XPath query to return just the row I'm looking for. I could also get all the rows in the table and iterate through them to find the particular row I want. Text within an element can be used for element location; however, as with XPath you'll need to be extremely careful how you go about using this strategy. You'll also need to understand the difference between Text Content and Inner Text, and you'll need to understand how your automation toolset supports this.
Text Content is the text, including whitespace, of the element you're looking at. Only that element, not its children.
Inner Text is the text of the current node plus its children. There is no whitespace between the text of the elements, but text within each element is properly shown. Inner Text is extremely useful when you're doing something like inspecting a menu for particular values. A quick "inner text contains 'foo'" may be just the trick you need in that case.
The trick about Inner Text, or Text Content, is that it's implemented differently depending on your automation driver, framework2, or tool. For example, WebDriver doesn't actually support grabbing text or inner text for locators. Instead, you've got to get a reference to the element and check its Text property.
This makes finding specific row elements in a table a bit dramatic—you need to iterate through the rows and check each one for the text you're looking for.
IWebElement table = browser.FindElement(By.Id(PeopleGrid));
IWebElement targetRow = null;
IList rows = table.FindElements(By.TagName("tr"));
foreach (var row in rows)
{
    if (row.Text.Contains("Cobb"))
    {
        targetRow = row;
    }
? }
Frankly, you'd be much better served in this case by using an XPath and its Contains function:
//table[@id='PeopleGrid']//tr[contains(.,'Cobb')]
Some other drivers like Telerik Testing Framework, or tools like QuickTest Professional or Telerik Test Studio allow you to use TextContent or InnerText right in their locators:

Other Attributes

Other attributes may be handy when you've nothing else to fall back on. Image 'src' attributes, link targets, or 'name' attributes may all be good choices for locators.
None of these attribute types are mandated to be unique, but again, avoid thinking about perfect locators and look for a strategy that meets the need at hand.