Grid Interaction in Selenium Tests with XPath

Posted on August 27, 2009. Filed under: test automation |

Even though I have been using SeleniumRC for a few years now, I never actually had the need to write xpath expressions. I knew that xpath was one option for locating UI controls in Selenium, but I was always able to use control IDs, names, or text…until recently.

I’m working on automating tests for a web app that has a lot settings configuration features, and many settings are managed in the UI via interactive grid controls. As the details of this app are proprietary, I will of course use a fake example. Since I’m on a Beatles kick, let’s imagine (har  har sorry for the bad pun and yes I know that was Lennon solo) I’m testing an album ranking control that looks like this:

SampleGrid

If I record my interactions with the grid using Selenium IDE, the output is something like this:

GridInteraction

Notice anything? I notice a couple things.

  1. Aside from the fact that I see “grdBeatlesAlbums” in the locator string, there is no context to the rest of it – “//tr[4]” doesn’t appear to correspond to Abbey Road which was the album I was moving up in the ranks.
  2. Yikes – am I really going to have to figure out the table row number for the album I want to act on in every test involving this grid?

My first inclination was to write a method that would determine the row position of an album with a given name. Then I realized that would involve parsing HTML. Yuck. I thought to myself, there has to be an easier way.  I went back to the Selenium docs to read about control location strategies a little more closely and saw that xpath would probably do the trick.  As so succinctly put on w3school’s page, “XPath is used to navigate through elements and attributes in an XML document.”

Now my problem was figuring out how to write an xpath expression that would locate a control in a column “next to” a given album name.

I wrote an almost-plain-English sentence to describe what I needed.

Version 1: Locate the “Move Up” link in the column adjacent to “Abbey Road.”

I thought “adjacent” would be a difficult concept but after Googling for a bit, I found information about the following and preceding xpath axes.

Version 2: Locate the “Move Up” link following the cell containing the string “Abbey Road.”

OK, so now to translate this to xpath – the Move Up link is just an HTML link, a.k.a. an “a” element.

a[.='Move Up'] translates to: a element whose inner text exactly matches ‘Move Up

And the cell containing “Abbey Road” – well, that’s just a table cell, or “td” element.

td[.='Abbey Road'] translates to: td element whose inner text exactly matches ‘Abbey Road

Next step: relate the two.

td[.='Abbey Road']/following::a[.='Move Up'] translates to: a element whose inner text exactly matches ‘Move Up‘, which follows a td element whose inner text exactly matches ‘Abbey Road

We just need one more thing: since the td element is not the first element on the page, we need to prepend the statement with // to indicate that the entire document (page source) should be searched to find the element.

//td[.='Abbey Road']/following::a[.='Move Up']

Even though the end result isn’t exactly plain English, it’s a lot more clear to me than “/tr[3]/td[4]/a” which is what the IDE recorded. It could also be reusable, providing the album name is passed via a variable instead of hard-coded.

Using xpath, you can also locate elements whose attributes (e.g. id or name) match certain criteria, and there are some handy functions like contains() to help in situations where a control’s full id or name is not known beforehand.

I’d still prefer the convenience of using control IDs, but there are just some situations where that either not possible or practical – xpath is now my fallback for tricky UI.

Update 8/28/09

Since I didn’t include this originally, the way to write an expression to find an element based on attribute values is

elementtype[@attributename='attribute value']

e.g. //table[@id='someTableID']

An example with contains():

elementtype[contains(@attributename, 'attribute substring')]

Advertisement

Make a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

Gravatar
WordPress.com Logo

You are commenting using your WordPress.com account. Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

2 Responses to “Grid Interaction in Selenium Tests with XPath”

RSS Feed for The Testing Blog Comments RSS Feed

That’s a great post, Marisa. I’ve never understand xpath stuff. Now that you’ve explained it halfway decently, I’m going to go experiment with it today toward the end of the day (or after I finish writing FIT tests). It’s always a challenge to find tutorials that make sense. Thanks for making sense!

BTW, I like the use of Beatle albums as the example. I remember, when I turned 16, I got Abbey Road for my birthday. I’ve listened to that album so many times; I could probably perform it live (a capella, of course). Don’t worry. If I do it, you’ll get front seat because of what you taught me about xpath expressions today.

“You never give me your money. You only give me your funny paper. And in the middle of negotiation, you break down.”

LOL thanks Daniel. I’m glad it was helpful. I was afraid it might not be enough, but I couldn’t write any more or it would have evolved into a full tutorial (and there are already a few out there for xpath).

BTW since I didn’t include this, the way to write an expression to find an element based on attribute values is elementtype[@attributename='attribute value'] e.g. table[@id='someTableID']

I will definitely be there for any performance you might give, especially a capella. HAHAHAH


Where's The Comment Form?

Liked it here?
Why not try sites on the blogroll...

Follow

Get every new post delivered to your Inbox.