So in a previous post I mentioned that I create objects which I call ControlObjects and a few of you told me that you do too and some of you call them Elements.
Would like to thank Adam Goucher for including it on a “Smattering of Selenium”.
So I mentioned I would share a some of them, so here is the first, its a Table ControlObject. My companies application has a financial section, with extended use of dynamic tables, so those lead to this object.
Before I created this object I found myself using a lot of XPath to read data from the table, and as we all know its not the most robust method for retrieving elements, however when you have a table, its hard to interact with a specific row/column unless it has a unique identifier which is rare.
So, I thought what if I can add some logic to my XPath calls, so that I was confident I was getting the cell I wanted.
A well structured HTML table consists of <table>/<thead></th> for the table headers and <table><tbody><tr><td> for the row and cells structure, so a standard XPath call would read: “table/tbody/tr[4]/td[3]” with the numbers being the required row / cell.
So what if I could determine those numbers using information I knew, then I could be assured I was always getting the cell I wanted, so here is how I achieved it.
I created a new object which took a table element as its parameter, then I create two lists, one for the headers (th) and one for the rows (tr), using By.Tagname, this then allows to me to inspect these lists for information I know, which in turn I can use to create an XPath request to retrieve the required cell / row.
So the standard structure of our tables is column headers across the top and the first column being a unique value such as a cost code / Id.
So I know the name of the unique column is “Cost Code”, I can then iterate through my column headers list to find the IWebElement text that equals “Cost Code”, I can then get the index of that element in the list, +1 (this is important as Lists are 0 indexed, Xpath isn’t) which gives me the correct td[x] value.
Then I can loop through the row list, using XPath to find the row that matches my unique value. So lets say that returned as 1.
Then from that match, I can do the same again to get the index of the column I want to read from, so lets say thats 5, then use XPath again to return the cell I was looking for.
So XPath can be useful especially if used Dynamically.
To note this will work if the table doesn’t have a thead area, however the first row which would contain all the th tags would be counted and looped through when looking for rows.
I have added the project to my GitHub account so please do download and have a look, and hopefully will be useful to some of you.
The project contains the ControlObject along with a set of tests to show it working. The tests are NUnit tests and use FirefoxDriver, and use the table below.
Company | Contact | Country |
---|---|---|
Alfreds Futterkiste | Maria Anders | Germany |
Berglunds snabbköp | Christina Berglund | Sweden |
Centro comercial Moctezuma | Francisco Chang | Mexico |
Ernst Handel | Roland Mendel | Austria |
Island Trading | Helen Bennett | UK |
Königlich Essen | Philip Cramer | Germany |
Laughing Bacchus Winecellars | Yoshi Tannamuri | Canada |
Magazzini Alimentari Riuniti | Giovanni Rovelli | Italy |
North/South | Simon Crowther | UK |
Paris spécialités | Marie Bertrand | France |
The Big Cheese | Liz Nixon | USA |
Vaffeljernet | Palle Ibsen | Denmark |