Monday, September 28, 2009

UI-Elements - All about it!

What is UI-Element?

UI-Element is selenium’s answer to object repository. Those of us who have worked with test automation tools like QTP and WinRunner know what they are. Just to recap object repositories or GUI-Maps are map files where GUI object references are stored. These typically allow you to create logical entities and map them to GUI elements present in your test application. Now in your test script wherever there is a need to refer to a GUI element you can do so using its logical name given in the map file. This allows us to have logical names for ui objects instead of literal locator strings.

UI-Element is supported as a user extension in Selenium IDE and Selenium-RC. Haw-Bin Chai is the creator of this cool feature.The complete documentation of UI-Elements is available here . I know the official doc is a little overwhelming when you read it for the first time. But don't worry we would only be needing a very small part of the stuff that is in there.

Why do we need it?

* Readability: You have semantically meaningful names of elements in your test script rather than having the locators themselves that don’t make much sense. The test script becomes readable and comprehendible to a non-technical person as well.

* Maintainability
+ Single point of update: If the definition of a ui-element changes than you need to make changes at just one central location i.e. in your map file. Against this if you are using literal locators in your test script you would have to edit every instance of that element in your script. This is usually very tedious and error prone.
+ Error checking: ui-map file is JavaScript file that will alert you if there were any syntactical mistakes like ill-formed regular expressions etc.

Below you can see a two versions of a test scenario recorded using IDE. The scenario involves searching for the word 'wikipedia' in google and then searching for the word 'selenium' in the wikipedia search. There are a few 'verify' and 'waitFor' commands thrown in just to make the whole thing look good. Now the first one is without the usage of UI-Elements, just the plain recording and the next one uses UI-Elements. Notice how the script becomes a lot more readable when using UI-Elements.

Google-wiki script without using UI-Elements















































































Command Target Value
open http://www.google.co.in/









verifyElementPresent logo









type q wikipedia
click btnG









waitForElementPresent nqsbq









verifyElementPresent nqsbq









type nqsbq selenium
click btnGNS









waitForElementPresent link=Selenium (software) - Wikipedia, the free encyclopedia









verifyElementPresent link=Selenium (software) - Wikipedia, the free encyclopedia









click link=Selenium (software) - Wikipedia, the free encyclopedia









waitForElementPresent //div[@id='p-logo']/a









verifyTitle Selenium (software) - Wikipedia, the free encyclopedia









verifyElementPresent //div[@id='p-logo']/a












Same script with UI-Elements















































































Command Target Value
open http://www.google.co.in/









verifyElementPresent ui=googleSearch_page::theBigGoogleLogo()









type ui=googleSearch_page::search_Textbox() wikipedia
click ui=googleSearch_page::search_button()









waitForElementPresent ui=googleSearch_page::searchwikipedia_textbox()









verifyElementPresent ui=googleSearch_page::searchwikipedia_textbox()









type ui=googleSearch_page::searchwikipedia_textbox() selenium
click ui=googleSearch_page::searchwikipedia_button()









waitForElementPresent ui=googleSearch_page::seleniumSearchResult_Link()









verifyElementPresent ui=googleSearch_page::seleniumSearchResult_Link()









clickAndWait ui=googleSearch_page::seleniumSearchResult_Link()









waitForElementPresent ui=wikipediaArticle_page::wikipediaGlobe_image()









verifyTitle Selenium (software) - Wikipedia, the free encyclopedia









verifyElementPresent ui=wikipediaArticle_page::wikipediaGlobe_image()











The UI-Element map file used to for this script is as follows:
var myMap = new UIMap();


myMap.addPageset({
name: 'googleSearch_page'
, description: 'google main search page'
, pathRegexp: '.*'
});

myMap.addElement('googleSearch_page', {
name: 'theBigGoogleLogo'
, description: 'the Google logo visible on the main google search page'
, locator: "logo"
}
);

myMap.addElement('googleSearch_page', {
name: 'search_Textbox'
, description: 'the Google search textbox on google search page'
, locator: "q"
}
);

myMap.addElement('googleSearch_page', {
name: 'search_button'
, description: 'the Google search button with "Google Search" label on google search page'
, locator: "btnG"
}
);

myMap.addElement('googleSearch_page', {
name: 'firstSearchResultItem_Link'
, description: 'the first item in the search result list'
, locator: "//ol[@id='rso']/li[1]/h3/a/em"
}
);

myMap.addElement('googleSearch_page', {
name: 'searchwikipedia_textbox'
, description: 'search wikipedia text box below the google search result item'
, locator: "nqsbq"
}
);

myMap.addElement('googleSearch_page', {
name: 'searchwikipedia_button'
, description: 'Search Wikipedia.org button'
, locator: "btnGNS"
}
);

myMap.addElement('googleSearch_page', {
name: 'seleniumSearchResult_Link'
, description: 'search result link to selenium article in wikipedia'
, locator:"link=Selenium (software) - Wikipedia, the free encyclopedia"
}
);

myMap.addElement('googleSearch_page', {
name: 'wikipediaSeleniumPage_title'
, description: 'Title of th wiki page for selenium'
, locator:"Selenium (software) - Wikipedia, the free encyclopedia"
}
);

