Building and using an Object Repository in Selenium Webdriver

One of the main burdens of automated GUI test script maintainability is the amount of maintenance needed when object properties change within the application under test. A very common way of minimizing the time it takes to update your automated test scripts is the use of a central object repository (or object map as it’s also referred to sometimes). A basic object repository can be implemented as a collection of key-value pairs, with the key being a logical name identifying the object and the value containing unique objects properties used to identify the object on a screen.

Selenium Webdriver offers no object repository implementation by default. However, implementing and using a basic object repository is pretty straightforward. In this article, I will show you how to do it and how to lighten the burden of test script maintenance in this way.

Note that all code samples below are written in Java. However, the object repository concept as explained here can be used with your language of choice just as easily.

Creating the object repository
First, we are going to create a basic object repository and fill it with some objects that we will use in our test script. In this article, I am going to model a very basic scenario: go to the Bing search engine, search for a particular search query and determine the number of search results returned by Bing. To execute this scenario, our script needs to manipulate three screen objects:

  • The textbox where the search string is typed
  • The search button to be clicked in order to submit the search query
  • The text field that displays the number of search results

Our object map will a simple .properties text file that we add to our Selenium project:
Our object mapThe key for each object, for example bing.homepage.textbox, is a logical name for the object that we will use in our script. The corresponding value consists of two parts: the attribute type used for uniquely identifying the object on screen and the corresponding attribute value. For example, the aforementioned text box is uniquely identified by its id attribute, which has the value sb_form_q.

Retrieving objects from the object repository
To retrieve objects from our newly created object map, we will define an ObjectMap with a constructor taking a single argument, which is the path to the .properties file:

