Marcos
Marcos

Reputation: 4930

HTML xpath tree dump? using Ruby Watir

Help! In carefully stepping through irb to control a browser (Firefox and Chrome) using the Watir library, it seems the xpath addresses are too shifty to rely on. Eg. one moment, the xpath for one's balance seems consistent, so I use that address in my script. Sometimes it works, but too often crashing with "element not found" although every time I manually step through, the webpage data is there (firebug inspect to confirm).

Yes, using Ajax-reliant sites, but not that changing....bank websites that pretty much remain the same across visits.

So question....is there some way watir-webdriver can simply give me a long, verbose dump of everything it sees in the DOM at the moment, in the form of an xpath tree? Would help me troubleshoot.

Upvotes: 3

Views: 1486

Answers (2)

Chuck van der Linden
Chuck van der Linden

Reputation: 6660

The big answer is to not use xpath, but instead use watir as the UI is intended to be used.

When it comes to a means to specify elements in browser automation, by and large Xpath is evil, it is SLOW, the code it creates is often (as you are finding) very very brittle, and it's nearly impossible to read and make sense of. Use it only as a means of last resort when nothing else will work.

If you are using a Watir API (as with Watir or Watir-webdriver) then you want to identify the element based on it's own attributes, such as class, name, id, text, etc If that doesn't work, then identify based on the closest container that wraps the element which has a way to find it uniquely. If that doesn't work identify by a sibling or sub-element and use the .parent method as a way to walk 'up' the dom to the 'parent container element.

To the point of being brittle and difficult readability, compare the following taken from the comments and consider the code using element_by_xpath on this:

/html/body/form/div[6]/div/table/tbody/tr[2]/td[2]/table/tbody/tr[2]/td/p/table[‌​2]/tbody/tr/td[2]/p/table/tbody/tr[3]/td[2]

and then compare to this (where the entire code is shorter than just the xpath alone)

browser.cell(:text => "Total Funds Avail. for Trading").parent.cell(:index => 1).text

or to be a bit less brittle replace index by some attribute of the cell who's text you want

browser.cell(:text => "Total Funds Avail. for Trading").parent.cell(:class => "balanceSnapShotCellRight").text

The xpath example is very difficult to make any sense of, no idea what element you are after or why the code might be selecting that element. And since there are so many index values, any change to the page design or just extra rows in the table above the one you want will break that code.

The second is much easier to make sense of, I can tell just by reading it what the script is trying to find on the page, and how it is locating it. Extra rows in the table, or other changes to page layout will not break the code. (with the exception of re-arranging the columns in the table, and even that could be avoided if I was to make use of class or some other characteristic of the target cell (as did an example in the comments below)

For that matter, if the use of the class is unique to that element on the page then

browser.cell(:class => 'balanceSnapShotCellRight').text

Would work just fine as long as there is only one cell with that class in the table.

Now to be fair I know there are ways to use xpath more elegantly to do something similar to what we are doing in the Watir code above, but while this is true, it's still not as easy to read and work with, and is not how most people commonly (mis)use xpath to select objects, especially if they have used recorders that create brittle cryptic xpath code similar to the sample above)

The answers to this SO question describe the three basic approaches to identifying elements in Watir. Each answer covers an approach, which one you would use depends on what works best in a given situation.

If you are finding a challenge on a given page, start a question here about it and include a sample of the HTML before/after/around the element you are trying to work with, and the folks here can generally point you the way.

If you've not done so, work through some of the tutorials in the Watir wiki, notice how seldom xpath is used.

Lastly, you mention Firewatir. Don't use Firewatir, it's out of date and no longer being developed and will not work with any recent version of FF. Instead use Watir-Webdriver to driver Firefox or Chrome (or IE).

Upvotes: 2

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243469

You just need to output the "innerXml" (I don't know Watir) of the node selected by this XPath expression:

/

Update:

In case that by "dump" you mean something different, such as a set of the XPath expressions each selecting a node, then have a look at the answer of this question:

https://stackoverflow.com/a/4747858/36305

Upvotes: 1

Related Questions