Thursday, October 27, 2011

Structure of UI-Element map file

Structure of UI-Element map file , Selenium Notes, Videos, examples by.www.laxmiroy.blogspot.com/


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 withingoogleSearch_page. Notice in the addElement method howgoogleSearch_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 inwww.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.
Relative locators for elements that change their position with time
Web applications are full of elements that are part of a list/table and their position in the list/table is bound to change with time. When identifying such elements static information such as the row number that they are on at the current moment is not the correct strategy. For example the vcdquaity website located here displays a long list of movie titles.
https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5UNcEamR7uT4PaNO0Me_eoqZdnUsE-wYjdgtedJdrOHHDR05G5uognsFQEF-AJvLfwDFP_WZ25dV4BZdVw-uzQKcgzwDYyTIwxEvnb0rJVV2Uf3RbyU20QMRnoiof1Ucfz2OzpZ7SYi4/s400/vcdquality+site+cropped+lvl2.PNG
New movies are added every now and then and these new ones will appear at the top pushing the existing ones down. Next to every movie title (apart from a few exceptions) you can see three small buttons namely JPG, nFO and IMDB respectively.
Let us record the step of clicking on the JPG button (highlighted in red square in the image above) next to the movie ‘Harry Potter The Half Blood Prince’ using selenium IDE.

clickAndWait //div[@id='content']/table/tbody/tr[17]/td[4]/a/img


As you can see the table row tr[17] is hard coded in the above locator. This will work as long as the table is unchanged but the moment a new title is added the above locator will point to the JPG button of some other movie title and not ‘Harry Potter The Half Blood Prince’.
For all such elements that change their position with time we need to devise locators that don’t have hard-coded positions in them and will work irrespective of their position in the list/table.
If the locators are xpath expressions then this can be done using the ‘xpath axes’.
W3school has an excellent tutorial on XPATH axes that can be found here.
I will try to demonstrate how to derive a relative xpath expression which will stand the test of time.
1. The first step should be to express the exact requirement in words. In this case we want the locator for the ‘jpg button that lies in the same row as the text Harry Potter The Half Blood Prince *XVID*’.
2. Now let us build a locator that point to the movie title text. Right click on the movie title ‘Harry Potter The Half Blood Prince *XVID*’and select ‘View XPath’. If you don’t see this option you don’t have XPath Checker installed in firefox. You can download XPath Checker here.
In XPath Checker window the XPath displayed isid('content')/table/tbody/tr[17]/td[3]/a.
3. We need to tweak this XPath expression to our requirement. Please remember that the XPath expression that we need mustnot have hard-coded row position but it’s ok to have a hard-coded column position because the column position will never change.
So lets start by removing the row position from the xpath expression in the Xpath Checker window.
Now we are left with id('content')/table/tbody/tr/td[3]/a
This xpath expression matches all movie title on the page. You can see in the XPath Checker window all the movie title shown as matches.
We can also get rid of the ‘/a’ from the expression since we are more interested in the textual contents of that cell and not the anchor tag.
So now we have id('content')/table/tbody/tr/td[3]
The next step would be to tweak the expression further such that it matches only the required row i.e the row that contains ‘Harry Potter The Half Blood Prince *XVID*’ in the 3rd column and not all the rows. To achieve this a node() predicate can be used in the following way

id('content')/table/tbody/tr/td[3][node()='Harry Potter The Half Blood Prince *XVID*']     


Now we have uniquely identified the row that contains our element and are currently pointing to the column that has the text‘Harry Potter The Half Blood Prince *XVID*’ in that row.
The JPG image/button resides one cell away from here.
To move in same row one cell to the right we need to use the XPath axes ‘following-sibling’. This XPath axes will help us to move right on the same level i.e move right in the same row of the table. Also remember that we need to move one cell i.e one td.Adding this axes changes our XPath expression to

id('content')/table/tbody/tr/td[3][node()='Harry Potter The Half Blood Prince *XVID*']/following-sibling::td[1]             


The XPath Checker would show just one match that is the JPG image/button.
To make this XPath expression work in selenium IDE append ‘xpath=’ to the beginning of the XPath expression derived above and voila it works.
So finally the XPath expression that matches our requirement is

xpath=id('content')/table/tbody/tr/td[3][node()='Harry Potter The Half Blood Prince *XVID*']/following-sibling::td[1]        


ancestor, descendant, following, preceding, preceding-siblingare some of the other XPath axes that I find very useful. All of these axes and more are explained in the link given at the beginning of this post.
Also please note that 'Harry Potter The Half Blood Prince *XVID*' was in the list when I wrote this post and you may have to replace it with some other movie title that is there in the list at that time.

No comments:

Post a Comment