Table ControlObject

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

Paper vs. Steel #1

I want to share my approach to making your page object methods a bit more "less flaky" but also easier to maintain and more flexible. Am not going to try and cover everything in one post, so here is the first.

Populating a field on a page.

Excellent, we all know how to do this.
So if we run this, unless we get an exception, we just expect the username field is now populated.
Well lets change it to a bool so our tests have something to assert against.

So now, we can assert this method returns true, and just let an exception inform us that it has failed.
Still not great, we are either going to get true or exception, so lets add a try/catch so we can catch exceptions and return false.

So now we would be able to use this method for positive and negative testing, if we were expecting an exception, our test would be asserting a false response.

But what about the different exceptions we could receive, if we are always returning false, we don't know what caused it, so for a start we could output this to the console, this introduces a manual task, however I will post about more complex approaches in different post.

So making it a bit more robust, we know we have to interact with an element, so why don't we wait for that element first, if its there, we carry on if not lets wait a bit.

So we have introduced a few new things in this code snippet, firstly I have included my locators dictionary, this approach can be found here. Secondly, I have included a WebDriverWait object, this can be found in the "OpenQA.Selenium.Support.UI" name space.
I have added the time to wait as a parameter to the method, I do this as sometimes you might be testing the speed of the application, other times you may want to use the global timeout, this gives you that flexibility. Also added an error message for when this wait expires, providing specific error to reduce investigation time upon a failure.

So we now wait, and can catch if there is a problem, but we can do more.
Lets check that the element is enabled, you might say, why wouldn't it be, who knows, but by doing this we can provide a specific message again reducing investigation time.

Ok, so we are getting there, but how do we know the field is now populated with what we asked WebDriver to populate it with, we don't, so lets check that as well.

You will see that I have also added to clear the field before populating it, not everyone will want this, but it something to consider, depending on your applications behaviour. You could have a method to clear it first.

So as you can see there are several things we do to reduce flakiness, and also reduce investigation time.
So I also said maintenance, well obviously we aren't going to write all this everytime we want to populated a field, so we extract this to a library or I have added this to my default page object as a protected method, a few tweaks and we end up with this:

We can than call this method from our page objects, as all with have access to it, as they all inherit from DefaultPage.

As mentioned, there is better approach to handling exception, but hopefully you get an idea of what else you can do to reduce flakiness in some of your methods, but also reduce investigation time with failures, with smarter reporting.

I have deliberately called this post Paper vs, Steel, paper was just chosen as I was trying to thing of something weak, and there is always a pile of it on my desk, as its my favourite testing tool,

Then Steel, its a very strong material, but not the strongest, so while I think my approach is strong, I know its not the best, so if you can see a way I can improve it, then let me know, and perhaps future posts can be about titanium methods!