myMap.addPageset({
name: 'wikipediaArticle_page'
, description: 'wikipedia'
, pathRegexp: 'wiki/Selenium.*'
});

myMap.addElement('wikipediaArticle_page', {
name: 'wikipediaGlobe_image'
, description: 'Wikipedia, the free encyclopedia globe image'
, locator:"//div[@id='p-logo']/a"
}
);
This UI-MAP file has to be created manually. It looks quite complex but believe me it becomes a lot easier ones you start using it regularly. This map file is a JavaScript file with extention '.js' and has to be attached to Selenium IDE from Options->Options->Selenium Core Extentions.



Try this example out yourself. Just copy the entire html table above and paste it into the IDE (except the header row). Similarly copy ui-map file into notepad and save it as 'uiMapGoogle.js'. Now attach this file as a user extension in IDE options. You will be able to run the ui-element version of the script at this point. Also for any recording you do on the element mentioned in the map file you will see UI-Element based locators recorded in the IDE window. Also remember that after making any changes the map file the changes will take effect only after you close-reopen the IDE window.

Why UI-Element and why not .properties file?

There are many advantages to using the UI-Elements approach

1) Selenium IDE supports UI-Elements. This means IDE will record your scripts and use UI-Elements in place of literal locator values if you provide it with UI-Elements map file for the application that you are recording on. After recording your scripts in IDE the scripts can easily be ported to the Selenium-RC environment in a language of your liking. IDE does not support any other mapping approach.

2) A map file created using UI-Elements approach will be much easier to maintain in the long run because it will mind its integrity on its own. A JavaScript file will not allow duplicate entries or malformed regular expressions. A flat file like a ‘.properties’ file will not have such error checking abilities.

Structure of UI-Element map file

The map file is has a 2 level hierarchy. The top level is the ‘Pageset’ and the next level is the ‘element’. Think of a map file as a collection of pages with any number of elements within each page.

So first you add a pageset and then add elements within that pageset. For every elemnt there a set of mandatory properties you must add. For a pageset element name and description properties are mandatory. And for a element within a pageset name, description and locator are mandatory properties.

For example in the ui-map below googleSearch_page is the pageset element and theBigGoogleLogo is the element within googleSearch_page. Notice in the addElement method how googleSearch_page is the first parameter.

myMap.addPageset({

name: 'googleSearch_page'
, description: 'google main search page'
, pathRegexp: '.*'
});

myMap.addElement('googleSearch_page', {
name: 'theBigGoogleLogo'
, description: 'the Google logo visible on the main google search page'
, locator: "logo"
}
);

The property name is the logical name of the element, description is just description of what the element is all about and locator is locator of that element. All ui maps must begin with the below statement.
var myMap = new UIMap();


The ‘pathRegexp’ property defined with the pageset element signifies which pages (paths after domain excluding cgi e.g abc/789 in www.google.com/abc/789 ?lang=en_US) are to be matched with this pageset element.
Read the documentation of UI-Element for understanding other properties that can be used with pageset item and elements within it. The properties covered in this post are the most basic ones and should be sufficient for majority of cases.

10 Comments:

Amit Bhagwat said...

Hi Mahesh..

It is a really nice article...And the most underrated i guess(As i could see no comments from users) Keep up the good work dude....

rutvik said...

Good article.I was all over the place looking for a way to UI mapping in Selenium and this close to implementing my XML based approach.I am going to give it a try

Vijitha said...

Hi Mahesh,

This is really simple and efficient article that i have seen so far, for newbies to UI-element. I want to use this with selenium RC -perl,can you please let me know where to include the map file in RC?

Mahesh Narayanan said...

Hi Vijitha,

I have written an article about how to use ui-maps with selenium RC. Please read http://functionaltestautomation.blogspot.com/2009/09/using-ui-elements-with-selenium-rc.html

Hope this helps!.

rajpriya said...

Hi Mahesh,

many thanks for such a useful post.

Am new to selenium, just started exploring.

i have a mxml where as function is there & registered the same for js call. ExternalInterface.addCallback("getColor", getColor);

Then am calling the same from selenium RC :
flashApp.call("getColor"); flashApp.call("click"));

getColor is returning the default value.
But in click function am getting "Object doesn't support the property " error.

should i register it in user-extension.js?
Plz help me to resolve the issue

Pradeep Kumar Duddilla said...
This comment has been removed by the author.
Pradeep Kumar Duddilla said...

Hi,
Good one, can i map multiple attributes like the name of the search box in google is 'q' and also i want to use the id also can i achieve this.

i am using a constants file where i declare the properties of the object here is a small example
public static String txtbox_GoogleSearch = "q";
this i will refer in my script and also this is easy to maintain

Prabu said...

Mahesh,
Great article. You have talked about error checking ability. Could you please explain what kind of error checking ability? could you please give me an example. I have already posted this query in selenium forum.

Cathy said...

Hello Mahesh,
Thanks for your article! it's really useful one.

However, I'd like to know that whether I'm able to add more than 1 level which is child of the 2nd level in the level hierarchy of the map file or not? If can, pls show me how to do it?

Shruti Ramalingam said...

Thanks for the great information in your blog Selenium Training in Chennai