public class ObjectMap {
	Properties prop;
	public ObjectMap (String strPath) {
		prop = new Properties();
		try {
			FileInputStream fis = new FileInputStream(strPath);
		}catch (IOException e) {

The class contains a single method getLocator, which returns a By object that is used by the Selenium browser driver object (such as a HtmlUnitDriver or a FirefoxDriver):

public By getLocator(String strElement) throws Exception {
		// retrieve the specified object from the object list
		String locator = prop.getProperty(strElement);
		// extract the locator type and value from the object
		String locatorType = locator.split(":")[0];
		String locatorValue = locator.split(":")[1];
		// for testing and debugging purposes
		System.out.println("Retrieving object of type '" + locatorType + "' and value '" + locatorValue + "' from the object map");
		// return a instance of the By class based on the type of the locator
		// this By can be used by the browser object in the actual test
		else if(locatorType.toLowerCase().equals("name"))
		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);
			throw new Exception("Unknown locator type '" + locatorType + "'");

As you can see, objects can be identified using a number of different properties, including object IDs, CSS selectors and XPath expressions.

Using objects in your test script
Now that we can retrieve objects from our object map, we can use these in our scripts to execute the desired scenario:

public static void main (String args[]) {

		// Create a new instance of the object map
		ObjectMap objMap = new ObjectMap("");

		// Start a browser driver and navigate to Google
		WebDriver driver = new HtmlUnitDriver();

        // Execute our test
        try {
        	// Retrieve search text box from object map and type search query
        	WebElement element = driver.findElement(objMap.getLocator("bing.homepage.textbox"));
			element.sendKeys("Alfa Romeo");
			// Retrieve search button from object map and click it
			element = driver.findElement(objMap.getLocator("bing.homepage.searchbutton"));;
			// Retrieve number of search results using results object from object map
			element = driver.findElement(objMap.getLocator("bing.resultspage.results"));
			System.out.println("Search result string: " + element.getText());
			// Verify page title
			Assert.assertEquals(driver.getTitle(), "Alfa Romeo - Bing");
		} catch (Exception e) {
			System.out.println("Error during test execution:\n" + e.toString());

You can see from this code sample that using an object from the object map in your test is as easy as referring to its logical name (i.e., the key in our object map).

Object repository maintenance
With this straightforward mechanism we have been able to vastly reduce the amount of time needed for script maintenance in case object properties change. All it takes is an update of the appropriate entries in the object map and we’re good to go and run our tests again.

Thanks to Selenium Master for explaining this concept clearly for me to apply.

An example Eclipse project using the pattern described above can be downloaded here.

94 thoughts on “Building and using an Object Repository in Selenium Webdriver

    • Hi Phil,

      I’ve updated this post with a download link for the Eclipse project. If you’d like me to include similar samples for other posts, please let me know.

  1. Yeah, that would be awesome! By the way, this download appears to be the project from your Page Object Pattern post….

    • Whoops..

      Updated once again, this time using the right project. I’ve moved the other link to the correct post, thank you for noticing!

      I’ll add the other samples to the correct posts in the coming week, thanks for the suggestion.

  2. This is turning out to be really handy. And, the project download is a good teaching tool and time-saver on my end.

    I’m wondering if you’ve used LoadableComponent and PageFactory…really helpful classes.

    • Glad to hear it is turning out to be valuable for you, Phil.

      I’ve not used those classes before (though I do know PageFactory) but I’m surely going to look into them a bit more now that you’ve recommended them. Cheers for that.

  3. I used your code. It works fine for id,linkText,class etc. But for cssSelector, It is returning By.Selector. Ideally it should return me By.cssSelector.

    Becoz of this, I ma unable to proceed. Please help

  4. Just what I was looking for! Useful information, clear steps and the sample download saves a lot of trouble 🙂
    Thanks Bas…

  5. Hi,
    Thank you for this information…
    I need some information about .properties file. is it common for application or it is different for each page.

    Thank you

    • Hi Savita,

      for smaller applications a single file is enough. When your application under test is large and your .properties file grows larger, you might consider modularizing it to keep it readable.

      Hope that helps.

    • Hi Sandeep,

      an Object Repository like this should be equally easy to use if you’re using the Page Object Model pattern. However, I think it’s a little less useful in that situation as you already optimize the number of times a reference to an object on a page is made. If you’re using POM and you’re still referencing the same button, link or whatever in many methods, then using an Object Repository might still be handy.

      I’d have to look deeper into the combination of a PageFactory and an Object Repository, but as objects in the PageFactory are initialized differently I don’t think the two can be combined as easily..

  6. I have a unique application where there are a lot of controls but they can easily be classified by type (single-select, freetext), so I create the selectors for it dynamically. I just use a keyword to match the element name, and list what of control it should be, and then I have a class that is able to interact with different controls… such as with single selects, it can select from a drop down. Our application has custom dropdowns, etc and the typical webdriver stuff doesn’t work. So I guess I’m saying that this works for certain scenarios, but not if your app would need like thousands of selectors. Then you gotta get creative. This would be a good option for smaller, less complex apps.

    • Hi Anna,

      thanks for sharing your insights. I wholeheartedly agree with what you said. Using an object repository is just one approach to object identification and administration, and one that is more suitable for those applications that do not have a lot of objects to interact with. I can see it getting messy when you have a couple of hundred of objects..

      I only recently learned about using the PageFactory approach myself and will probably write something about it in a future post. This is another approach to object identification, and one you might be familiar with already. It makes object identification manageable as well, even though I can see problems for dynamic pages that have a lot of objects in this approach too.

      Your solution sounds pretty creative and well suited to your situation as far as I can judge from your explanation. Out of curiosity, what type of selectors do you use? XPath or CSS?

  7. Hi Bas,
    Let’s consider an object repository as a row of books in a each book points to an element in the website we need to be in future if there happens to be a change in the website suppose an element is added or deleted or gets changed we can manipulate it in the object repository.Is this the idea?
    otherwise please explain.

  8. Hi Bas,
    I downloaded your script which contains three java, and two object Repository-objectmap.paroperties and how does this work?which file to run first?The file containing Main() function?

    • Yes, that’s in The other classes are helper classes. I forgot to use appropriate package definitions there I think, my bad..

      • Hi Bas,
        I found a video that contains the Page Object design pattern in combination with a PageFactory that you said here i guess.
        Check this video-

        • I think if i follow the pattern shown in the video that is separating objects from tests and write the code plus if i use ExtentReport to generate the report,maybe i can automate a full website right?Is the right approach to build framework?Does this avoid redundancy,duplication and all?

  9. In the text file,the attribute you used to locate all the bing webelements is can also be done by using name, classname, tagname, linktext, cssselector,xpath for this to work you wrote the below code-
    else if(locatorType.toLowerCase().equals(“name”))
    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);
    throw new Exception(“Unknown locator type ‘” + locatorType + “‘”);

    Is that correct?

  10. Thanks for providing this, but I believe I’ve run into an issue. I use XPaths to locate my elements, and within some xpaths, 2 consecutive colons are used (i.e. xpath://div[@class=’contactus’]/parent::div).

    In these cases, I think the following piece of your code is shortening my xpath:

    // extract the locator type and value from the object
    String locatorType = locator.split(“:”)[0];
    String locatorValue = locator.split(“:”)[1];

    Can you please confirm that in my xpath’s scenarios with 2 colons, the above code would end my xpaths at the first of my 2 colons. And if it does, could you provide a workaround?

    Thank you

    • Hi Cyrus,

      You’re absolutely right, using a colon as a separator character won’t work when using xpaths that contain semicolons. A simple workaround would be to use another separator character, one that does not occur in xpath or any other locator. Maybe a semicolon would be a good candidate? Don’t forget to change the split() call as well.

      • Hi, thanks for the quick reply. I did try using unique characters for the split() calls, but they didn’t work (I used ” | ” and ” ^ ” characters, and separated my xpaths with those characters accordingly). However I found a workaround, using 3 colons does work.

        So now my modified code looks like:
        // extract the locator type and value from the object
        String locatorType = locator.split(“:::”)[0];
        String locatorValue = locator.split(“:::”)[1];

        With my sample xpath looking like this:

  11. Thanks for your post. I need your help in locating the split button in salesforce application. There is a small arrow. I tried but couldn’t succeed.

    • Hey Madhu,

      You could always try and right-click the button in Chrome and choose ‘Inspect’ to see its properties. You can also directly copy an XPath locator from there, although it’s probably an ugly one. Without access to the application I can’t help you further I’m afraid..

  12. Hi Bas,
    1. Can you guide me on how to to validate expected and actual value in selenium. Is there a generic method that I can use.
    2. Is there a way where I can use your Object Repository file (.properties) to store the expected values for various fields (ex:dropdown, multiselect checkbox) so that it is easy to maintain.

    I am trying to validate various fields and its values on a salesforce webpage.

    Really appreciate you help. Thanks

    • Hi Alok,

      1. There isn’t. Selenium itself cannot perform any validations as it is just a library to automate browser interactions. For generic assertions JUnit or TestNG are often used (for Java).

      2. Sure you can do that. Simply read out the previously stored value and compare it to the actual value using (for example) the assertEquals assertion in JUnit or TestNG.

  13. Hi, Just a suggestion.
    We can use Switch case for “public By getLocator(String strElement) ” method. since if else logic will traverse through all the code where as switch case will directly go to the desired Locator type.

    public static By get_Locator(String strElement) throws Exception

    /*Retrieve the strValue from the object repository list */
    String strLocator = Object_Repository.objObject_Repository_Properties_File.getProperty(strElement);

    /*Splitting String to extract the strLocator type and strValue from the object*/
    String strLocator_Type = strLocator.split(“:”)[0]; /*Example: strLocator = id:00N54000000SOrU, then strLocator_Type = id */
    String strLocator_Value = strLocator.split(“:”)[1];/*Example: strLocator = id:00N54000000SOrU, then strLocator_Value = 00N54000000SOrU */

    /* Printing the for testing and debugging purposes
    * System.out.println(“Locator is:” + strElement+ ” LocatorType is:” + strLocator_Type + ” LocatorValue is:” + strLocator_Value);

    By by; /* Created an instance of By Class */

    * Using switch case to get the ‘by’ strValue depending upon “strLocator_Type” and “strLocator strValue”.
    * @return by
    switch (strLocator_Type)
    case “id”:
    by =;

    case “name”:
    by =;

    case “classname”:
    by = By.className(strLocator_Value);

    case “tagname”:
    by = By.tagName(strLocator_Value);

    case “linktext”:
    by = By.linkText(strLocator_Value);

    case “partiallinktext”:
    by = By.partialLinkText(strLocator_Value);

    case “cssselector”:
    by = By.cssSelector(strLocator_Value);

    case “xpath”:
    by = By.xpath(strLocator_Value);

    by = null;
    throw new Exception(“—-Unknown strLocator type: ” + strLocator_Type + “——” );
    return by;


  14. Hi Bas,

    Can you please have an article on the below:
    1. Comparison between Page Object Model vs Properties Files.
    2. Data Driven Framework and Hydrid Driven Framework

    • Hi Alok,

      I’ll put those on the to-write list! It might take a while before I get the time to do some research and see whether I can write a blog post about it but I surely appreciate the suggestions!

  15. Bas,

    I am into Selenium C# and I was trying to implement POM using FindBy annotation. However this seems to be not working.
    Below here is the snippet :

    public class UnitTest1
    public IWebDriver wd;
    public string urlToNavigate;
    [FindsBy(How = How.ClassName, Using = “input”)]
    IList listOfInputBox;
    string webDriverPath = ConfigurationManager.AppSettings[“WebDriverPath”];

    public UnitTest1() { }
    public UnitTest1(IWebDriver driver)
    this.wd = driver;
    PageFactory.InitElements(wd, this);

    public void TestSetup()
    wd = new ChromeDriver(webDriverPath);
    urlToNavigate = “”;

    public void PageMethodNavigate()
    wd.Url = urlToNavigate;

    public void TearDown()

    Could you please suggest alternative OR types ?

  16. Hi,

    Can this code can also be used for InternetExplorerDriver?

    The class contains a single method getLocator, which returns a By object that is used by the Selenium browser driver object (such as a HtmlUnitDriver or a FirefoxDriver):

    Or is there any some other way?

  17. Hi,
    I’m just wondering if we can use a variable in the properties file , i mean something like nth-of-type(” + i+ “) as part of selector?

    • Not directly. Theoretically, you could try using a placeholder string (something like #INDEX#) and replace that at runtime with the actual index.

      I don’t like the look of that, but if it works for you..

  18. I disagree about the usefullness of the object repository in Selenium WebDriver test automation projects.

    In my opinion, using object repositories in Selenium projects is a bad practice.

    The object repository concept comes from record-and-playback tools such as QTP.

    The object repository is a tree-like structure that is created while recording a test.

    It has attributes for each element of the page used in the test.

    Selenium does not have any record-and-play feature for test automation (Selenium IDE is not an automation tool).

    Using object repositories in Selenium projects (as property or csv or xml files) has many disadvantages such as

    1. since each locator is a line in a text file, it is impossible to open the declaration of the locator in the IDE (using F3 or Open Declaration)

    2. page object classes with no locator variables break the class encapsulation principle (methods of a class should execute on variables of a class)

    3. object repositories do not scale well for big pages; since big pages are bad and should be broken down in small pages, should we not have object repositories for each page widget?

    4. object repositories do not work with page factory

    Read more about the disadvantages on this article:

    • Hey Alex,

      I agree. I’ve moved on since this post was published as well (it was published April 2014, 3,5 years ago). I’d never use it today. Just like I wouldn’t use page factory 😉

  19. Thanks, Bas.

    I had the feeling that you moved on while reading other posts on your excellent blog.

    Object repositories are obsolete and should be avoided.

  20. Hey Bas,
    Thanks for such an excellent article.In one of your earlier comments,you mentioned that you moved on from storing objects in properties file.Is there a better way to maintain page objects.Does storing objects in a JSON file makes it easier to understand ?Please advise.

      • Hi Bas,

        Your articles are really helpful.

        After reading your article and comments above i understood maintaining object repository from properties file with object map is not a good idea implementing using pom & page factory options are the best.

        Can you please help me on this scenario like testing the application with multiple countries and different languages.

        Since i already implemented my framework with POM and page factory for one country and want to convert this framework to multiple countries and languages.
        With out object repository how can we achieve this using pom and page factory.

  21. POM is a lot of overhead to maintain as the suite gets larger and once pages start sharing elements and functionalities, which is basically every web application out there. Many times automation testers find themselves maintaining POM instead of actually writing tests. Let’s also admit that most automation testers are not developers, making POM notorious for bad implementations. Partly the limitation of the tester but also alludes to the fact that it has a steep learning curve and not tester friendly – this coming from a Java developer like myself. I’ve worked with it long enough to understand it’s a maintenance chore nobody wants to admit because everyone else is using it. POM with Cucumber is the WORST as step definitions/methods are already independent units on their own. POM is also AUT-specific, which makes it unusable in other projects. Any change of the elements requires a recompile of the .java file.

    POM is an inflexible and rigid design pattern that builds technical debt over time and bloats the codebase. I have seen suites with 50+ page objects and it is an absolute nightmare. You will need developers to continue it in the long run, not testers.

    UI map/object repo is a good compromise of maintainability, learning curve, and delivery. And this article outlines a good approach to it. At the end of the day, it’s really the completed tests that matter to the stakeholders.

    • Hey Kat, thank you for your insights. I tend to use and teach Page Objects regularly, but as you say, they do have their downsides as well. It really depends on the situation whether or not it is a useful pattern.

      Also sorry for taking so long to approve your comment and reply to it, I blame holiday!

      • Hey Bas,

        No problem! The UI map definitely still has its place as does this fine article you wrote. The UI map can scale from medium-large projects – which is usually enough and there’s a faster ROI to it. Companies like to think they’re “big data” but most of the time, they’re really not haha.

        A framework is only as good as its maintainability and if the framework cannot live beyond its creator, it’s as good as dead – as does any software. Hence why there is no one-size-fits-all design pattern. 🙂

        By the way, the StringUtils from Apache Commons Lang has some really splendid methods for splicing/manipulating Strings like subStringAfter() and subStringBefore().

  22. Hey Bas,

    Need your help in resolving this issue. I’ m getting below error here-
    E/launcher – Error: TypeError: Cannot read property ‘0’ of undefined
    at objectLocator.findLocator

    Could you please help.

    let objectLocator = function(){

    var webElement = null;

    //find locator using provided locator type and locator value
    this.findLocator = function (locator, value) {
    var locatorType = locator[0];
    var locatorValue = locator[1];
    if (typeof locatorType !== ‘undefined’) {
    if (locatorValue.includes(‘#REPLACE#’)) {
    locatorValue = locatorValue.replace(‘#REPLACE#’, value);
    if (locatorType == ‘id’) {
    if (locatorValue !== ‘undefined’) {
    this.webElement = element(;
    } else if (locatorType == ‘name’) {
    if (locatorValue !== ‘undefined’) {
    this.webElement = element(;
    } else if (locatorType == ‘xpath’) {
    if (locatorValue !== ‘undefined’) {
    this.webElement = element(by.xpath(locatorValue));
    } else if (locatorType == ‘css’) {
    if (locatorValue !== ‘undefined’) {
    this.webElement = element(by.css(locatorValue));
    return this.webElement;
    module.exports = new objectLocator();

Leave a Reply to Bas Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.