Creating an object map for Selenium tests

So far, we have seen how the Selenium WebDriver API needs locator information to find the elements on the page. When a large suite of tests is created, a lot of locator information is duplicated in the test code. It becomes difficult to manage locator details when the number of tests increases. If any changes happen in the element locator, we need to find all the tests that use this locator and update these tests. This becomes a maintenance nightmare.

One way to overcome this problem is to use page objects and create a repository of pages as reusable classes.

There is another way to overcome this problem—by using an object map. An object or 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 GUI elements change in the application under test. The test script then uses the object map to locate the elements to be tested.

Object maps help in 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 the 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. The object map files can also be version-controlled.

In this recipe, we will implement the ObjectMap class to maintain locator details obtained from the tests.

Getting ready

Set up a new Java project for the ObjectMap class. This class will be used by Selenium tests as an extension to read the ObjectMap file.

How to do it...

Let's implement an object map to store the locators used in a test with the following steps:

  1. We will create a properties file named objectmap.properties. We will add the locators in a key/value pair. The part before the equal-to sign (=) will be the key or the logical name of the element, and the part after will be the locator details, in the following format:
    [logical_name]=[locator_type]>[locator_value]

    The following code is an example of the object map for the BMI calculator page:

    height_field=name>heightCMS
    weight_field=id>weightKg
    calculate_button=id>Calculate
    bmi_field=id>bmi
  2. Implement the ObjectMap class to read the property file and provide the locator information to the test:
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.util.Properties;
    
    public class ObjectMap {
    
      Properties properties;
    
      public ObjectMap(String mapFile)
      {
        properties = new Properties();
        try {
          FileInputStream in = new FileInputStream(mapFile);
          properties.load(in);
          in.close();
        }catch (IOException e) {
          System.out.println(e.getMessage());
        }
    
      }
    
    }
  3. Add a method to the ObjectMap class which will read the locator details from the properties file and create and return the locator using the By class, as shown in following code:
    public By getLocator(String logicalElementName) throws Exception
    {
      //Read value using the logical name as Key
      String locator = properties.getProperty(logicalElementName);
    
      //Split the value which contains locator type and locator value
      String locatorType = locator.split(">")[0];
      String locatorValue = locator.split(">")[1];
    
      //Return a instance of By class based on type of locator
      if(locatorType.toLowerCase().equals("id"))
        return By.id(locatorValue);
      else if(locatorType.toLowerCase().equals("name"))
        return By.name(locatorValue);
      else if((locatorType.toLowerCase().equals("classname")) || (locatorType.toLowerCase().equals("class")))
        return By.className(locatorValue);
      else if((locatorType.toLowerCase().equals("tagname")) || (locatorType.toLowerCase().equals("tag")))
        return By.className(locatorValue);
      else if((locatorType.toLowerCase().equals("linktext")) || (locatorType.toLowerCase().equals("link")))
        return By.linkText(locatorValue);
      else if(locatorType.toLowerCase().equals("partiallinktext"))
        return By.partialLinkText(locatorValue);
      else if((locatorType.toLowerCase().equals("cssselector")) || (locatorType.toLowerCase().equals("css")))
        return By.cssSelector(locatorValue);
      else if(locatorType.toLowerCase().equals("xpath"))
        return By.xpath(locatorValue);
      else
      throw new Exception("Locator type '" + locatorType + "' not   defined!!");
    }
  4. Finally, create a test that uses the property file to store the locator information, using the following code:
    package com.secookbook.examples.chapter09;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.firefox.FirefoxDriver;
    import org.openqa.selenium.WebElement;
    
    import org.junit.*;
    import static org.junit.Assert.assertEquals;
    
    public class ObjectMapTest {
    
      private WebDriver driver;
      private ObjectMap map;
      @Before
      public void setUp() throws Exception {
        // Create a new instance of the Firefox driver
        driver = new FirefoxDriver();
        driver.get("http:// cookbook.seleniumacademy.com/bmicalculator.html");
      }
    
      @Test
      public void testBmiCalculator() {
        // Get the Object Map File
        map = new ObjectMap("src/test/resources/objectmap/objectmap.properties");
    
        // Get the Height element
        WebElement height = driver.findElement(map.getLocator("height_field"));
        ;
        height.sendKeys("181");
    
        // Get the Weight element
        WebElement weight = driver.findElement(map.getLocator("weight_field"));
        weight.sendKeys("80");
    
        // Click on the Calculate button
        WebElement calculateButton = driver.findElement(map.getLocator("calculate_button"));
        calculateButton.click();
    
        // Verify the Bmi
        WebElement bmi = driver.findElement(map.getLocator("bmi_field"));
        assertEquals("24.4", bmi.getAttribute("value"));
      }
    
      @After
      public void tearDown() throws Exception {
        // Close the browser
        driver.quit();
      }
    }

How it works...

First, we created a Java properties file with the key/value pair, storing a logical name for an element and locator value. The properties files are flat text files, and the java.util.Properties namespace provides the Properties class to access a property file:

properties = new Properties();

By passing a logical name or key to the getProperty() method of the Properties class, we can retrieve a value from the pair.

The getLocator() method uses the value returned by the getProperty() method and returns a matching By locator method, along with the value, to the test.

In the test, we created an instance of an object map and then passed the location of the property file, as shown in the following code:

map = new ObjectMap("src/test/resources/objectmap/objectmap.properties");

We passed the locator value to the findElement() method by passing the logical name or key of the element to the getLocator() method of the ObjectMap class, as follows:

WebElement height = driver.findElement(map.getLocator("height_field"));

We can have a single object map file to store all the locators and can use the same locators in multiple tests.

There's more…

Object maps can also be created in XML files. The following code is an example of an XML-based object map:

<elements>
  <element name="HeightField" locator_type="name" locator_value="heightCMS"/>
  <element name="WeightField" locator_type="id" locator_value="weightKg"/>
  <element name="CalculateButton" locator_type="xpath" locator_value="//input[@value='Calculate']"/>
  <element name="BmiField" locator_type="id" locator_value="bmi"/>
  <element name="BmiCategoryField" locator_type="css" locator_value="#bmi_category"/>
</elements>

The following code is the C# implementation of the getLocator() method:

public By GetLocator(string locatorName)
{
  var element = from elements in _root.Elements("element")
          where elements.Attributes("name").First().Value == locatorName
          select elements;
  try
  {
    string locatorType = element.Attributes("locator_type").First().Value.ToString();
    string locatorValue = element.Attributes("locator_value").First().Value.ToString();

    switch (locatorType.ToLower())
    {
      case "id":
        return By.Id(locatorValue);
      case "name":
        return By.Name(locatorValue);
      case "classname":
        return By.ClassName(locatorValue);
      case "linktext":
        return By.LinkText(locatorValue);
      case "partiallinktext":
        return By.PartialLinkText(locatorValue);
      case "css":
        return By.CssSelector(locatorValue);
      case "xpath":
        return By.XPath(locatorValue);
      case "tagname":
        return By.TagName(locatorValue);
      default:
        throw new Exception("Locator Type '" + locatorType + "' not supported!!");
    }
  }
  catch (Exception)
  {
    throw new Exception("Failed to generate locator for '" + locatorName + "'");
  }
}

A similar approach can be taken with other Selenium WebDriver language bindings, such as Java, Python, or Ruby.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.43.26