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!

I Call Them ControlObjects

Am not 100% sure what other people are going such objects however am I calling them "ControlObjects".

By a ControlObject I mean a common UI control used throughout your application such as SelectBox, Tables, Lists, plus controls specific to your application, such as we use several of the JQueryUI controls like MultiSelectBoxes and Toggle switch.

If your familiar with WebDriver you will already know that there is a Selectbox ControlObject already available in the OpenQA.Selenium.Support.UI.SelectElement namespace, but I believe that is the only one.

I have a separate Project within my solution for ControlObjects, mainly because they are used across a lot of our applications. You might not have noticed already but within your PageObjects you have probably already written code to handle the same control, so ControlObjects could work for you.

Obviously there is a dependency to some degree that the controls are always used in the same way in each instance, but you can control this by working close to the developers, or if you are the developer always use it the same way, then using ControlObjects should save you a lot of time, and also speed up the creation of PageObjects and in turn Tests. They could also assist you in creating more methods in your PageObjects because you have already written the complex code in the ControlObject.

Maintainability is also a factor, for example if the company decides to use a new control for MultiSelectBoxes you only need to change your ControlObject and all your tests should still function.

Here is how I use ControlObjects in my code:

The reason for having the ControlObject as a property is that, its likely you are going to use several methods from your page object, so we can use the same ControlObject instead of creating a new one each time. The saving is probably not noticeable, but I feel its good practise.

I will tidy up some of the ControlObjects I have created and share them at a later date.

Do you use ControlObjects? What do you call them? Love to hear how other people approach this.

My Page Object Approach

So I have been using a page object (PO) approach for a while now, but not been blogging for long, so am going to mark the below as "My Page Object Mach 1", and will continue the theme as my PO's involve.

So to start with I have abstract class which we are going to call DefaultPage, this is essentially my default PO, but it started by just handling WebDriver, like so:

It has since evolved into having several methods for interactions I found myself repeating, such as populated and reading fields, and dealing with Select boxes.

Then each of my page objects inherits the DefaultPage.

The basic structure of my page objects is:
  • Initiate locators.
  • Wait for a specific element
  • Assert that the application has taken you to the correct page, using a specific attribute of an element or could use the URL depending on your application.
Edit: I no longer agree with Assertions in PageObjects. The PageObjects job/role is to allow a test/check to interact with a page, a test/check would soon tell you there is an issue when the PO fails to serve the request. And if you are always running all your tests/checks, which you should be otherwise why bother to create them, you know soon enough if the page header isn't correct!

Which looks like:

I parameterise the timeout value, as I required to increase it for specific tests / environments, so made sense to make it default page of my approach.

I have heard people not recommend putting asserts in your page objects, however I believe that should be the rule for the methods but serves a good purpose in the constructor.

Then objects are instantiated like so:

Perhaps for another post, but I believe this is a good approach, and as mentioned above you can add common methods to the default page.

Appreciate all comments.

Take Screenshots With RemoteWebDriver

So am currently working on a project that I intend to post about soon, and ran into an issue when trying to take screenshots using RemoteWebDriver.
Turns out that RemoteWebDriver doesn't have the capability that the other drivers have, however after a few searches I managed to find a solution and with a small tweak got it working.

So here is how you can take screenshots using RemoteWebDriver.

You need to create a class that extends RemoteWebDriver and inherits ITakeScreenshot, should look like this:

The issue I had was that the example I found by Jim Evans, must have been when RemoteWebDriver didn't have any paramters, so had to include the URI and Capabilities.

To use this now you have to use your ScreenShotRemoteWebDriver instead of RemoteWebDriver, like so:

Then you can take a screenshot using the following code:

Note that the screenshots are saved on the machine where the test is being executed from, not the client.

Happy screenshoting!

* Update *

There has been lots of changes in RemoteWebDriver since I wrote this original post, one of those is that screenshots are now a lot easier as per Jan Zdrahal comment below.

So you can now create an extension for IWebDriver to take a screenshot for you that will also work with RemoteWebDriver.

Then you can call the method like so.

Share Share Share

ShareA part of a larger amount that is divided among a number of people, or to which a number of people contribute.
I want to start my blog by thanking everyone out there that already blogs and tweets about testing, for sharing their knowledge and experiences.

So far in my testing career I've been taking all your parts and processing them to further my skills and progress my career, so again thank you all for sharing. 

However, in the last few years my skillset has developed hugely and I feel that I am now in a position to contribute by sharing my knowledge and experiences.

It actually excites me that I too could write something that will further the skills of new testers or even established testers.

So please do follow me on twitter @FriendlyTester and check back to see if I share anything that interests you.