tag:blogger.com,1999:blog-14602597503862785182024-03-18T04:03:08.138-07:00Software Functional Test AutomationThe main theme of this blog is software functional test automation with special stress on selenium suite of tools, frameworks, methodologies and approach.Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.comBlogger30125tag:blogger.com,1999:blog-1460259750386278518.post-60938273201268152212010-11-13T09:10:00.000-08:002010-11-13T23:44:15.975-08:00Testing sorting feature of an applicationAll applications display data and allow the user to sort the data on some column. I am sure you would have written or executed test cases to test the sorting feature of your application. There are many strategies to automate such test. In this post I will try to explain a strategy I use widely.<br />
<br />
Data is generally displayed in the form of a table (webtable) with each row containing one record. Generally in web applications the sorting feature is given on some or all column of the table. Let’s look at one such website that displays data in this fashion. Navigate to www.vcdq.com<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmtRUBYf50_WTGGPD-NJVH9k8-MegMZjgozXQW1rU6sXnUGLPkfh-3mu7q-iU4C3JY8rBQaSSY-jmo8SDvTHADP5KbQoejLkbFbqmjC9CM1cOazorf-QH0gQHVD5Eu7O6FzZ56jdl2dX0/s1600/vcdquality1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmtRUBYf50_WTGGPD-NJVH9k8-MegMZjgozXQW1rU6sXnUGLPkfh-3mu7q-iU4C3JY8rBQaSSY-jmo8SDvTHADP5KbQoejLkbFbqmjC9CM1cOazorf-QH0gQHVD5Eu7O6FzZ56jdl2dX0/s1600/vcdquality1.PNG" /></a></div><br />
This website as you can see has information on the latest movie releases. It allows you to sort the data on two of the columns, Date and Release. You can sort the data by clicking the respective column header. Both columns can be sorted in ascending and descending order. A small arrow icon is indicating the current sorting order next to the column header text. <br />
<br />
My strategy involves the following <br />
a) Reading all the data of this table into a java ArrayList. Lets call this ExpectedList<br />
b) Perform the sort on the application by clicking the column header<br />
c) Read the data from the table again and store it in another ArrayList. Lets call this ActualListAfterSort<br />
d) Sort the ExpectedList<br />
e) Compare ExpectedList with ActualListAfterSort and verify that the order of the elements is same.<br />
<br />
There is a distinction between the ArrayList that holds primitive datatypes like String or int and the one I use. I use a user defined class to hold the rows of data. Each member element of this class represents one column of the table. The class is defined below.<br />
<br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>public class ReleaseInfoTableRecord {
String standard;
Date date;
String format;
String source;
String release;
double imdb;
int disks;
String group;
int ratingAudio;
int ratingVideo;
public ReleaseInfoTableRecord(String standard, Date date, String format,
String source, String release, double imdb, int disks, String group,
int ratingAudio, int ratingVideo) {
super();
this.standard = standard;
this.date = date;
this.format = format;
this.source = source;
this.release = release;
this.imdb = imdb;
this.disks = disks;
this.group = group;
this.ratingAudio = ratingAudio;
this.ratingVideo = ratingVideo;
}
}
</code></pre><br />
I will insert objects of this class into the ArrayList. An object will represent one row of the table. This is how will insert record within the ArrayList.<br />
<br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>ArrayList<ReleaseInfoTableRecord> LatestMovieReleaseDisplayed=new ArrayList<ReleaseInfoTableRecord>();
LatestMovieReleaseDisplayed.add(new ReleaseInfoTableRecord(standard, date, format,
source, release, imdb, disks, group, ratingAudio, ratingVideo ) );
</code></pre><br />
Now in order to sort the data of the ArrayList I would have to define some comparators. I will have to define comparators for all the sort features that I wish to test. For example If the application under test allows sorting the data on ascending and descending order on column Date and I want to test this feature than I need to define two comparators one for ascending and other for descending on date. I will be defining these comparators in the class ReleaseInfoTableRecord.<br />
<br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>static final Comparator<ReleaseInfoTableRecord> SORT_DATE_ASCENDING = new Comparator<ReleaseInfoTableRecord>(){
public int compare(ReleaseInfoTableRecord o1, ReleaseInfoTableRecord o2) {
int result = o1.getDate().compareTo(o2.getDate());
if (o1.getDate().equals(o2.getDate()))
result =o1.getRelease().compareTo(o2.getRelease())*-1;
return (result);
}
};
static final Comparator<ReleaseInfoTableRecord> SORT_DATE_DESCENDING = new Comparator<ReleaseInfoTableRecord>(){
public int compare(ReleaseInfoTableRecord o1, ReleaseInfoTableRecord o2) {
int result = o1.getDate().compareTo(o2.getDate())*-1;
if (o1.getDate().equals(o2.getDate()))
result =o1.getRelease().compareTo(o2.getRelease());
return (result);
}
};
</code></pre><br />
The hashCode and equals method of the data class must be overridden to make the comparison possible. This overriden methods can be genarated in eclipse by doing right click source-->generate hashcode and equals. You will se this below in the full class code.<br />
<br />
If the two records have the same date then the application sorts on the basis of Release name. Note the logic for each comparator when the date is same. This is specific to this application and the application that you are testing may have a different logic. Go thru the application logic carefully before defining the comparators.<br />
<br />
Now we define the actual test method that tests the sorting feature. Note that I have read the data into the ArrayList dataAsDisplayedInDefaultView in an earlier step. The code in the while loop is instruction that performs the sorting on the web application i.e clicks the column header link repeatedly till the appropriate arrow icon appears. Your application may involve steps different than this to invoke sort.<br />
<br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>@Test
public void testSortingDateAscending() {
int i=0;
<span style="color: lime;"><span style="color: #38761d;">//Click Date column header till the small up arrow is visible next to <Date> column header, </span>
<span style="color: #38761d;"> //don't get confused by the title of the up arrow image</span></span>
while (false==selenium.isElementPresent("//table//th[2]/a/img[@title='sort descending']")&&i<2){
selenium.click("link=Date");
selenium.waitForPageToLoad("30000");
}
ArrayList<ReleaseInfoTableRecord> dataAsDisplayedAfterSort=getLatestMovieReleaseDisplayed();
<span style="color: #38761d;"> //make a copy of the arraylist that holds the displayed data </span>
ArrayList<ReleaseInfoTableRecord> expectedOrder=dataAsDisplayedInDefaultView;
<span style="color: #38761d;">//sort the copy on Date Descending, this is how the data is sorted in the default view on this website</span>
Collections.sort(expectedOrder, ReleaseInfoTableRecord.SORT_DATE_ASCENDING);
<span style="background-color: #eeeeee; color: #38761d;"> //This will pass only if the elements in both the lists appear in the same order</span>
org.testng.Assert.assertTrue(dataAsDisplayedAfterSort.equals(expectedOrder));
}</code></pre><br />
Below you can see both the classes in their full glory. ReleaseInfoTableRecord class that will be used to hold the data (record of the table) and SortingTest is the test class.<br />
<br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>package test;
import java.util.Comparator;
import java.util.Date;
public class <b>ReleaseInfoTableRecord</b> {
String standard;
Date date;
String format;
String source;
String release;
double imdb;
int disks;
String group;
int ratingAudio;
int ratingVideo;
public ReleaseInfoTableRecord(String standard, Date date, String format,
String source, String release, double imdb, int disks, String group,
int ratingAudio, int ratingVideo) {
super();
this.standard = standard;
this.date = date;
this.format = format;
this.source = source;
this.release = release;
this.imdb = imdb;
this.disks = disks;
this.group = group;
this.ratingAudio = ratingAudio;
this.ratingVideo = ratingVideo;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((date == null) ? 0 : date.hashCode());
result = prime * result + disks;
result = prime * result + ((format == null) ? 0 : format.hashCode());
result = prime * result + ((group == null) ? 0 : group.hashCode());
long temp;
temp = Double.doubleToLongBits(imdb);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ratingAudio;
result = prime * result + ratingVideo;
result = prime * result + ((release == null) ? 0 : release.hashCode());
result = prime * result + ((source == null) ? 0 : source.hashCode());
result = prime * result + ((standard == null) ? 0 : standard.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ReleaseInfoTableRecord other = (ReleaseInfoTableRecord) obj;
if (date == null) {
if (other.date != null)
return false;
} else if (!date.equals(other.date))
return false;
if (disks != other.disks)
return false;
if (format == null) {
if (other.format != null)
return false;
} else if (!format.equals(other.format))
return false;
if (group == null) {
if (other.group != null)
return false;
} else if (!group.equals(other.group))
return false;
if (Double.doubleToLongBits(imdb) != Double.doubleToLongBits(other.imdb))
return false;
if (ratingAudio != other.ratingAudio)
return false;
if (ratingVideo != other.ratingVideo)
return false;
if (release == null) {
if (other.release != null)
return false;
} else if (!release.equals(other.release))
return false;
if (source == null) {
if (other.source != null)
return false;
} else if (!source.equals(other.source))
return false;
if (standard == null) {
if (other.standard != null)
return false;
} else if (!standard.equals(other.standard))
return false;
return true;
}
public String getStandard() {
return standard;
}
public void setStandard(String standard) {
this.standard = standard;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getRelease() {
return release;
}
public void setRelease(String release) {
this.release = release;
}
public double getImdb() {
return imdb;
}
public void setImdb(double imdb) {
this.imdb = imdb;
}
public int getDisks() {
return disks;
}
public void setDisks(int disks) {
this.disks = disks;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public int getRatingAudio() {
return ratingAudio;
}
public void setRatingAudio(int ratingAudio) {
this.ratingAudio = ratingAudio;
}
public int getRatingVideo() {
return ratingVideo;
}
public void setRatingVideo(int ratingVideo) {
this.ratingVideo = ratingVideo;
}
static final Comparator<ReleaseInfoTableRecord> SORT_DATE_ASCENDING = new Comparator<ReleaseInfoTableRecord>(){
public int compare(ReleaseInfoTableRecord o1, ReleaseInfoTableRecord o2) {
int result = o1.getDate().compareTo(o2.getDate());
if (o1.getDate().equals(o2.getDate()))
result =o1.getRelease().compareTo(o2.getRelease())*-1;
return (result);
}
};
static final Comparator<ReleaseInfoTableRecord> SORT_DATE_DESCENDING = new Comparator<ReleaseInfoTableRecord>(){
public int compare(ReleaseInfoTableRecord o1, ReleaseInfoTableRecord o2) {
int result = o1.getDate().compareTo(o2.getDate())*-1;
if (o1.getDate().equals(o2.getDate()))
result =o1.getRelease().compareTo(o2.getRelease());
return (result);
}
};
static final Comparator<ReleaseInfoTableRecord> SORT_RELEASE_ASCENDING = new Comparator<ReleaseInfoTableRecord>(){
public int compare(ReleaseInfoTableRecord o1, ReleaseInfoTableRecord o2) {
int result = o1.getRelease().compareTo(o2.getRelease());
return (result);
}
};
static final Comparator<ReleaseInfoTableRecord> SORT_RELEASE_DESCENDING = new Comparator<ReleaseInfoTableRecord>(){
public int compare(ReleaseInfoTableRecord o1, ReleaseInfoTableRecord o2) {
int result = o1.getRelease().compareTo(o2.getRelease());
return (result * -1);
}
};
}
</code></pre><br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>package test;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import org.openqa.selenium.server.SeleniumServer;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.thoughtworks.selenium.SeleneseTestCase;
public class <b>SortingTest</b> extends SeleneseTestCase{
ArrayList<ReleaseInfoTableRecord> dataAsDisplayedInDefaultView;
@BeforeClass
public void setUp() throws Exception {
SeleniumServer seleniumserver=new SeleniumServer();
seleniumserver.boot();
seleniumserver.start();
setUp("http://www.vcdq.com", "*firefox");
selenium.open("/");
selenium.windowMaximize();
selenium.windowFocus();
<span style="color: #38761d;">//filter the results to reduce the data-set to manageable levels</span> selenium.select("filterStandard", "label=SCENE");
selenium.select("filterTerm3", "label=DVDR");
selenium.select("filterTerm2", "label=DVD");
selenium.click("//input[@value='Filter']");
selenium.waitForPageToLoad("20000");
dataAsDisplayedInDefaultView=getLatestMovieReleaseDisplayed();
}
@Test
public void testDefaultSorting(){
<span style="color: #38761d;">//make a copy of the arraylist that holds the displayed data </span>
ArrayList<ReleaseInfoTableRecord> expectedOrder=dataAsDisplayedInDefaultView;
<span style="color: #38761d;"> //sort the copy on Date Descending, this is how the data is sorted in the default view on this website</span>
Collections.sort(expectedOrder, ReleaseInfoTableRecord.SORT_DATE_DESCENDING);
<span style="color: #38761d;">//This will pass only if the elements in both the lists appear in the same order</span>
org.testng.Assert.assertTrue(dataAsDisplayedInDefaultView.equals(expectedOrder));
}
@Test
public void testSortingDateAscending() {
int i=0;
<span style="color: #38761d;">//Click Date column header till the small up arrow is visible next to <Date> column header, </span>
<span style="color: #38761d;"> //don't get confused by the title of the up arrow image</span>
while (false==selenium.isElementPresent("//table//th[2]/a/img[@title='sort descending']")&&i<2){
selenium.click("link=Date");
selenium.waitForPageToLoad("30000");
}
ArrayList<ReleaseInfoTableRecord> dataAsDisplayedAfterSort=getLatestMovieReleaseDisplayed();
<span style="color: #38761d;">//make a copy of the arraylist that holds the displayed data </span>
ArrayList<ReleaseInfoTableRecord> expectedOrder=dataAsDisplayedInDefaultView;
<span style="color: #38761d;">//sort the copy on Date Descending, this is how the data is sorted in the default view on this website</span>
Collections.sort(expectedOrder, ReleaseInfoTableRecord.SORT_DATE_ASCENDING);
<span style="color: #38761d;"> //This will pass only if the elements in both the lists appear in the same order</span>
org.testng.Assert.assertTrue(dataAsDisplayedAfterSort.equals(expectedOrder));
}
@Test
public void testSortingReleaseNameAscending(){
int i=0;
<span style="color: #38761d;">//Click Date column header till the small up arrow is visible next to <Release> column header, </span>
<span style="color: #38761d;"> //don't get confused by the title of the up arrow image</span>
while (false==selenium.isElementPresent("//table//th[6]/a/img[@title='sort descending']")&&i<2){
<span style="color: #38761d;">//Click Date column header once so that the sort ascending image is visible</span>
selenium.click("link=Release");
selenium.waitForPageToLoad("30000");
i=i+1;
}
ArrayList<ReleaseInfoTableRecord> dataAsDisplayedAfterSort=getLatestMovieReleaseDisplayed();
<span style="color: #38761d;">//make a copy of the arraylist that holds the displayed data </span>
ArrayList<ReleaseInfoTableRecord> expectedOrder=dataAsDisplayedInDefaultView;
<span style="color: #38761d;">//sort the copy on Date Descending, this is how the data is sorted in the default view on this website</span>
Collections.sort(expectedOrder, ReleaseInfoTableRecord.SORT_RELEASE_ASCENDING);
<span style="color: #38761d;"> //This will pass only if the elements in both the lists appear in the same order</span>
org.testng.Assert.assertTrue(dataAsDisplayedAfterSort.equals(expectedOrder));
}
@Test
public void testSortingReleaseNameDescending(){
int i=0;
<span style="color: #38761d;">//Click Date column header till the small up arrow is visible next to <Release> column header, </span>
<span style="color: #38761d;"> //don't get confused by the title of the up arrow image </span>
while (false==selenium.isElementPresent("//table//th[6]/a/img[@title='sort ascending']")&&i<2) {
<span style="color: #38761d;">//Click Date column header once so that the sort ascending image is visible</span>
selenium.click("link=Release");
selenium.waitForPageToLoad("30000");
}
ArrayList<ReleaseInfoTableRecord> dataAsDisplayedAfterSort=getLatestMovieReleaseDisplayed();
<span style="color: #38761d;">//make a copy of the arraylist that holds the displayed data </span>
ArrayList<ReleaseInfoTableRecord> expectedOrder=dataAsDisplayedInDefaultView;
<span style="color: #38761d;">//sort the copy on Date Descending, this is how the data is sorted in the default view on this website</span>
Collections.sort(expectedOrder, ReleaseInfoTableRecord.SORT_RELEASE_DESCENDING);
<span style="color: #38761d;">//This will pass only if the elements in both the lists appear in the same order</span>
org.testng.Assert.assertTrue(dataAsDisplayedAfterSort.equals(expectedOrder));
}
public ArrayList<ReleaseInfoTableRecord> getLatestMovieReleaseDisplayed() {
ArrayList<ReleaseInfoTableRecord> LatestMovieReleaseDisplayed=new ArrayList<ReleaseInfoTableRecord>();
String standard;
Date date=null;
String format;
String source;
String release;
double imdb;
int disks;
String group;
int ratingAudio;
int ratingVideo;
String rating;
String imdbCellContent;
int tableRowCount=selenium.getXpathCount("/descendant::table//tr").intValue();
<span style="color: #38761d;">//read the data from the webtable</span>
for (int i=1;i<tableRowCount;i++){
standard=selenium.getText("XPATH=/descendant::table//tr["+i+"]//td[1]");
DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
try{
date=df.parse(selenium.getText("XPATH=/descendant::table//tr["+i+"]//td[2]"));
}catch (ParseException p){
System.out.println(p.getMessage());
}
format=selenium.getText("XPATH=/descendant::table//tr["+i+"]//td[4]");
source=selenium.getText("XPATH=/descendant::table//tr["+i+"]//td[5]");
release=selenium.getText("XPATH=/descendant::table//tr["+i+"]//td[6]");
imdbCellContent=selenium.getText("XPATH=/descendant::table//tr["+i+"]//td[10]");
imdb=!(imdbCellContent.equalsIgnoreCase("N/A"))?Double.parseDouble(selenium.getText("XPATH=/descendant::table//tr["+i+"]//td[10]")):0.0;
disks=Integer.parseInt(selenium.getText("XPATH=/descendant::table//tr["+i+"]//td[11]"));
group=selenium.getText("XPATH=/descendant::table//tr["+i+"]//td[12]");
rating=selenium.getText("XPATH=/descendant::table//tr["+i+"]//td[13]");
ratingVideo=Integer.parseInt(rating.split(" ")[0].split(":")[1]);
ratingAudio=Integer.parseInt(rating.split(" ")[1].split(":")[1]);
<span style="color: #38761d;">//insert the data as a instances of the class ReleaseInfoTableRecord into the arraylist</span>
LatestMovieReleaseDisplayed.add(new ReleaseInfoTableRecord(standard, date, format,
source, release, imdb, disks, group, ratingAudio, ratingVideo ) );
}
return LatestMovieReleaseDisplayed;
}
}
</code></pre><br />
Copy paste these classes into your project and run as testng test to see them in action.<br />
<br />
This is the most robust and foolproof strategy I have come across for testing sorting functionality. I use it to test search results, reports etc. You might also want to create test data before invoking the sort i.e create test data items abc, efg, zab or you could just use the existing data in the system.<br />
<pre></pre>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com59tag:blogger.com,1999:blog-1460259750386278518.post-20948905822643793972010-09-05T10:59:00.000-07:002010-09-05T18:29:45.373-07:00Locator for cell containing nbsp in Selenium RCIf you want to point to a table cell containing a <b style="color: blue;">&<i>nbsp;</i></b> (non breaking space) character then you must use the unicode equivalent of nbsp i.e <b style="color: blue;">\u00a0</b> in your locator. Interestingly this is required only in Selenium RC. A simple space would suffice if you were to achieve this in Selenium IDE. Below is the sample HTML code that has the table with the cell containing the nbsp and the selenium RC instruction to highlight that cell.<br />
<br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code><table border="1">
<tr>
<td>abcd&nbsp;efgh</td>
<td>abcdefgh</td>
</tr></table>
</code></pre><br />
<br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>
selenium.highlight("//td[text()='abcd<b>\u00a0</b>efgh']");</code></pre>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com20tag:blogger.com,1999:blog-1460259750386278518.post-8838293212008752932010-07-14T10:39:00.000-07:002010-07-14T10:41:09.683-07:00Introducing SeleniumForum.com, the forum for selenium userHi,<br />
I had always felt a lack of a proper forum for selenium users. And ever since clerspace.openqa was discontinued it was ever more important to start one. Google groups just does not have the features of a forum. So here it goes http://www.seleniumforum.com<br />
<br />
Please register and start participating.Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com131tag:blogger.com,1999:blog-1460259750386278518.post-76684834544077800602010-05-02T10:18:00.000-07:002010-05-03T11:29:23.381-07:00Extending the Default Selenium<span style="font-size: 130%;">What the heck is Default Selenium?<br />
<span style="font-size: small;">Calm down!, DefaultSelenium is the base class that you instantiate early on in your test class to get the selenium object which you later use in almost every line of you test script.</span></span><br />
<span style="font-size: 130%;"><span style="font-size: small;"> </span><br />
</span><br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>.
.
Selenium selenium=new DefaultSelenium("localhost",4444,"*chrome","http://www.google.com/");
selenium.start();
selenium.open("/");
.
.
.
</code></pre><pre> OR
</pre><pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>
/*Creates a new DefaultSelenium object and starts it using the specified baseUrl and browser string*/
setUp("http://www.imdb.com/", "*firefox");
selenium.open("/");
selenium.click("nb15go_image");
.
.
.
</code></pre><span style="font-size: 130%;"><span style="font-size: small;">does that ring a bell?</span> </span><br />
<br />
<span style="font-size: 130%;"> </span><br />
<span style="font-size: 130%;">What do you mean by extending the default selenium?</span><br />
<span style="font-size: 100%;">Extending the default selenium means enhancing or customizing or modifying the existing features of selenium class. We are reusing the existing class after adding some enhancements so as to customize the existing features to our taste and requirement. Programming languages such as JAVA provide the facility of extending/modifying the behavior of a class without having to re-write the entire class. We can create a new class that inherits the attributes and methods of another. We don't need a copy of the original source code (as is the case with many other languages) to extend the usefulness of a class/library.</span><br />
<span style="font-size: 130%;"><br />
Why do I need to extend selenium?</span><br />
If you want certain operations to be done every time before a step is executed then you would have to extend the default selenium. For example let’s say that you wish to wait 5 seconds after every step or you want to highlight the element before clicking on it or you want to record every step in log file or you want to poll for a element’s existence for a certain amount of time before performing an operation (click, type) on it. For all these to happen you would have to extend the default selenium class that you use in your RC test script.<br />
<br />
Below is a simple example that demonstrates this concept. The class <span style="font-style: italic;">MySelenium</span> extends the class <span style="font-style: italic;">DefaultSelenium</span>. The methods <span style="font-style: italic;">click</span> and <span style="font-style: italic;">type</span> of the base class have been over-ridden in such a way that the target element (which is to be clicked on or typed into) is highlighted thrice before the <span style="font-style: italic;">click</span> or <span style="font-style: italic;">type</span> operation. The class <span style="font-style: italic;">UsingMySelenium</span> by the means of a simple example demonstrates the usage of our extended class.<br />
<br />
<span style="font-size: 85%;">Class MySelenium</span><br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>package seleniumExtention;
import com.thoughtworks.selenium.DefaultSelenium;
public class MySelenium extends DefaultSelenium{
public MySelenium(String seleniumSeverHost, int port,String browserString,String autURL){
super(seleniumSeverHost, port,browserString, autURL);
}
@Override
public void click(String target) {
try {
for (int i=0;i<3;i++){
super.highlight(target);
Thread.sleep(500);
}
super.click(target);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void type(String target, String value){
try{
for (int i=0;i<3;i++){
super.highlight(target);
Thread.sleep(500);
}
super.type(target,value);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
</code></pre><br />
<br />
<span style="font-size: 85%;">Class UsingMySelenium</span><br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>package seleniumExtention;
import org.junit.Test;
import org.junit.BeforeClass;
import org.openqa.selenium.server.SeleniumServer;
import com.thoughtworks.selenium.SeleneseTestCase;
public class UsingMySelenium extends SeleneseTestCase{
public MySelenium selenium;
@BeforeClass
public void setUp() throws Exception {
SeleniumServer seleniumserver=new SeleniumServer();
seleniumserver.boot();
seleniumserver.start();
/*using the customized selenium class that we created earlier instead of the default selenium*/
selenium=new MySelenium ("localhost",4444,"*iexplore","http://www.google.com/");
selenium.start();
selenium.windowMaximize();
}
@Test
public void testSimpleGoogleSearch() throws Exception {
selenium.open("/");
selenium.waitForPageToLoad("5000");
selenium.type("q", "Aston Martin volante");
selenium.click("//input[@value='Google Search']");
selenium.waitForPageToLoad("5000");
selenium.click("xpath=/descendant::a[text()=' - The Cars']/em[text()='Aston Martin']/parent::a");
selenium.waitForPageToLoad("25000");
Thread.sleep(5000);
}
}
</code></pre><br />
To make this work you need to do the following<br />
1) Create a package <span style="font-style: italic;">seleniumExtention</span> inside the java project.<br />
2) Create the classes <span style="font-style: italic;">MySelenium</span> & <span style="font-style: italic;">UsingMySelenium</span> and copy paste the content as given above.<br />
3) Run the <span style="font-style: italic;">testSimpleGoogleSearch()</span> given in the class <span style="font-style: italic;">UsingMySelenium</span> (right click Run As-->JUnit Test).<br />
<br />
*Following jars need to be referenced<br />
selenium-server.jar<br />
selenium-java-client-driver.jar<br />
junit.jar<br />
<br />
good luck with this and keep the questions coming!Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com11tag:blogger.com,1999:blog-1460259750386278518.post-75273106777023371132010-02-07T09:27:00.000-08:002010-02-08T10:59:51.503-08:00Running TestNG tests from command lineNote: Eclipse is not required to compile or run TestNG tests.<br />This is how you can <span style="font-weight: bold;">compile and run testng tests</span> from command line. Follow the steps below<br />1. Download and Install JDK from http://java.sun.com/javase/downloads/index.jsp<br />2. The below bat file compiles and runs the dataProviderExample test explained in my earlier <a href="http://functionaltestautomation.blogspot.com/2009/10/dataprovider-data-driven-testing-with.html">blog post</a>. Read that post before trying this.<br />3. The project folder is at C:\MyEclipseWorkspace\dataDrivenTestProject. You would have to modify javaTestProjectPath variable in the bat file if your project folder lies elsewhere.<br />4. Java development kit or JDK is installed at C:\Program Files\java\jdk1.6.0_18, You need to change this if your jdk folder path is different from this. This will happen if you are using a different version of java than mine.<br />5. The <span style="font-weight: bold;">testng.xml file</span> given below is placed at C:\MyEclipseWorkspace\dataDrivenTestProject.<br /><br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); line-height: 14px; width: 100%;font-family:Andale Mono,Lucida Console,Monaco,fixed,monospace;font-size:12px;"><code><span style="font-family:verdana;"><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"></span><br /><span style="font-family:verdana;"><suite name="dataDrivenTestProject"></span><br /><span style="font-family:verdana;"> <test name="script.dataProviderExample"></span><br /><span style="font-family:verdana;"> <classes></span><br /><span style="font-family:verdana;"> <class name="script.dataProviderExample"/></span><br /><span style="font-family:verdana;"> </classes></span><br /><span style="font-family:verdana;"> </test></span><br /><span style="font-family:verdana;"></suite></span><br /></code></pre><br />6. Open Notepad and copy paste the below commands. Unselect word wrap from format-->word wrap in Notepad. This will ensure that there are no unwanted line breaks. Now save the file as testng.bat anywhere in your local machine. Double click the bat file to run.<br /><br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); line-height: 14px; width: 100%;font-family:Andale Mono,Lucida Console,Monaco,fixed,monospace;font-size:12px;"><code><span><span style="font-family:verdana;"><span style="color: rgb(0, 102, 0);">REM create variable that stores the project folder path. This variable will used in the subsequent statements.</span><br />set javaTestProjectPath=C:\MyEclipseWorkspace\dataDrivenTestProject</span></span></code><br /><code><span style="font-family:verdana;"><span style="color: rgb(0, 102, 0);">REM move to the project folder</span><br />c:<br />cd </span></code><code><span><span><span><span style="font-family:verdana;">%javaTestProjectPath</span></span></span></span></code><code><span style="font-family:verdana;"><span style="color: rgb(0, 102, 0);"><span style="color: rgb(0, 0, 0);">%</span><br />REM set path to dir that contains javac.exe and java.exe</span><br />set path=C:\Program Files\java\jdk1.6.0_18\bin<span style="color: rgb(0, 102, 0);"></span><br /><span style="color: rgb(0, 102, 0);">REM set the classpath, this tells java where to look for the library files, the project bin folder is adde as it will store the .class file after compile</span><br />set classpath=%javaTestProjectPath%\bin;%javaTestProjectPath%\Lib\junit-4.5.jar;%javaTestProjectPath%\Lib\jxl.jar;%javaTestProjectPath%\Lib\selenium-java-client-driver.jar;%javaTestProjectPath%\Lib\selenium-server.jar;%javaTestProjectPath%\Lib\testng-5.9-jdk15.jar<br /><span style="color: rgb(0, 102, 0);">REM compile the dataProviderExample.java file, the -d parameter tells javac where to put the .class file that is created on compile</span><br />javac -verbose %javaTestProjectPath%\test\script\dataProviderExample.java -d %javaTestProjectPath%\bin<br /><span style="color: rgb(0, 102, 0);">REM execute testng framework by giving the path of the testng.xml file as a parameter. The xml file tells testng what test to run</span><br />java org.testng.TestNG %javaTestProjectPath%\testng.xml</span><span style="font-family:verdana;"></span><br /></code></pre><br />Read the <span style="color: rgb(0, 102, 0);">REM statements</span> in the bat file to understand the commands used.<br /><br /><pre><br /><br /></pre>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com12tag:blogger.com,1999:blog-1460259750386278518.post-53816520632122276912009-12-26T10:45:00.001-08:002009-12-26T10:48:53.126-08:00Merry Christmas and a Happy New Year!<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgguerSvP-bj_WQtNwgI0ThXlgs2XNnFEZYVm_smd4dco8dtDKo99SlpJ7lfkQC2F7ZHHrMbjj5qLRMyevRsptVxPmWTe-R9X3wYf74Z68vMOsnwIj6yrbO56BvzawCJ1jEphoDa_UqE4w/s1600-h/usaidTheCameraWasOff.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 297px; height: 400px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgguerSvP-bj_WQtNwgI0ThXlgs2XNnFEZYVm_smd4dco8dtDKo99SlpJ7lfkQC2F7ZHHrMbjj5qLRMyevRsptVxPmWTe-R9X3wYf74Z68vMOsnwIj6yrbO56BvzawCJ1jEphoDa_UqE4w/s400/usaidTheCameraWasOff.jpg" alt="" id="BLOGGER_PHOTO_ID_5419618137426823186" border="0" /></a>Hey there, check out the coolest website in the whole friggin world <a href="http://icanhascheezburger.com/">icanhascheezburger</a>. Happy Holidays and try not to think about testing. :)Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com0tag:blogger.com,1999:blog-1460259750386278518.post-87916770982847278862009-10-26T12:25:00.000-07:002009-10-26T12:51:31.212-07:00Maximize browser window using java robot in Selenium RC<span style="font-size:100%;">Have you noticed that selenium RC does not maximize the browser window even after invoking the <span style="font-style: italic;">selenium.windowMaximize( )</span> ? The window is not stretched-out fully.</span><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgk0jneGqNygBowDJ25qx2-GggWODzwpCohnY0YMTALVvVI0KN20EuXxPHk4POnYmoaUfv-Ofkf9mPWTFGUzO8V2t4za_S2fv7CzMMXNaU_AJXlKRbQ_Asb1RhvzJC27_TFD9JHERAACSo/s1600-h/windowMaximize1.PNG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 203px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgk0jneGqNygBowDJ25qx2-GggWODzwpCohnY0YMTALVvVI0KN20EuXxPHk4POnYmoaUfv-Ofkf9mPWTFGUzO8V2t4za_S2fv7CzMMXNaU_AJXlKRbQ_Asb1RhvzJC27_TFD9JHERAACSo/s400/windowMaximize1.PNG" alt="" id="BLOGGER_PHOTO_ID_5396996057442820946" border="0" /></a><span style="font-size:100%;"><br /></span><span style="font-size:100%;">The only way to maximize the browser window fully I suppose is to use the java robot to do a keyboard simulation of ALT+SPACE which displays the main window's system menu and then using the down arrow key reach the maximize option and then do an ENTER to invoke this option.<br /><br />Below is the code that will do this for you. </span><br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); line-height: 14px; width: 100%;font-family:Andale Mono,Lucida Console,Monaco,fixed,monospace;font-size:12px;"><code><span style="color: rgb(0, 153, 0);">//maximize the window as much a possible using selenium</span><br /><br /> selenium.windowMaximize();<br /><br /><span style="color: rgb(0, 153, 0);">//bring the browser window into focus</span><br /><br /> selenium.windowFocus();<br /><br /><span style="color: rgb(0, 153, 0);">//invoke the system menu using robot </span><br /><br /> Robot robot = new Robot();<br /> robot.keyPress(KeyEvent.VK_ALT);<br /> robot.keyPress(KeyEvent.VK_SPACE);<br /> robot.keyRelease(KeyEvent.VK_ALT);<br /> robot.keyRelease(KeyEvent.VK_SPACE);<br /> Thread.sleep(1000);<br /><br /></code><code><span style="color: rgb(0, 153, 0);">//Press down arrow key to move down the menu</span></code><br /><br /><code> robot.keyPress(KeyEvent.VK_DOWN);<br /> robot.keyRelease(KeyEvent.VK_DOWN);<br /> Thread.sleep(100);<br /><br /> robot.keyPress(KeyEvent.VK_DOWN);<br /> robot.keyRelease(KeyEvent.VK_DOWN);<br /> Thread.sleep(100);<br /><br /> robot.keyPress(KeyEvent.VK_DOWN);<br /> robot.keyRelease(KeyEvent.VK_DOWN);<br /> Thread.sleep(100);<br /><br /> robot.keyPress(KeyEvent.VK_DOWN);<br /> robot.keyRelease(KeyEvent.VK_DOWN);<br /> Thread.sleep(100);<br /><br /></code><code><span style="color: rgb(0, 153, 0);">//Press enter to invoke the Maximize menu option </span> </code><br /><br /><code> robot.keyPress(KeyEvent.VK_ENTER);<br /> robot.keyRelease(KeyEvent.VK_ENTER);<br /><br /></code></pre><span style="font-size:100%;"><br />Don't forget to import the following in your test class.</span><br /><br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>import java.awt.Robot;<br />import java.awt.event.KeyEvent;<br /></code></pre>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com20tag:blogger.com,1999:blog-1460259750386278518.post-12718520576634375742009-10-03T08:29:00.000-07:002010-07-10T11:31:30.139-07:00DataProvider - Data Driven Testing with Selenium and TestNGData-Driven testing generally means executing a set of steps with multiple sets of data.<br />
Selenium does not provide any out-of-the box solution for data driven testing but leaves it up to the user to implement this on his own. People who are familiar with QuickTest Professional or QTP would know Datatables (Global & Action) that allows the scripter to link a action or a function with multiple rows of data.<br />
<br />
<a href="http://testng.org/doc/documentation-main.html"><span style="text-decoration: underline;">TestNG</span></a> is a framework that makes data-driven testing possible in selenium. TestNG is a testing framework created in line with Junit but with added features that makes it suitable for use in regression test automation projects. DataProvider is one such feature in testng; it allows a test method to be executed with multiple sets of data.<br />
<br />
A DataProvider is data feeder method defined in your class that supplies a test method with data. You may hook up any test method with a DataProvider and make the test method execute once for every row of your test data.<br />
<br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code><span style="font-family: verdana;">@DataProvider(name = "DP1")</span>
<span style="font-family: verdana;"> public Object[][] createData() {</span>
<span style="font-family: verdana;"> Object[][] retObjArr={{"001","Jack","London"},</span>
<span style="font-family: verdana;"> {"002","John","New York"},</span>
<span style="font-family: verdana;"> {"003","Mary","Miami"},</span>
<span style="font-family: verdana;">{"004","George","california"}};</span>
<span style="font-family: verdana;"> return(retObjArr);</span>
<span style="font-family: verdana;"> }</span>
<span style="font-family: verdana;">@Test (dataProvider = "DP1")</span>
<span style="font-family: verdana;"> public void testEmployeeData(String empid, String empName, String city){</span>
<span style="font-family: verdana;">selenium.type("id", empid);</span>
<span style="font-family: verdana;">selenium.type("name", empName);</span>
<span style="font-family: verdana;">selenium.click("submit_button");</span>
<span style="font-family: verdana;">selenium.waitForPageToLoad("30000");</span>
<span style="font-family: verdana;">assertTrue(selenium.isTextPresent(city));</span>
<span style="font-family: verdana;">}</span>
</code></pre><style>
<!-- /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman";} pre {margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Courier New"; mso-fareast-font-family:"Times New Roman";} span.com {mso-style-name:com;} @page Section1 {size:8.5in 11.0in; margin:1.0in 1.25in 1.0in 1.25in; mso-header-margin:.5in; mso-footer-margin:.5in; mso-paper-source:0;} div.Section1 {page:Section1;} -->
</style><br />
In the example above createData() is the DataProvider function that is sending out test data in the form of array of array of objects (object[][]). The test method testEmployeeData() hooks onto the DataProvider by declaring that its data should be supplied by the DataProvider named "DP1". On execution testEmployeeData() will be executed 4 times, once with each row of object[][]. Note that the dimension of the array returned by the DataProvider must match the parameter type of the test method. This means if your test method takes 3 parameters then array returned by the DataProvider must have its second dimension equal to 3. Try to visualize the array of array as a table where each row constitutes one test case.<br />
<br />
In the example above the test data is defined withing the DataProvider function. But ideally you want to keep your test data in spreadsheet like media and not in the test script. To achieve this instead of declaring the test data array within the DataProvider function we should call a function that fetches the data from an excel sheet and returns an array of array object to the DataProvider.<br />
I will share with you my way of storing data in XL sheets. I store test data in the form of tables within an excel sheet. There could be any number of tables within an excel sheet. Each table is marked by an startTag and an endTag. The startTag and endTag is the Name of the table. The startTag is placed <span style="font-weight: bold;">one cell diagonally above the cell from where the first row of table data begins</span>. And the <span style="font-weight: bold;">endTag is placed one cell diagonally below the cell from where last row of table data ends</span>. A table always begins with a column header row although this row is just for our understanding and is ignored in the computation. Below is the image of a sample test data excel sheet. Click on the image to see a bigger version of it. Also below the image you can see the google doc with the test data I will use in an example later in this post.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjl8pVS4DF7oVxghZfMD8yiHLlHALCpB2WCL-l0SS3m-SABS8KDBFf6CC2PwK8Izc1hCX9ufBcVZmTU6N3kaLiGWCHt9tCoswmlzcqZWJg9lqpt_LoTBvKhyphenhyphenBcSI83OsF8ojJLcHuKgBN8/s1600-h/dataProviderTestData3.PNG" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5388430797205029778" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjl8pVS4DF7oVxghZfMD8yiHLlHALCpB2WCL-l0SS3m-SABS8KDBFf6CC2PwK8Izc1hCX9ufBcVZmTU6N3kaLiGWCHt9tCoswmlzcqZWJg9lqpt_LoTBvKhyphenhyphenBcSI83OsF8ojJLcHuKgBN8/s400/dataProviderTestData3.PNG" style="cursor: pointer; display: block; height: 240px; margin: 0px auto 10px; text-align: center; width: 400px;" /></a><br />
<iframe frameborder="0" height="600" src="http://spreadsheets.google.com/pub?key=tHBiSOMu95PYwF_LZ949pHA&single=true&gid=0&output=html&widget=true" width="700"></iframe><br />
<br />
Below is the function that fetches the table from the excel sheet and returns it as an array of array of String type. It uses <a href="http://jexcelapi.sourceforge.net/">Java Excel API</a> to fetch data from excel sheet.<br />
It takes 3 parameters<br />
1. xlFilePath - the path of XL file/workbook containing the data, the path is relative to java project<br />
2. sheetName- name of the xl sheet that contains the table<br />
3. tableName- Name of the table that you wish to fetch<br />
The function returns a String type array of array.<br />
<br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code><span style="font-family: verdana;">public String[][] getTableArray(String xlFilePath, String sheetName, String tableName){</span>
<span style="font-family: verdana;"> String[][] tabArray=null;</span>
<span style="font-family: verdana;"> try{</span>
<span style="font-family: verdana;"> Workbook workbook = Workbook.getWorkbook(new File(xlFilePath));</span>
<span style="font-family: verdana;"> Sheet sheet = workbook.getSheet(sheetName);</span>
<span style="font-family: verdana;"> int startRow,startCol, endRow, endCol,ci,cj;</span>
<span style="font-family: verdana;"> Cell tableStart=sheet.findCell(tableName);</span>
<span style="font-family: verdana;"> startRow=tableStart.getRow();</span>
<span style="font-family: verdana;"> startCol=tableStart.getColumn();</span>
<span style="font-family: verdana;"> Cell tableEnd= sheet.findCell(tableName, startCol+1,startRow+1, 100, 64000, false); </span>
<span style="font-family: verdana;"> endRow=tableEnd.getRow();</span>
<span style="font-family: verdana;"> endCol=tableEnd.getColumn();</span>
<span style="font-family: verdana;"> System.out.println("startRow="+startRow+", endRow="+endRow+", " +</span>
<span style="font-family: verdana;"> "startCol="+startCol+", endCol="+endCol);</span>
<span style="font-family: verdana;"> tabArray=new String[endRow-startRow-1][endCol-startCol-1];</span>
<span style="font-family: verdana;"> ci=0;</span>
<span style="font-family: verdana;"> for (int i=startRow+1;i<endRow;i++,ci++){</span>
<span style="font-family: verdana;"> cj=0;</span>
<span style="font-family: verdana;"> for (int j=startCol+1;j<endCol;j++,cj++){</span>
<span style="font-family: verdana;"> tabArray[ci][cj]=sheet.getCell(j,i).getContents();</span>
<span style="font-family: verdana;"> }</span>
<span style="font-family: verdana;"> }</span>
<span style="font-family: verdana;"> }</span>
<span style="font-family: verdana;"> catch (Exception e) {</span>
<span style="font-family: verdana;"> System.out.println("error in getTableArray()");</span>
<span style="font-family: verdana;"> }</span>
<span style="font-family: verdana;"> return(tabArray);</span>
<span style="font-family: verdana;"> }</span>
</code></pre><br />
Now we will put all of this together in an example. We will keep the test data in excel sheets and use the above function to fetch from it.<br />
Note:<br />
1. testng jar should be in the class path. You may download the latest testng jar file from <a href="http://testng.org/doc/download.html">here</a>.<br />
2. testng eclipse plugin must be installed. Get it from the same location as the testng jar file mentioned above.<br />
3. jxl jar should be in the class path Java Excel API. You can get this from <a href="http://sourceforge.net/projects/jexcelapi/files/">here</a>. Download the jexcelapi.zip, unzip to get the jxl.jar<br />
4. Selenium-server and selenium-java-client-driver and junit jar (selenium classes need junit) files must in class path.<br />
5. The file data1.xls is kept at test\\Resources\\Data\\data1.xls<br />
I have attached this file to the blog as a google doc, please copy paste its contents to a excel file. Rename the excel-sheet to <span style="font-style: italic;">DataPool </span>and the save the excel file as <span style="font-style: italic;">data.xls</span>. The path mentioned is relative to the project.<br />
<br />
The test method testDataProviderExample() below navigates to www.imdb.com and performs search for movie titles. On the movie details page it verifies the presence of director name, movie plot and the name of the lead actor. This routine is repeated for all the rows of the test-data table.<br />
<br />
<pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code><span style="font-family: verdana;">import com.thoughtworks.selenium.*;</span>
<span style="font-family: verdana;">import org.junit.AfterClass;</span>
<span style="font-family: verdana;">import org.openqa.selenium.server.SeleniumServer;</span>
<span style="font-family: verdana;">import org.testng.annotations.*;</span>
<span style="font-family: verdana;">import java.io.File;</span>
<span style="font-family: verdana;">import jxl.*; </span>
<span style="font-family: verdana;">public class DataProviderExample extends SeleneseTestCase{</span>
<span style="font-family: verdana;"> </span>
<span style="font-family: verdana;"> @BeforeClass</span>
<span style="font-family: verdana;"> public void setUp() throws Exception {</span>
<span style="font-family: verdana;"> SeleniumServer seleniumserver=new SeleniumServer();</span>
<span style="font-family: verdana;"> seleniumserver.boot();</span>
<span style="font-family: verdana;"> seleniumserver.start();</span>
<span style="font-family: verdana;"> setUp("http://www.imdb.com/", "*firefox");</span>
<span style="font-family: verdana;"> selenium.open("/");</span>
<span style="font-family: verdana;"> selenium.windowMaximize();</span>
<span style="font-family: verdana;"> selenium.windowFocus();</span>
<span style="font-family: verdana;"> }</span>
<span style="font-family: verdana;"> </span>
<span style="font-family: verdana;"> @DataProvider(name = "DP1")</span>
<span style="font-family: verdana;"> public Object[][] createData1() throws Exception{</span>
<span style="font-family: verdana;"> Object[][] retObjArr=getTableArray("test\\Resources\\Data\\data1.xls",</span>
<span style="font-family: verdana;"> "DataPool", "imdbTestData1");</span>
<span style="font-family: verdana;"> return(retObjArr);</span>
<span style="font-family: verdana;"> }</span>
<span style="font-family: verdana;"> </span>
<span style="font-family: verdana;"> @Test (dataProvider = "DP1")</span>
<span style="font-family: verdana;"> public void testDataProviderExample(String movieTitle, </span>
<span style="font-family: verdana;"> String directorName, String moviePlot, String actorName) throws Exception { </span>
<span style="font-family: verdana;"> //enter the movie title </span>
<span style="font-family: verdana;"> selenium.type("q", movieTitle);</span>
<span style="font-family: verdana;"> //they keep switching the go button to keep the bots away</span>
<span style="font-family: verdana;"> if (selenium.isElementPresent("nb15go_image"))</span>
<span style="font-family: verdana;"> selenium.click("nb15go_image");</span>
<span style="font-family: verdana;"> else</span>
<span style="font-family: verdana;"> selenium.click("xpath=/descendant::button[@type='submit']");</span>
<span style="font-family: verdana;"> </span>
<span style="font-family: verdana;"> selenium.waitForPageToLoad("30000");</span>
<span style="font-family: verdana;"> //click on the movie title in the search result page</span>
<span style="font-family: verdana;"> selenium.click("xpath=/descendant::a[text()='"+movieTitle+"']");</span>
<span style="font-family: verdana;"> selenium.waitForPageToLoad("30000");</span>
<span style="font-family: verdana;"> //verify director name is present in the movie details page </span>
<span style="font-family: verdana;"> verifyTrue(selenium.isTextPresent(directorName));</span>
<span style="font-family: verdana;"> //verify movie plot is present in the movie details page</span>
<span style="font-family: verdana;"> verifyTrue(selenium.isTextPresent(moviePlot));</span>
<span style="font-family: verdana;"> //verify movie actor name is present in the movie details page</span>
<span style="font-family: verdana;"> verifyTrue(selenium.isTextPresent(actorName));</span>
<span style="font-family: verdana;"> }</span>
<span style="font-family: verdana;"> </span>
<span style="font-family: verdana;"> @AfterClass</span>
<span style="font-family: verdana;"> public void tearDown(){</span>
<span style="font-family: verdana;"> selenium.close();</span>
<span style="font-family: verdana;"> selenium.stop();</span>
<span style="font-family: verdana;"> } </span>
<span style="font-family: verdana;"> </span>
<span style="font-family: verdana;"> public String[][] getTableArray(String xlFilePath, String sheetName, String tableName) throws Exception{</span>
<span style="font-family: verdana;"> String[][] tabArray=null;</span>
<span style="font-family: verdana;"> </span>
<span style="font-family: verdana;"> Workbook workbook = Workbook.getWorkbook(new File(xlFilePath));</span>
<span style="font-family: verdana;"> Sheet sheet = workbook.getSheet(sheetName); </span>
<span style="font-family: verdana;"> int startRow,startCol, endRow, endCol,ci,cj;</span>
<span style="font-family: verdana;"> Cell tableStart=sheet.findCell(tableName);</span>
<span style="font-family: verdana;"> startRow=tableStart.getRow();</span>
<span style="font-family: verdana;"> startCol=tableStart.getColumn();</span>
<span style="font-family: verdana;"> Cell tableEnd= sheet.findCell(tableName, startCol+1,startRow+1, 100, 64000, false); </span>
<span style="font-family: verdana;"> endRow=tableEnd.getRow();</span>
<span style="font-family: verdana;"> endCol=tableEnd.getColumn();</span>
<span style="font-family: verdana;"> System.out.println("startRow="+startRow+", endRow="+endRow+", " +</span>
<span style="font-family: verdana;"> "startCol="+startCol+", endCol="+endCol);</span>
<span style="font-family: verdana;"> tabArray=new String[endRow-startRow-1][endCol-startCol-1];</span>
<span style="font-family: verdana;"> ci=0;</span>
<span style="font-family: verdana;"> for (int i=startRow+1;i<endRow;i++,ci++){</span>
<span style="font-family: verdana;"> cj=0;</span>
<span style="font-family: verdana;"> for (int j=startCol+1;j<endCol;j++,cj++){</span>
<span style="font-family: verdana;"> tabArray[ci][cj]=sheet.getCell(j,i).getContents();</span>
<span style="font-family: verdana;"> }</span>
<span style="font-family: verdana;"> }</span>
<span style="font-family: verdana;"> </span>
<span style="font-family: verdana;"> return(tabArray);</span>
<span style="font-family: verdana;"> }</span>
<span style="font-family: verdana;"> </span>
<span style="font-family: verdana;"> </span>
<span style="font-family: verdana;">}//end of class</span>
</code></pre><br />
Just copy paste the above in a java file, reference the necessary jars in the build path, put the test-data excel file in the correct location and it should work just fine. To run right click the java file in eclipse and select <span style="font-style: italic;">Run As-->TestNG Test</span>.<br />
<br />
<span style="font-weight: bold;">Watch video of how to create a data driven test script from scratch step by step</span><br />
<br />
<b>Part 1</b><br />
<br />
<object height="344" width="425"><param name="movie" value="http://www.youtube.com/v/KL4Y7cWiK4g&hl=en_US&fs=1&"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/KL4Y7cWiK4g&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object><br />
<br />
<b>Part 2</b><br />
<br />
<object height="344" width="425"><param name="movie" value="http://www.youtube.com/v/JMZeaF0ST4w&hl=en_US&fs=1&"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/JMZeaF0ST4w&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object><br />
<br />
<b>Part 3</b><br />
<br />
<object height="344" width="425"><param name="movie" value="http://www.youtube.com/v/1ZV8pZAKkDQ&hl=en_US&fs=1&"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/1ZV8pZAKkDQ&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object><br />
<br />
<b>Part 4</b><br />
<br />
<object height="344" width="425"><param name="movie" value="http://www.youtube.com/v/A6ND9pRRBY8&hl=en_US&fs=1&"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/A6ND9pRRBY8&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object><br />
<br />
Feel free to post queries here.<br />
<br />
edit on 10 july 2010: removed try/catch from getTableArray(), it's easier to debug spreadsheet file name/sheet name mismatch this way.Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com312tag:blogger.com,1999:blog-1460259750386278518.post-74910358786899172872009-09-29T10:55:00.000-07:002009-10-07T12:31:59.196-07:00Using UI-Elements user-extension with Selenium RCPlease refer to my post <a href="http://functionaltestautomation.blogspot.com/2009/09/ui-elements-all-about-it.html">UI-Elements - All about it</a> to understand what UI-Elements are. In this post I wish to describe how UI-Elements can be used with Selenium RC.<br /><br />There are a few things that are different here from how it is used with selenium ide<br /><span style="font-weight: bold;">1)</span> In Selenium IDE the UI-Map file is added to the IDE environment as selenium core extension. You may add any number of such files from the IDE->options->Selenium core extensions.<br />In Selenium RC the UI Map file is added either programatically or added as command line parameter when invoking selenium-server.<br /><br /><span style="font-weight: bold;">2)</span>In Selenium IDE you may add as many map files as you wish. However in<br />Selenium RC you can add only one UI-Map file and that file must be in the same directory as selenium-server.jar. Also the name of ui-map file must be 'user-extensions.js'.<br /><br />Below is code for attaching the ui-map file to the selenium server. The 'getConfiguration()' method of <span style="font-weight: bold;">seleniumserver </span>object is used to get the configuration object and the 'setUserExtension()' method is used to set the uimap file as the user-extension.<br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>.<br />.<br />.<br />SeleniumServer seleniumserver;<br />seleniumserver=new SeleniumServer();<br />RemoteControlConfiguration a= seleniumserver.getConfiguration();<br />File uimap=new File("lib\\user-extensions.js");<br />a.setUserExtensions(uimap);<br />seleniumserver.boot();<br />seleniumserver.start();<br />.<br />.<br />.<br /></code></pre><br />Now what if you have multiple ui-map files? In that case you must combine all of them together to create one consolidated 'user-extension.js' file. I have written a function that does this for me.<br />Please note that you must remove the instruction<br /><br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>var myMap = new UIMap();<br /></code></pre><br />from the individual map files as the function adds it automatically in the combined file.<br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>public static void createUIMAP(String masterUIMAPfilePath) throws java.io.IOException{ <br />RandomAccessFile file = null;<br />RandomAccessFile fileui = null;<br />String line = null;<br />String lineui = null;<br /><br /><br />File oldFile=new File("lib\\user-extentions.js");<br />if (oldFile.exists())<br />oldFile.delete();<br /><br />FileWriter fstream = new FileWriter("lib\\user-extensions.js",true);<br />String theFirstLine="var myMap = new UIMap();";<br />fstream.write(theFirstLine, 0, theFirstLine.length());<br />file = new RandomAccessFile(masterUIMAPfilePath, "r");<br />while ((line = file.readLine()) != null) {<br />System.out.println(line);<br />fileui = new RandomAccessFile(line, "r");<br />while ((lineui = fileui.readLine()) != null) {<br />System.out.println(lineui);<br />fstream.write(lineui, 0, lineui.length());<br />fstream.write(System.getProperty("line.separator"));<br /><br />}<br />}<br />fstream.close();<br />}<br /></code></pre>This function deletes any file with the name 'user-extension.js' that may be there in the \lib folder within your java project and creates a new 'user-extension.js' file by combining any number of child ui-map file(s) whose location(s) is mentioned in the text file masterUIMAPfile whose path is supplied as a parameter to this function.<br />The masterUIMapFile may look something like this (all paths are relative to the java project).<br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>test\\Resources\\UIMaps\\admin\\uimap1.js<br />test\\Resources\\UIMaps\\admin\\uiMapGoogle.js<br /></code></pre>I have placed the 'uiMaster.txt' in <span style="font-style: italic;">test\Resources\UIMaps\admin\uiMaster.txt</span> within my java project.<br />Now I will put this all together with the script that was created in my last <a href="http://functionaltestautomation.blogspot.com/2009/09/ui-elements-all-about-it.html">post</a>. The createUIMAP() function is to be called before calling the setUserExtensions() method.<br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code><br />import org.junit.AfterClass;<br />import org.junit.Test;<br />import org.openqa.selenium.server.RemoteControlConfiguration;<br />import org.openqa.selenium.server.SeleniumServer;<br />import com.thoughtworks.selenium.*;<br />import java.io.File;<br />import java.io.FileWriter;<br />import java.io.RandomAccessFile;<br /><br /><br />public class testGoogleUIMapNew extends SeleneseTestCase {<br />public void setUp() throws Exception {<br />createUIMAP("test\\Resources\\UIMaps\\admin\\uiMaster.txt");<br />SeleniumServer seleniumserver;<br />seleniumserver=new SeleniumServer();<br />RemoteControlConfiguration a= seleniumserver.getConfiguration();<br />File uimap=new File("lib\\user-extensions.js");<br />a.setUserExtensions(uimap);<br />seleniumserver.boot();<br />seleniumserver.start();<br /><br />setUp("http://www.google.com/", "*firefox");<br />}<br /><br /><br /><br />@Test public void testGoogleuimap() throws Exception {<br />selenium.open("www.google.co.in");<br />verifyTrue(selenium.isElementPresent("ui=googleSearch_page::theBigGoogleLogo()"));<br />selenium.type("ui=googleSearch_page::search_Textbox()", "wikipedia");<br />selenium.click("ui=googleSearch_page::search_button()");<br />selenium.waitForPageToLoad("30000");<br />verifyTrue(selenium.isElementPresent("ui=googleSearch_page::searchwikipedia_textbox()"));<br />selenium.type("ui=googleSearch_page::searchwikipedia_textbox()", "selenium");<br />selenium.click("ui=googleSearch_page::searchwikipedia_button()");<br />selenium.waitForPageToLoad("30000");<br />verifyTrue(selenium.isElementPresent("ui=googleSearch_page::seleniumSearchResult_Link()")); <br />selenium.click("ui=googleSearch_page::seleniumSearchResult_Link()");<br />selenium.waitForPageToLoad("30000");<br />verifyEquals(selenium.getTitle(), "Selenium (software) - Wikipedia, the free encyclopedia");<br />verifyTrue(selenium.isElementPresent("ui=wikipediaArticle_page::wikipediaGlobe_image()")); <br />}<br /><br /><br />@AfterClass<br />public void tearDown(){<br />selenium.close();<br />selenium.stop();<br />} //end of tearDown()<br /><br />public static void createUIMAP(String masterUIMAPfilePath) throws java.io.IOException{<br />RandomAccessFile file = null;<br />RandomAccessFile fileui = null;<br />String line = null;<br />String lineui = null;<br /><br /><br />File oldFile=new File("lib\\user-extentions.js");<br />if (oldFile.exists())<br />oldFile.delete();<br /><br />FileWriter fstream = new FileWriter("lib\\user-extensions.js",true);<br />String theFirstLine="var myMap = new UIMap();";<br />fstream.write(theFirstLine, 0, theFirstLine.length()); <br />file = new RandomAccessFile(masterUIMAPfilePath, "r");<br />while ((line = file.readLine()) != null) {<br />System.out.println(line);<br />fileui = new RandomAccessFile(line, "r");<br />while ((lineui = fileui.readLine()) != null) {<br />System.out.println(lineui);<br />fstream.write(lineui, 0, lineui.length());<br />fstream.write(System.getProperty("line.separator"));<br /><br />}<br />}<br />fstream.close();<br />}<br />}<br /><br /></code></pre><br />To run this just right click and choose option 'Run As junit test'. Please remember that in my case the 'selenium-server.jar' fie is in the /lib folder.<br /><br />You should ideally tuck away the createUIMAP() function and the code to start the selenium-server in a utility class in your project and just be calling them in your test script.<br /><br />Also note that the testGoogleuimap() test method in this example is from my last <a href="http://functionaltestautomation.blogspot.com/2009/09/ui-elements-all-about-it.html">post</a>. You can derive this java equivalent of the IDE recording by doing <span style="font-style: italic;">Options-->format-->Java (Junit) - Selenium RC</span> from Selenium IDE. I have just replaced the awfully big while constructs in the script with<br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>selenium.waitForPageToLoad("30000");<br /></code></pre>As always junit, selenium-server and selenium-client-driver are in the classpath.<br /><br />Please feel free to post any queries here.Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com17tag:blogger.com,1999:blog-1460259750386278518.post-76123501920207693882009-09-28T11:05:00.000-07:002009-09-29T10:43:40.084-07:00UI-Elements - All about it!<span style="font-weight: bold;">What is UI-Element?</span>
<br />
<br />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.
<br />
<br />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 <a href="http://ttwhy.org/code/ui-doc.html">here</a> . 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.
<br />
<br /><span style="font-weight: bold;">Why do we need it?</span>
<br />
<br />* 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.
<br />
<br />* Maintainability
<br />+ 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.
<br />+ Error checking: ui-map file is JavaScript file that will alert you if there were any syntactical mistakes like ill-formed regular expressions etc.
<br />
<br />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.
<br />
<br /><span style="font-weight: bold;">Google-wiki script without using UI-Elements</span>
<br /><style type="text/css">.nobrtable br { display: none }</style>
<br /><div class="nobrtable">
<br /><table border="1" cellpadding="1" cellspacing="1">
<br /><tbody>
<br /><tr>
<br /> <td>Command</td>
<br /> <td>Target</td>
<br /> <td>Value</td>
<br /></tr>
<br /><tr>
<br /> <td>open</td>
<br /> <td>http://www.google.co.in/</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>verifyElementPresent</td>
<br /> <td>logo</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>type</td>
<br /> <td>q</td>
<br /> <td>wikipedia </td>
<br /></tr>
<br /><tr>
<br /> <td>click</td>
<br /> <td>btnG</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>waitForElementPresent</td>
<br /> <td>nqsbq</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>verifyElementPresent</td>
<br /> <td>nqsbq</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>type</td>
<br /> <td>nqsbq</td>
<br /> <td>selenium</td>
<br /></tr>
<br /><tr>
<br /> <td>click</td>
<br /> <td>btnGNS</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>waitForElementPresent</td>
<br /> <td>link=Selenium (software) - Wikipedia, the free encyclopedia</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>verifyElementPresent</td>
<br /> <td>link=Selenium (software) - Wikipedia, the free encyclopedia</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>click</td>
<br /> <td>link=Selenium (software) - Wikipedia, the free encyclopedia</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>waitForElementPresent</td>
<br /> <td>//div[@id='p-logo']/a</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>verifyTitle</td>
<br /> <td>Selenium (software) - Wikipedia, the free encyclopedia</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>verifyElementPresent</td>
<br /> <td>//div[@id='p-logo']/a</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /></tbody></table>
<br /></div>
<br />
<br /><span style="font-weight: bold;">Same script with UI-Elements</span>
<br /><style type="text/css">.nobrtable br { display: none }</style>
<br /><div class="nobrtable">
<br /><table border="1" cellpadding="1" cellspacing="1">
<br /><tbody>
<br /><tr>
<br /> <td>Command</td>
<br /> <td>Target</td>
<br /> <td>Value</td>
<br /></tr>
<br /><tr>
<br /> <td>open</td>
<br /> <td>http://www.google.co.in/</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>verifyElementPresent</td>
<br /> <td>ui=googleSearch_page::theBigGoogleLogo()</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>type</td>
<br /> <td>ui=googleSearch_page::search_Textbox()</td>
<br /> <td>wikipedia </td>
<br /></tr>
<br /><tr>
<br /> <td>click</td>
<br /> <td>ui=googleSearch_page::search_button()</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>waitForElementPresent</td>
<br /> <td>ui=googleSearch_page::searchwikipedia_textbox()</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>verifyElementPresent</td>
<br /> <td>ui=googleSearch_page::searchwikipedia_textbox()</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>type</td>
<br /> <td>ui=googleSearch_page::searchwikipedia_textbox()</td>
<br /> <td>selenium</td>
<br /></tr>
<br /><tr>
<br /> <td>click</td>
<br /> <td>ui=googleSearch_page::searchwikipedia_button()</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>waitForElementPresent</td>
<br /> <td>ui=googleSearch_page::seleniumSearchResult_Link()</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>verifyElementPresent</td>
<br /> <td>ui=googleSearch_page::seleniumSearchResult_Link()</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>clickAndWait</td>
<br /> <td>ui=googleSearch_page::seleniumSearchResult_Link()</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>waitForElementPresent</td>
<br /> <td>ui=wikipediaArticle_page::wikipediaGlobe_image()</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>verifyTitle</td>
<br /> <td>Selenium (software) - Wikipedia, the free encyclopedia</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /><tr>
<br /> <td>verifyElementPresent</td>
<br /> <td>ui=wikipediaArticle_page::wikipediaGlobe_image()</td>
<br /> <td>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></td>
<br /></tr>
<br /></tbody></table>
<br /></div>
<br />The UI-Element map file used to for this script is as follows:
<br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>var myMap = new UIMap();
<br />
<br />myMap.addPageset({
<br />name: 'googleSearch_page'
<br />, description: 'google main search page'
<br />, pathRegexp: '.*'
<br />});
<br />
<br />myMap.addElement('googleSearch_page', {
<br />name: 'theBigGoogleLogo'
<br />, description: 'the Google logo visible on the main google search page'
<br />, locator: "logo"
<br />}
<br />);
<br />
<br />myMap.addElement('googleSearch_page', {
<br />name: 'search_Textbox'
<br />, description: 'the Google search textbox on google search page'
<br />, locator: "q"
<br />}
<br />);
<br />
<br />myMap.addElement('googleSearch_page', {
<br />name: 'search_button'
<br />, description: 'the Google search button with "Google Search" label on google search page'
<br />, locator: "btnG"
<br />}
<br />);
<br />
<br />myMap.addElement('googleSearch_page', {
<br />name: 'firstSearchResultItem_Link'
<br />, description: 'the first item in the search result list'
<br />, locator: "//ol[@id='rso']/li[1]/h3/a/em"
<br />}
<br />);
<br />
<br />myMap.addElement('googleSearch_page', {
<br />name: 'searchwikipedia_textbox'
<br />, description: 'search wikipedia text box below the google search result item'
<br />, locator: "nqsbq"
<br />}
<br />);
<br />
<br />myMap.addElement('googleSearch_page', {
<br />name: 'searchwikipedia_button'
<br />, description: 'Search Wikipedia.org button'
<br />, locator: "btnGNS"
<br />}
<br />);
<br />
<br />myMap.addElement('googleSearch_page', {
<br />name: 'seleniumSearchResult_Link'
<br />, description: 'search result link to selenium article in wikipedia'
<br />, locator:"link=Selenium (software) - Wikipedia, the free encyclopedia"
<br />}
<br />);
<br />
<br />myMap.addElement('googleSearch_page', {
<br />name: 'wikipediaSeleniumPage_title'
<br />, description: 'Title of th wiki page for selenium'
<br />, locator:"Selenium (software) - Wikipedia, the free encyclopedia"
<br />}
<br />);
<br />
<br />myMap.addPageset({
<br />name: 'wikipediaArticle_page'
<br />, description: 'wikipedia'
<br />, pathRegexp: 'wiki/Selenium.*'
<br />});
<br />
<br />myMap.addElement('wikipediaArticle_page', {
<br />name: 'wikipediaGlobe_image'
<br />, description: 'Wikipedia, the free encyclopedia globe image'
<br />, locator:"//div[@id='p-logo']/a"
<br />}
<br />);
<br /></code></pre>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.
<br />
<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg17OvSiuglHPBjyOL7oBEhc7GjFGNEilNknD1cH1w8AIpDTtqct9CrhkpBfx52paUXQ9F0DVNLxD6Kmj0jOLD-emjMH4qrpnUIbC0CQ5wQ0U8IA2l_JJcyuEs64m8Ar3snfKjWC2QHcEI/s1600-h/uimapFileAttachedToIDE.JPG"><img style="cursor: pointer; width: 400px; height: 386px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg17OvSiuglHPBjyOL7oBEhc7GjFGNEilNknD1cH1w8AIpDTtqct9CrhkpBfx52paUXQ9F0DVNLxD6Kmj0jOLD-emjMH4qrpnUIbC0CQ5wQ0U8IA2l_JJcyuEs64m8Ar3snfKjWC2QHcEI/s400/uimapFileAttachedToIDE.JPG" alt="" id="BLOGGER_PHOTO_ID_5386596453523162690" border="0" /></a>
<br />
<br />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.
<br />
<br /><span style="font-weight: bold;">Why UI-Element and why not .properties file?</span>
<br />
<br />There are many advantages to using the UI-Elements approach
<br />
<br />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.
<br />
<br />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.
<br />
<br /><span style="font-weight: bold;">Structure of UI-Element map file</span>
<br />
<br />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.
<br />
<br />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.
<br />
<br />For example in the ui-map below <span style="font-weight: bold;">googleSearch_page</span> is the pageset element and <span style="font-weight: bold;">theBigGoogleLogo</span> is the element within <span style="font-weight: bold;">googleSearch_page</span>. Notice in the addElement method how <span style="font-weight: bold;">googleSearch_page</span> is the first parameter.
<br />
<br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>myMap.addPageset({
<br />name: 'googleSearch_page'
<br />, description: 'google main search page'
<br />, pathRegexp: '.*'
<br />});
<br />
<br />myMap.addElement('googleSearch_page', {
<br />name: 'theBigGoogleLogo'
<br />, description: 'the Google logo visible on the main google search page'
<br />, locator: "logo"
<br />}
<br />);
<br /></code></pre>
<br />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.
<br /><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>var myMap = new UIMap();
<br /></code></pre>
<br />The ‘pathRegexp’ property defined with the pageset element signifies which pages (paths after domain excluding cgi e.g <span style="font-weight: bold;">abc/789</span> in <span style="font-weight: bold;">www.google.com/abc/789 ?lang=en_US</span>) are to be matched with this pageset element.<meta equiv="Content-Type" content="text/html; charset=utf-8"><meta name="ProgId" content="Word.Document"><meta name="Generator" content="Microsoft Word 11"><meta name="Originator" content="Microsoft Word 11"><link rel="File-List" href="file:///C:%5CDOCUME%7E1%5CM%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C02%5Cclip_filelist.xml"><!--[if gte mso 9]><xml> <w:worddocument> <w:view>Normal</w:View> <w:zoom>0</w:Zoom> <w:punctuationkerning/> <w:validateagainstschemas/> <w:saveifxmlinvalid>false</w:SaveIfXMLInvalid> <w:ignoremixedcontent>false</w:IgnoreMixedContent> <w:alwaysshowplaceholdertext>false</w:AlwaysShowPlaceholderText> <w:compatibility> <w:breakwrappedtables/> <w:snaptogridincell/> <w:wraptextwithpunct/> <w:useasianbreakrules/> <w:dontgrowautofit/> </w:Compatibility> <w:browserlevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:latentstyles deflockedstate="false" latentstylecount="156"> </w:LatentStyles> </xml><![endif]--><style> <!-- /* Font Definitions */ @font-face {font-family:"Lucida Console"; panose-1:2 11 6 9 4 5 4 2 2 4; mso-font-charset:0; mso-generic-font-family:modern; mso-font-pitch:fixed; mso-font-signature:-2147482993 6144 0 0 31 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman";} code {font-family:"Courier New"; mso-ascii-font-family:"Courier New"; mso-fareast-font-family:"Times New Roman"; mso-hansi-font-family:"Courier New"; mso-bidi-font-family:"Courier New";} pre {margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Courier New"; mso-fareast-font-family:"Times New Roman";} @page Section1 {size:8.5in 11.0in; margin:1.0in 1.25in 1.0in 1.25in; mso-header-margin:.5in; mso-footer-margin:.5in; mso-paper-source:0;} div.Section1 {page:Section1;} --> </style><!--[if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} </style> <![endif]-->
<br />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.
<br /><meta equiv="Content-Type" content="text/html; charset=utf-8"><meta name="ProgId" content="Word.Document"><meta name="Generator" content="Microsoft Word 11"><meta name="Originator" content="Microsoft Word 11"><link rel="File-List" href="file:///C:%5CDOCUME%7E1%5CM%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"><!--[if gte mso 9]><xml> <w:worddocument> <w:view>Normal</w:View> <w:zoom>0</w:Zoom> <w:punctuationkerning/> <w:validateagainstschemas/> <w:saveifxmlinvalid>false</w:SaveIfXMLInvalid> <w:ignoremixedcontent>false</w:IgnoreMixedContent> <w:alwaysshowplaceholdertext>false</w:AlwaysShowPlaceholderText> <w:compatibility> <w:breakwrappedtables/> <w:snaptogridincell/> <w:wraptextwithpunct/> <w:useasianbreakrules/> <w:dontgrowautofit/> </w:Compatibility> <w:browserlevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:latentstyles deflockedstate="false" latentstylecount="156"> </w:LatentStyles> </xml><![endif]--><style> <!-- /* Font Definitions */ @font-face {font-family:Wingdings; panose-1:5 0 0 0 0 0 0 0 0 0; mso-font-charset:2; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:0 268435456 0 0 -2147483648 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman";} @page Section1 {size:8.5in 11.0in; margin:1.0in 1.25in 1.0in 1.25in; mso-header-margin:.5in; mso-footer-margin:.5in; mso-paper-source:0;} div.Section1 {page:Section1;} /* List Definitions */ @list l0 {mso-list-id:321398277; mso-list-type:hybrid; mso-list-template-ids:-660057578 67698705 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;} @list l0:level1 {mso-level-text:"%1\)"; mso-level-tab-stop:.5in; mso-level-number-position:left; text-indent:-.25in;} @list l1 {mso-list-id:798649306; mso-list-type:hybrid; mso-list-template-ids:-868430130 67698689 67698691 67698693 67698689 67698691 67698693 67698689 67698691 67698693;} @list l1:level1 {mso-level-number-format:bullet; mso-level-text:; mso-level-tab-stop:.5in; mso-level-number-position:left; text-indent:-.25in; font-family:Symbol;} @list l1:level3 {mso-level-number-format:bullet; mso-level-text:; mso-level-tab-stop:1.5in; mso-level-number-position:left; text-indent:-.25in; font-family:Wingdings;} ol {margin-bottom:0in;} ul {margin-bottom:0in;} --> </style><!--[if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} </style> <![endif]-->Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com11tag:blogger.com,1999:blog-1460259750386278518.post-73253747407277763702009-07-26T08:48:00.000-07:002010-02-11T11:07:08.438-08:00Relative locators for elements that change their position with time<span style=";font-family:arial;font-size:100%;" >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 </span><span style=";font-family:times new roman;font-size:100%;" ><a href="http://www.vcdq.com/index.php">here</a></span><span style=";font-family:arial;font-size:100%;" > displays a long list of movie titles.</span><br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhN4gUIOYmMKRfbXTdMFLD9ONAglMrrNAMv773rECcIl8A5OHwKItUfHNY8k-_nKc1KHD6IkkzErbD0M9tOIqJenTvrcGFXg1KEMev7fkNtTVLl-dFpfaJKyhfKp5hMPbvqv8buhqSYdD8/s1600-h/vcdquality+site+cropped+lvl2.PNG"><img style="cursor: pointer; width: 400px; height: 209px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhN4gUIOYmMKRfbXTdMFLD9ONAglMrrNAMv773rECcIl8A5OHwKItUfHNY8k-_nKc1KHD6IkkzErbD0M9tOIqJenTvrcGFXg1KEMev7fkNtTVLl-dFpfaJKyhfKp5hMPbvqv8buhqSYdD8/s400/vcdquality+site+cropped+lvl2.PNG" alt="" id="BLOGGER_PHOTO_ID_5362805262952202866" border="0" /></a><br /><br /><!--[if gte mso 9]><xml> <w:worddocument> <w:view>Normal</w:View> <w:zoom>0</w:Zoom> <w:punctuationkerning/> <w:validateagainstschemas/> <w:saveifxmlinvalid>false</w:SaveIfXMLInvalid> <w:ignoremixedcontent>false</w:IgnoreMixedContent> <w:alwaysshowplaceholdertext>false</w:AlwaysShowPlaceholderText> <w:compatibility> <w:breakwrappedtables/> <w:snaptogridincell/> <w:wraptextwithpunct/> <w:useasianbreakrules/> <w:dontgrowautofit/> </w:Compatibility> <w:browserlevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:latentstyles deflockedstate="false" latentstylecount="156"> </w:LatentStyles> </xml><![endif]--><style> <!-- /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman";} a:link, span.MsoHyperlink {color:blue; text-decoration:underline; text-underline:single;} a:visited, span.MsoHyperlinkFollowed {color:purple; text-decoration:underline; text-underline:single;} @page Section1 {size:8.5in 11.0in; margin:1.0in 1.25in 1.0in 1.25in; mso-header-margin:.5in; mso-footer-margin:.5in; mso-paper-source:0;} div.Section1 {page:Section1;} --> </style><!--[if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} </style> <![endif]--> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">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. </span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><o:p> </o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">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.</span></p><p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><br /></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><o:p> </o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style=";font-size:100%;color:blue;" ><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>clickAndWait //div[@id='content']/table/tbody/tr[17]/td[4]/a/img<br /></code></pre></span></p><p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><br /></span><span style=";font-size:100%;color:blue;" ><o:p></o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><o:p> </o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">As you can see the table row </span><span style=";font-size:100%;color:blue;" >tr[17]</span><span style="font-size:100%;"> 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’.</span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><o:p> </o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">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.</span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><o:p> </o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">If the locators are xpath expressions then this can be done using the ‘xpath axes’. </span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><a href="http://www.w3schools.com/XPath/xpath_axes.asp">W3school</a> has an excellent tutorial on XPATH axes that can be found <a href="http://www.w3schools.com/XPath/xpath_axes.asp">here</a>.</span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><o:p> </o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">I will try to demonstrate how to derive a relative xpath expression which will stand the test of time.</span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-weight: bold;font-size:100%;" >1. </span><span style="font-size:100%;">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 </span><span style=";font-size:100%;color:blue;" >Harry Potter The Half Blood Prince *XVID*’. <o:p></o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-weight: bold;font-size:100%;" >2.</span><span style="font-size:100%;"> Now let us build a locator that point to the movie title text. Right click on the movie title ‘</span><span style=";font-size:100%;color:blue;" >Harry Potter The Half Blood Prince *XVID*’</span><span style="font-size:100%;">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 <a href="https://addons.mozilla.org/en-US/firefox/addon/1095">here</a>. </span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">In XPath Checker window the XPath displayed is </span><span style=";font-size:100%;color:blue;" >id('content')/table/tbody/tr[17]/td[3]/a.<o:p></o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style=";font-size:100%;color:blue;" ><o:p> </o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-weight: bold;font-size:100%;" >3.</span><span style="font-size:100%;"> We need to tweak this XPath expression to our requirement. Please remember that the XPath expression that we need must <b style="">not </b>have hard-coded row position but it’s ok to have a hard-coded column position because the column position will never change. </span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">So lets start by removing the row position from the xpath expression in the Xpath Checker window. </span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">Now we are left with </span><span style=";font-size:100%;color:blue;" >id('content')/table/tbody/tr/td[3]/a<o:p></o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">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.</span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">We can also get rid of the ‘</span><span style=";font-size:100%;color:blue;" >/a’ </span><span style="font-size:100%;">from the expression since we are more interested in the textual contents of that cell and not the anchor tag.</span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">So now we have </span><span style=";font-size:100%;color:blue;" >id('content')/table/tbody/tr/td[3]</span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">The next step would be to tweak the expression further such that it matches only the required row i.e the row that contains ‘</span><span style=";font-size:100%;color:blue;" >Harry Potter The Half Blood Prince *XVID*’ </span><span style="font-size:100%;">in the 3<sup>rd</sup> column</span><span style=";font-size:100%;color:blue;" > </span><span style="font-size:100%;">and not all the rows. To achieve this a node() predicate can be used in the following way</span></p><p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><br /></span></p> <p class="MsoNormal" style="font-family:trebuchet ms;"><span style=";font-size:100%;color:blue;" ><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>id('content')/table/tbody/tr/td[3][node()='Harry Potter The Half Blood Prince *XVID*'] <br /></code></pre></span></p><p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><br /></span><span style=";font-size:100%;color:blue;" ><o:p></o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><o:p> </o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">Now we have uniquely identified the row that contains our element and are currently pointing to the column that has the text</span><span style=";font-size:100%;color:blue;" > </span><span style="font-size:100%;">‘</span><span style=";font-size:100%;color:blue;" >Harry Potter The Half Blood Prince *XVID*’ <span style="color: rgb(51, 51, 51);">in that row. </span><o:p></o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">The JPG image/button resides one cell away from here. </span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">To move in same row one cell to the right we need to use the XPath axes ‘</span><span style=";font-size:100%;color:blue;" >following-sibling’</span><span style="font-size:100%;">.</span><span style=";font-size:100%;color:blue;" > </span><span style="font-size:100%;">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</span></p><p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><br /></span></p> <p class="MsoNormal" style="font-family:trebuchet ms;"><span style=";font-size:100%;color:blue;" ><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>id('content')/table/tbody/tr/td[3][node()='Harry Potter The Half Blood Prince *XVID*']/following-sibling::td[1] <br /></code></pre></span></p><p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><br /></span><span style=";font-size:100%;color:blue;" ><o:p></o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">The XPath Checker would show just one match that is the JPG image/button.</span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><o:p> </o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">To make this XPath expression work in selenium IDE append ‘</span><span style=";font-size:100%;color:blue;" >xpath=</span><span style="font-size:100%;">’ to the beginning of the XPath expression derived above and voila it works.</span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><o:p> </o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">So finally the XPath expression that matches our requirement is</span></p><p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><br /></span><span style="font-size:100%;"> </span></p> <p class="MsoNormal" style="font-family:trebuchet ms;"><span style=";font-size:100%;color:blue;" ><span style=""><pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"><code>xpath=id('content')/table/tbody/tr/td[3][node()='Harry Potter The Half Blood Prince *XVID*']/following-sibling::td[1] <br /></code></pre></span></span></p><p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><br /></span><span style=";font-size:100%;color:blue;" ><o:p></o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style=";font-size:100%;color:blue;" ><o:p> </o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style=";font-size:100%;color:blue;" >ancestor, descendant, following, preceding, preceding-sibling</span><span style="font-size:100%;"> are 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.</span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;"><o:p> </o:p></span></p> <p class="MsoNormal" style="font-family:arial;"><span style="font-size:100%;">Also please note that '</span><span style=";font-size:100%;color:blue;" >Harry Potter The Half Blood Prince *XVID*</span><span style="font-size:100%;">' 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.</span></p>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com8tag:blogger.com,1999:blog-1460259750386278518.post-14308071870846089572009-07-25T12:16:00.000-07:002009-07-26T09:33:15.670-07:00xpath not working in selenium RC? 'descendant' axes to the rescueYou will encounter many instances where the xpath expression for an element works perfectly well in IDE but won't work in Selenium RC. Also there will be instances where the xpath expression works well in IDE and RC for the chrome, firefox browser's but won't work in internet explorer. I will now demonstrate one such case.<br />Navigate to <a href="http://clearspace.openqa.org/index.jspa">openQA forum</a> . Now lets say that you wish to click on the 3rd instance of the image that has <span style="color: rgb(51, 102, 255);">"/avatar/22.png?a=-1"</span> in it's src tag. I'm talking about member icon next to every thread on the left hand side. See below, the image i'm taking about is highlighted in red.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNB7sgYRG88OQR6BedgLuwc-K0jYczuVaOsf7Yion5E1NQwltUQr-EBn1AQQgZ-fn22rdVzGSDqHD6f7rHtirl7NQd1TrIuxBQslQwjeOEgXqDmjesX5j33CzX9tGkiWhEycf0f66Tiyg/s1600-h/openQA+descendant+example.PNG"><img style="cursor: pointer; width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNB7sgYRG88OQR6BedgLuwc-K0jYczuVaOsf7Yion5E1NQwltUQr-EBn1AQQgZ-fn22rdVzGSDqHD6f7rHtirl7NQd1TrIuxBQslQwjeOEgXqDmjesX5j33CzX9tGkiWhEycf0f66Tiyg/s400/openQA+descendant+example.PNG" alt="" id="BLOGGER_PHOTO_ID_5362482153358796690" border="0" /></a><br /><br />Now the xpath for this element would be<br /><span style="color: rgb(51, 102, 255);">xpath=(//img[contains(@src,'/avatar/22.png?a=-1')])[3]<br /><span style="color: rgb(51, 51, 51);">I used firebug to determine that all such images on this page contain </span></span><span style="color: rgb(51, 51, 51);">"/avatar/22.png?a=-1" in their src tag.</span><br /><br />now if you enter the instruction<br /><span style="color: rgb(102, 102, 204);font-family:trebuchet ms;" >click</span><span style="font-family:trebuchet ms;"> </span><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" >xpath=(//img[contains(@src,'/avatar/22.png?a=-1')])[3]</span><br />in IDE and click the find button it will highlight the image of our interest. And when you run the script it will promptly click on this image and take you to the profile page of that member whoever that may be.<br /><br />The problem arises when you try to run this in RC. Below is the test method that tries to do the same.<br /><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" >import com.thoughtworks.selenium.*;</span><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" >import org.testng.annotations.*;</span><br /><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" >public class TestContainsPredicateInXPATH {</span><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" > @Test public void clickThirdMemberImage() throws Exception {</span><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" > DefaultSelenium selenium =new DefaultSelenium("localhost",4444,"*firefox","http://clearspace.openqa.org");</span><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" > selenium.start();</span><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" > selenium.open("/index.jspa");</span><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" > selenium.waitForPageToLoad("90000");</span><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" > <span style="font-weight: bold;"> selenium.click("xpath=(//img[contains(@src,'/avatar/22.png?a=-1')])[3]");</span></span><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" > </span><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" >selenium.waitForPageToLoad("90000");</span><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" > selenium.close();</span><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" > </span><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" > }</span><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" >}</span><br /><br />When you run this it will throw the error<br /><span style="color: rgb(255, 102, 102);">ERROR: Element xpath=(//img[contains(@src,'/avatar/22.png?a=-1')])[3] not found</span><br /><br />to make this work we need to tweak the xpath a little to<br /><br /><span style="color: rgb(51, 102, 255);font-family:trebuchet ms;" >xpath=/descendant::img[contains(@src,'/avatar/22.png?a=-1')][3]</span><br /><br />In the above expression the '//' have been replaced with '<span style="color: rgb(51, 102, 255);">/descendant::<span style="color: rgb(51, 51, 51);">'</span></span> and the simple brackets after the '=' expression is gone. so the instruction now becomes<br /><br /><span style="font-weight: bold;font-size:85%;" ><span style="color: rgb(51, 102, 255);">selenium.click("xpath=/descendant::img[contains(@src,'/avatar/22.png?a=-1')][3]");</span></span><br /><br />Give it a try and it will work like a charm. This fix is needed whenever your xpath expressions contains functions such as 'contains', 'start-with' etc. I would recommend using <span style="color: rgb(51, 102, 255);">/descendant <span style="color: rgb(51, 51, 51);">axis </span></span><span style="color: rgb(51, 102, 255);"><span style="color: rgb(51, 51, 51);">instead of '//' </span></span><span style="color: rgb(51, 102, 255);"><span style="color: rgb(51, 51, 51);">on all xpath expressions that start with '//' .</span><br /></span>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com4tag:blogger.com,1999:blog-1460259750386278518.post-17517491867943259662009-03-28T02:59:00.000-07:002009-04-05T10:41:59.808-07:00Getting rid of ugly large white space above table in blogger or blogspot posts<a href="http://www.bloggertipsandtricks.com/2007/06/avoid-large-white-space-above-table-in.html">click here to know how</a>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com0tag:blogger.com,1999:blog-1460259750386278518.post-34457703241154822992009-03-24T04:03:00.000-07:002009-03-24T04:06:25.492-07:00RC with testng and eclipse - Folder structure<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGYqbxecLqn5KklgEXCBC5gi_oEkTwMzZ7iBWsw9fZf8qFtiW8kNCFswuw4DXZhn9yFCZ7oslO-HQJiLfTp8iWegoqmqAQu6pu-wkaQrniCsRG8nqi5GyRUdeVVErVhSjKCFKjylzeu_E/s1600-h/eclipseTestngStructure.PNG"><img style="cursor: pointer; width: 400px; height: 300px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGYqbxecLqn5KklgEXCBC5gi_oEkTwMzZ7iBWsw9fZf8qFtiW8kNCFswuw4DXZhn9yFCZ7oslO-HQJiLfTp8iWegoqmqAQu6pu-wkaQrniCsRG8nqi5GyRUdeVVErVhSjKCFKjylzeu_E/s400/eclipseTestngStructure.PNG" alt="" id="BLOGGER_PHOTO_ID_5316708655393485298" border="0" /></a><br />Screen-shot of the eclipse windowMahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com0tag:blogger.com,1999:blog-1460259750386278518.post-36379567179153038382009-03-14T01:59:00.000-07:002009-03-16T00:51:54.509-07:00Instructions to download nightly builds of selenium RCNew features and bug fixes are added regularly to the nightly builds and finally after a bunch of them has been incorporated a new version of selenium is released. It can be a long while before a new release comes out some times it can be as long as a year. If you can't wait that long for a bug fix or a new feature then you would want to get hold of the latest nightly build. As the name suggests such a build is posted in the public repository every night. Sadly downloading a nightly-build of selenium RC is not as easy and straightforward as it should be. It can be very confusing and frustrating especially for someone who is new to the world of selenium.<br /><br />Instructions to download Selenium RC nightly build<br />Navigate to http://seleniumhq.org/download/nightly.html<br />click <span style="font-weight: bold;">Maven repository</span><br />click <span style="font-weight: bold;">OpenQA Nexus Repository Manager</span><br />click <span style="font-weight: bold;">Browse Repositories </span>link on to the left<br />Click Snapshots<br />Navigate to the latest build in the <span style="font-weight: bold;">Repository Content</span> section below.<br />Snapshots-->org-->seleniumhq-->selenium-->selenium-remote-control-->1.0-SNAPSHOT<br />If 1.0-SNAPSHOT is not the latest build then click on the snapshot version that is the latest build.<br />Right click the latest dist zip file that has the name in the following format<br />selenium-remote-control-1.0-20090312.011253-61-dist.zip and click download from the drop down options.<br /><br />Following is an url of nightly build.<br />http://nexus.openqa.org/content/repositories/snapshots/org/seleniumhq/selenium/seleniu<br />m-remote-control/1.0-SNAPSHOT/selenium-remote-control-1.0-20090312.011253-61<br />-dist.zipMahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com2tag:blogger.com,1999:blog-1460259750386278518.post-34958990540351658852009-01-09T05:36:00.000-08:002009-08-09T22:31:15.205-07:00Code to Identify an element on the basis of it's any dom attribute and index<span style="color: rgb(51, 51, 255);"><span style="color: rgb(0, 0, 0);">use firebug to identify the attributes and their values</span><br /><br /><br /><br />function getLocator(elementClassName,attributeName,attribtePtrn,elemIndex){</span><br /><span style="color: rgb(51, 51, 255);">var allInputArray = new Array();</span><br /><span style="color: rgb(51, 51, 255);">var requiredElement;</span><br /><span style="color: rgb(51, 51, 255);">allInputArray=document.getElementsByTagName(elementClassName);</span><br /><span style="color: rgb(51, 51, 255);">var i=0;</span><br /><span style="color: rgb(51, 51, 255);">var index=0;</span><br /><span style="color: rgb(51, 51, 255);">var requiredIndex=elemIndex;</span><br /><br /><span style="color: rgb(51, 51, 255);">var pattrn=new RegExp("^"+attribtePtrn+"$");</span><br /><br /><span style="color: rgb(51, 51, 255);"> for(i=0; i</span><allinputarray.length;><br /><span style="color: rgb(51, 51, 255);"> if (pattrn.test(allInputArray[i].getAttribute(attributeName))){</span><br /><span style="color: rgb(51, 51, 255);"> if (index==requiredIndex){</span><br /><span style="color: rgb(51, 51, 255);"> requiredElement=allInputArray[i];</span><br /><span style="color: rgb(51, 51, 255);"> break;}</span><br /><span style="color: rgb(51, 51, 255);"> index=index+1;</span><br /><span style="color: rgb(51, 51, 255);"> }</span><br /> <br /><span style="color: rgb(51, 51, 255);">}</span><br /><br /><span style="color: rgb(51, 51, 255);">return requiredElement;</span><br /><span style="color: rgb(51, 51, 255);">}</span><br /><br /><span style="color: rgb(51, 51, 255);">//function call</span><br /><span style="color: rgb(51, 51, 255);">getLocator("input","id","[a-c]{1}al00_mc_Chec.*",16);</span><br /></allinputarray.length;>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com1tag:blogger.com,1999:blog-1460259750386278518.post-5074015448523911112008-12-16T03:56:00.000-08:002008-12-16T04:00:52.451-08:00Another way to get XPATH in Internet ExplorerNavigate to the page in Internet explorer. Save the page on your local machine with suitable name . IE will create a folder and a html file with the name you have given. Now open this html file in firefox. Now you can use xpath-checker or xpather to get the xpath of the element in this page.Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com2tag:blogger.com,1999:blog-1460259750386278518.post-46484929477727588472008-12-15T09:30:00.000-08:002008-12-15T09:41:41.682-08:00Select one of many similar elements by index in Selenium?Imagine there are 10 web buttons on the page. All have the id <span style="font-style: italic;">button</span> followed by a dynamic number. So the buttons would have id button12234, button12235,button12236 and so on. Now if you wish to select the second button from the top of the page.<br />Easy to this in QTP. <span style="color: rgb(0, 0, 153);">Browser().Page().WebButton().Click("htmlid:=button.*","index:=1") </span>should do the job.<br />In selenium use the following<br /><span style="font-family: arial; color: rgb(0, 0, 153);font-size:100%;" ><span style="font-size: 12pt;"><strong><span style="font-size: 12pt;"></span></strong></span></span><span style="color: rgb(0, 0, 153);">xpath=(//input[contains(@id,'button')])[2]</span><br /><br />The prefix <span style="color: rgb(0, 0, 153);">xpath=</span> is essential or this expression won't work.Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com7tag:blogger.com,1999:blog-1460259750386278518.post-65087733815585516832008-12-15T08:27:00.000-08:002008-12-15T20:35:05.248-08:00Way to get XPATH in Internet ExplorerAre you stuck with an application that only works in IE?<br />Do you want the XPATH of an element that can be seen only IE? Unable to replicate the scenario in firefox. There are many firefox addons like xpather, xpath-checker and firebug that will give you the xpath of an element in a second. But sadly there is no addon or tool avaialable that will do this for IE. For most cases you can get the xpath of the elements that fall in your script using the above tools in firefox and tweak them a little (if required) to make them work in IE. But if you are testing an application that will work only in IE or the specific scenario or page that has this element will open-up/play-out only in IE then you cannot use any of the above mentione tools to find the XPATH.<br />Well the only thing that works in this case is the Bookmarklets that were coded just for this purpose. Bookmarklets are JavaScript code that you will add in IE as bookmarks and later use to get the XPATH of the element you desire. Using these you can get the XPATH as easily as you get using xpather or any other firefox addon.<br /><br />STEPS TO INSTAL BOOKMARKLETS<br />1)Open IE<br />2)Type <span style="font-style: italic; color: rgb(204, 102, 204);">about:blank</span> in the address bar and hit enter<br />3)From Favorites main menu select--->Add favorites<br />4) In the Add a favorite popup window enter name <span style="font-style: italic;">GetXPATH1</span>.<br />5)Click add button in the add a favorite popup window.<br />6)Open the Favorites menu and right click the newly added favorite and select properties option.<br />7)GetXPATH1 Properties will open up. Select the web Document Tab.<br />8)Enter the following in the URL field.<br /><br /><code style="color: rgb(0, 0, 153);"><span style="font-family:Georgia,serif;">javascript:function getNode(node){var nodeExpr=node.tagName;if(!nodeExpr)return null;if(node.id!=''){nodeExpr+="[@id='"+node.id+"']";return "/"+nodeExpr;}var rank=1;var ps=node.previousSibling;while(ps){if(ps.tagName==node.tagName){rank++;}ps=ps.previousSibling;}if(rank>1){nodeExpr+='['+rank+']';}else{var ns=node.nextSibling;while(ns){if(ns.tagName==node.tagName){nodeExpr+='[1]';break;}ns=ns.nextSibling;}}return nodeExpr;}</span></code><br /><br />9)Click Ok. Click YES on the popup alert.<br />10)Add another favorite by following steps 3 to 5, Name this favorite GetXPATH2 (step4)<br />11)Repeat steps 6 and 7 for GetXPATH2 that you just created.<br />12)Enter the following in the URL field for GetXPATH2<br /><br /><span style="color: rgb(0, 0, 153);">javascript:function o__o(){var currentNode=document.selection.createRange().parentElement();var path=[];while(currentNode){var pe=getNode(currentNode);if(pe){path.push(pe);if(pe.indexOf('@id')!=-1)break;}currentNode=currentNode.parentNode;}var xpath="/"+path.reverse().join('/');clipboardData.setData("Text", xpath);}o__o();</span><br /><br />13)Repeat Step 9.<br /><br />You are all done!!<br /><br />Now to get the XPATH of elements just select the element with your mouse. This would involve clicking the left mouse button just before the element (link, button, image, checkbox, text etc) begins and dragging it till the element ends. Once you do this first select the favorite GetXPATH1 from the favorites menu and then select the second favorite GetXPATH2. At his point you will get a confirmation, hit allow access button. Now open up a notepad file, right click and select paste option. This will give you the XPATH of the element you seek.<br /><br /><br /><span style="font-family:monospace;">*I got this bookmarklets from some other site but can't remember which one. Credit goes to the guy who created these JS.<br /><br /></span>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com273tag:blogger.com,1999:blog-1460259750386278518.post-92200710584577557132008-11-13T00:49:00.000-08:002008-11-13T01:06:18.273-08:00Framework idea from Google conferenceHere is a presentation of a framework built around Selenium. I think this team presented it in Google testing conference. Click on <span style="font-style: italic;">iPaper</span> menu and select <span style="font-style: italic;">save document </span><span>to save it as PDF.</span><br /><br /><a title="View GTAC_SeleniumFramework document on Scribd" href="http://www.scribd.com/doc/7949401/GTACSeleniumFramework" style="margin: 12px auto 6px; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 14px; line-height: normal; font-size-adjust: none; font-stretch: normal; display: block; text-decoration: underline;">GTAC_SeleniumFramework</a> <object codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" id="doc_472520471842499" name="doc_472520471842499" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" align="middle" height="500" width="100%"> <param name="movie" value="http://documents.scribd.com/ScribdViewer.swf?document_id=7949401&access_key=key-946x5lm754hhahra273&page=1&version=1&viewMode="> <param name="quality" value="high"> <param name="play" value="true"> <param name="loop" value="true"> <param name="scale" value="showall"> <param name="wmode" value="opaque"> <param name="devicefont" value="false"> <param name="bgcolor" value="#ffffff"> <param name="menu" value="true"> <param name="allowFullScreen" value="true"> <param name="allowScriptAccess" value="always"> <param name="salign" value=""> <embed src="http://documents.scribd.com/ScribdViewer.swf?document_id=7949401&access_key=key-946x5lm754hhahra273&page=1&version=1&viewMode=" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" play="true" loop="true" scale="showall" wmode="opaque" devicefont="false" bgcolor="#ffffff" name="doc_472520471842499_object" menu="true" allowfullscreen="true" allowscriptaccess="always" salign="" type="application/x-shockwave-flash" align="middle" height="500" width="100%"></embed> </object> <div style="margin: 6px auto 3px; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 12px; line-height: normal; font-size-adjust: none; font-stretch: normal; display: block;"> <a href="http://www.scribd.com/upload" style="text-decoration: underline;">Get your own</a> at Scribd or <a href="http://www.scribd.com/browse" style="text-decoration: underline;">explore</a> others: <a href="http://www.scribd.com/tag/selenium%20framework%20idea%20presented%20in%20google%20conference" style="text-decoration: underline;">selenium framework i</a> </div>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com1tag:blogger.com,1999:blog-1460259750386278518.post-5720316807329611472008-10-22T05:29:00.000-07:002009-10-14T20:32:30.277-07:00QTP vs Selenium - my takeThis is a little comparison I did of the two premier tools in the market.<br /><style type="text/css">.nobrtable br { display: none }</style><br /><div class="nobrtable"><br /><table align="center" border="2" bordercolor="#000000" cellpadding="3" cellspacing="0" width="100%"><br /><tbody><tr><br /><td><strong>SNO</strong></td><br /><td><strong>Features</strong></td><br /><td><strong>QTP</strong></td><br /><td><strong>Selenium</strong></td><br /><td><strong>Explanation</strong></td></tr><br /><br /><tr><br /><td>1</td><br /><td>Actual end user simulation, Is the test conducted<br />using this tool equivalent to an end user action?</td><br /><td>YES</td><br /><td>NO</td><br /><td>Selenium performs actions in the background on the<br />browser. It modifies the DOM structure of the HTML page in order to<br />perform actions on the page. To be more precise it executes javascript on UI objects within the webpage to perform actions like click, type, select etc. This is the reason why you can execute tests<br />with the browser minimized. QTP claims to perform end user simulation, in other words executing QTP scripts is equivalent to a person performing those steps manually on the application.<br /></td></tr><br /><br /><br /><tr><br /><td>2</td><br /><td>Support for most UI Components</td><br /><td>YES</td><br /><td>YES</td><br /><td>Certain events, methods and Object properties are<br />not supported by selenium. But broadly most UI components are<br />supported. QTP requires extra addins (plugins, not free) to work with dotNet components.<br /></td></tr><br /><br /><tr><br /><td>3</td><br /><td>UI-Object management & storage</td><br /><td>YES</td><br /><td>NO</td><br /><td>QTP comes built-in with object repository. Object<br />repository management is quite easy in QTP. Selenium has no such built in<br />feature but objects can be managed using UI-Element user extension. Other custom solutions like properties files can also be used in selenium. But for all such solutions the<br />map file in selenium has to be hand-coded i.e unlike QTP the objects won't be recorded/added automatically .</td></tr><br /><br /><br /><tr><br /><td>4</td><br /><td>Support for Dialog Boxes</td><br /><td>YES</td><br /><td>NO</td><br /><td><br />QTP supports all kinds of IE<br />dialog boxes. There is partial support for dialog boxes in Selenium.<br />Some actions like retrieving the tittle of he dialog box can't be performed in selenium<br /></td></tr><br /><br /><tr><br /><td>5</td><br /><td>Support for file upload scenario</td><br /><td>YES</td><br /><td>NO</td><br /><td><br />This is the scenario where you upload a file located in your local machine onto the application using 'browse file' dialog or something similar. Selenium does not support this scenario due to JavaScript restriction. QTP has no problem whatsoever simulating this scenario.<br /></td></tr><br /><br /><tr><br /><td>6</td><br /><td>Support for web browsers</td><br /><td>YES</td><br /><td>YES</td><br /><td>QTP supports IE & Firefox. Selenium supports<br />IE, Firefox, Safari and Opera and a few more browsers. But either tools are far far away from full cross-browser support. Don't expect scripts created using browser to run flawlessly in another browser.<br /></td></tr><br /><br /><br /><tr><br /><td>7</td><br /><td><br />Object Recognition Parameters, Recognition on the<br />basis of WYSWYG (what you see is what you get)<br /></td><br /><td>YES</td><br /><td>NO</td><br /><td>Selenium recognizes objects on the basis of the<br />DOM structure of the HTML Page. The UI objects in selenium have vague<br />descriptions and don't comply with WYSWYG policy. QTP recognises and names objects based on properties which are more visible and obvious and are hence the objects have user friendly names.<br /></td></tr><br /><br /><br /><tr><br /><td>8</td><br /><td>Object Oriented Language support &<br />Scalability (as in Integration with External tools utilities and libraries).</td><br /><td>NO</td><br /><td>YES</td><br /><td>Selenium Supports JAVA, dot net and many other<br />industry standard programming languages. QTP supports vb script only.</td></tr><br /><br /><tr><br /><td>9</td><br /><td>Integration with test management tool</td><br /><td>With HP Quality Center and TestDirector </td><br /><td>No</td><br /><td>QTP integrates seamlessly with QC and TD. Test management and mapping the manual testing process with automation becomes a lot easier with this integration. I have not yet heard of any test management tool that can integrate seamlessly with Selenium. keep an eye out for Bromide though. </td></tr><br /><br /><br /><tr><td>10</td><br /><td><br /><span style="color: rgb(0, 0, 0);"><br />Types of application supported</span></td><br /><td>Web,Windows(DotNet,VB, Powerbuilder, TCL/TK), Terminal Emulation, Command prompt</td><br /><td>Web Only</td><br /><td>QTP wins this one hands down. This is one of the main reason why selenium can't even be considered in many cases. Imagine real-time applications like trading terminals, risk management applications built in TCL/TK and powerbuilder. QTP supports most of these interfaces. Selenium on the other hand can work only on applications that open up inside a browser. But aren't most applications moving to the browser based platform? :)</td></tr><br /><tr><br /></tr><br /><br /><tr><br /><td>11</td><br /><td>Support for operating system/platforms</td><br /><td>NO</td><br /><td>YES</td><br /><td>Selenium Supports JAVA and hence can be used in Windows PC or MAC or UNIX. Using selenium you can test your web application in all the above platforms. QTP supports Windows only.</td></tr><br /><br /><tr><br /><td>12</td><br /><td><br />Ease of creation of Scripts<br /></td><br /><td>Excellent</td><br /><td>Good</td><br /><td>Selenium IDE Recorder is not as powerful as QTP<br />but is good for a free tool, many actions are not recorded by the IDE and<br />have to be manually entered.</td></tr><br /><br /><br /><tr><br /><td>13</td><br /><td><br /><span style="color: rgb(0, 0, 0);"><br />Technical Support</span></td><br /><td>YES</td><br /><td>NO</td><br /><td>QTP offers technical support by phone and mail, HP also have a web-forum.<br />QTP user community is vast and questions posted on online forums get<br />answered quickly. Selenium being an open source tool has no official tech<br />support, the user community is small, less-active and questions on forums<br />seldom get answered. But the community is growing day by day as the tool gains acceptance.<br /></td></tr><br /><br /><br /><tr><br /><td>14</td><br /><td><br /><span style="color: rgb(0, 0, 0);"><br />Cost</span></td><br /><td>Costly, $5,000 per seat license when i last checked</td><br /><td>Free</td><br /><td>Many people want to switch to selenium because it's free. But cost isn't really a factor when your client's a investment bank :)<br /></td></tr><br /><br /><tr><td>15</td><br /><td><br /><span style="color: rgb(0, 0, 0);"><br />Test Development Environment</span></td><br /><td>Reasonable but not the best</td><br /><td>Best in the world</td><br /><td>When you are working on selenium you have the option of using wide range of IDEs like Eclipse, Netbeans, Visual Studio etc depending on your choice of development language. If you are a developer then you must have developed a taste for rich IDEs and switching to a environment given by a test tool may be hard for you. QTP tests can only be developed in QTP.</td></tr><br /><br /><tr><td>16</td><br /><td><br /><span style="color: rgb(0, 0, 0);"><br />Integration with development process</span></td><br /><td>No real integration possible</td><br /><td>Yes</td><br /><td>Tests developed using selenium can be easily part of the development project. Using tools like cruise control Continuous Integration is easier with Selenium. But don't get too caught up with this feature, it's really not that important to be integrated with the development process but it's nice to have.<br /></td></tr><br /><br /><tr><td>17</td><br /><td><br /><span style="color: rgb(0, 0, 0);"><br />Future in terms of usability and acceptance</span></td><br /><td>Will have it's presence in non-web based application testing</td><br /><td>Will be the market leader in web application testing</td><br /><td>The future bodes well for selenium because it's free, supports all programming languages/platforms and is immensely scalable and expandable due to it being free and open source. Many pundits have predicted that it will completely conquer the web testing market in the next 5 years. It being free makes a huge difference especially when times are hard like what we have now. QTP on the other hand is the current market leader and I think that it will have it's presence for long due to it's user friendliness and support for interfaces other than web.</td></tr><br /></tbody></table><p></p><br /></div>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com152tag:blogger.com,1999:blog-1460259750386278518.post-3973853965383258692008-08-26T01:26:00.000-07:002009-07-27T12:35:27.767-07:00Gather requirements : Functional testing questionnaire<p style="margin-bottom: 0in;">This is a set of questions/questionnaire for one of my friend's client to gather their requirements for functional test automation. Thought I would share with you.<br /></p><p style="margin-bottom: 0in; font-weight: bold;">Functional Test Automation – Requirements gathering</p> <p style="margin-bottom: 0in;"><span style="font-weight: bold;">Questionnaire for client</span> </p><br />1) What is the frequency of change of business rules of the Application (number of change requests/week)?<br /><br />2) What is the frequency of change of UI of the Application (number of change requests/week)?<br /><p style="margin-bottom: 0in;"> 3) Do you have a manual regression test suite? If Yes</p> <p style="margin-bottom: 0in;">a) What percentage of application functionality does it cover?<br />b) How many test cases are their?<br />c)How well described are the cases? Can a computer literate person having no knowledge of your application execute these cases?<br />d) How long does it take to run 1 full cycle in terms of man days(8 hrs a day)?<br />e) Where are the test cases stored?<br />f) Can you share a test plan with us?</p> <p style="margin-bottom: 0in;">4)How do you set the test environment? What are the requirements in terms of Hardware and Software? Will you let us host the application in our company premises?</p> <p style="margin-bottom: 0in;">5What is your requirement/expectation from Functional Testing Automation? What percentage of the regression suite do you expect to get automated?</p> <p style="margin-bottom: 0in;">6) What is lacking in the present manual testing process you wish to complement/improve through functional testing automation?</p> <p style="margin-bottom: 0in;">7) What protocol is used to access the application? Example http,https.</p> <p style="margin-bottom: 0in;">8) Can we access the Application directly over the web or Access is available only through VPN?<br /></p> <p style="margin-bottom: 0in;"><br /></p>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com2tag:blogger.com,1999:blog-1460259750386278518.post-89284030916485651572008-08-21T10:48:00.000-07:002008-08-21T11:45:58.345-07:00Ridiculously overpriced version of iPhone launched in India<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKFoo-v_cQZCue0ZaTJAmP3i_I7lE7XRtfCmmFsAuFX8pHC1mek_yDXmmCXYhAGdrx_2f7d2-XyWbdWYr4NJ7isjjpGS5GocyIbHbb9lU2kD23tIUcduAamOCN5Jrt5wez7nNnySF2QuA/s1600-h/modeliphone.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKFoo-v_cQZCue0ZaTJAmP3i_I7lE7XRtfCmmFsAuFX8pHC1mek_yDXmmCXYhAGdrx_2f7d2-XyWbdWYr4NJ7isjjpGS5GocyIbHbb9lU2kD23tIUcduAamOCN5Jrt5wez7nNnySF2QuA/s200/modeliphone.jpg" alt="" id="BLOGGER_PHOTO_ID_5237032858773788770" border="0" /></a><br />What costs $199 in U.S will cost $720 or Rs. 31,000 in India. This is ridiculous! The phone is marketed by Airtel and vodaphone.Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com0tag:blogger.com,1999:blog-1460259750386278518.post-12879269222697323892008-08-20T10:24:00.000-07:002008-08-20T10:42:32.410-07:00Acer Aspire One - Sleek and affordable<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5MnEhAZ3hX2XeLCSLthe_gAAuwfDjWpdtqSqpjZHvI2zhdfxW0_ZqBbHgnQP9fTohDLMLNtH5P48jsme2sHLgb3XtZzsgjsISsndVGWzJp1FiFKRArt-mo5yf3NEtwfbt35u78t9lNhg/s1600-h/acer_aspire_one1_500x333.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5MnEhAZ3hX2XeLCSLthe_gAAuwfDjWpdtqSqpjZHvI2zhdfxW0_ZqBbHgnQP9fTohDLMLNtH5P48jsme2sHLgb3XtZzsgjsISsndVGWzJp1FiFKRArt-mo5yf3NEtwfbt35u78t9lNhg/s200/acer_aspire_one1_500x333.jpg" alt="" id="BLOGGER_PHOTO_ID_5236655910560341442" border="0" /></a> <a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfP2SAaS9wTCHO9xzjF28e_17np1nvhc3cqTpTu5l9bUQU6HX23zjnZvy3dbf5BdAyRdWg51z3hGG0LcXoFe98_AnjAvzmpAn3ddw_hsYnDBSGh_2luSNxCHea39AbT7PgO4cImy2HkyM/s1600-h/aspireone_main540.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfP2SAaS9wTCHO9xzjF28e_17np1nvhc3cqTpTu5l9bUQU6HX23zjnZvy3dbf5BdAyRdWg51z3hGG0LcXoFe98_AnjAvzmpAn3ddw_hsYnDBSGh_2luSNxCHea39AbT7PgO4cImy2HkyM/s200/aspireone_main540.jpg" alt="" id="BLOGGER_PHOTO_ID_5236655914149075634" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br />This has been launched in India and is priced at around Rs.22,000. It is available only in chroma stores. I found some reviews and comparisons of this baby and some other sub-notebooks on youtube.<br />1) <a href="http://in.youtube.com/watch?v=0CuxV-jsrk8">Comparison of Acer Aspire One, Asus Eee 901, HP 2133, MSI Wind Hands On</a><br />2) <a href="http://in.youtube.com/watch?v=0ShPGRQE3qE">Review by Kat and Dan</a><br />3) <a href="http://in.youtube.com/watch?v=ZhvVd0NrxWg">Shows the Acer Aspire One playing video</a>Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com0tag:blogger.com,1999:blog-1460259750386278518.post-2447837500219983852008-08-16T10:56:00.000-07:002008-11-09T05:26:25.771-08:00Selenium: Recovery using try catchAll Test tools have a way to handle unexpected events like a popup alert or <span>a</span><span style="font-style: italic;"> page not found </span>error. Like for example in QTP there is something called the recovery scenario manager. Here one could define a bunch of scenarios, one for each unexpected event and the recovery action to be taken if and when such an event presents itself. This would be something like if there is an <span>pop-up alert with text </span><span style="font-style: italic;">"Session expired. Do you want to re-login?"</span> then <span style="font-style: italic;">Click OK </span>on the dialog box (this takes you to login page) and <span style="font-style: italic;">Login</span> again.<br /><br />Anyone who is serious of test automation would want to build a sturdy set of recovery scenarios.<br /><br />So what do you do in case of selenium?<br />Not to worry. This feature could be easily imitated by a simple Try-catch block within your Selenium RC Java tests.<br /><br /><span style="font-style: italic; color: rgb(51, 102, 255);">Class Test1{</span><br /><br /><span style="font-style: italic; color: rgb(51, 102, 255);">public Test1(){</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">try{</span><br /><br /><span style="font-style: italic; color: rgb(51, 102, 255);">browser.click("link=Start");</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">browser.type("Title","Mr.");</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">//unexpected dialog pops-up here</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">browser.type("FirstName","John");</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">}</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">catch(Exception e)</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">{</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">recoveryModule.invokeRecovery(e.getMessage);</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">}</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">}</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">}//end of test case</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">//end of class</span><br /><br /><span style="font-style: italic; color: rgb(51, 102, 255);">Class recoveryModule{</span><br /><br /><span style="font-style: italic; color: rgb(51, 102, 255);">public invokeRecovery(errorMessage){</span><br /><br /><span style="font-style: italic; color: rgb(51, 102, 255);">if errorMessage.equaltIgnoreCase("unexpected confirmation")</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">if browser.getConfirmation.equal(</span><span style="font-style: italic; color: rgb(51, 102, 255);">"Session expired. Do you want to re-login?"</span><span style="font-style: italic; color: rgb(51, 102, 255);">)</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">Appfunctions.loginApp();</span><br /><br /><br /><span style="font-style: italic; color: rgb(51, 102, 255);">//Other if blocks; one each for every unexpected event</span><br /><br /><span style="font-style: italic; color: rgb(51, 102, 255);">}</span><br /><span style="font-style: italic; color: rgb(51, 102, 255);">}</span><br /><br />For those who are working with drivers other than Java they should look up error handling in that language. The idea remains the same.Mahesh Narayananhttp://www.blogger.com/profile/08958481406561426910noreply@blogger.com4