Google Analytics

Search

To search for specific articles you can use advanced Google features. Go to www.google.com and enter "site:darrellgrainger.blogspot.com" before your search terms, e.g.

site:darrellgrainger.blogspot.com CSS selectors

will search for "CSS selectors" but only on my site.


Tuesday, January 31, 2012

CSS for WebDriver revisited

I always liked using XPath for locators in Selenium and WebDriver. It was more procedural than using Cascading Style Sheets (CSS) and felt more like programming. However, using CSS for locators is much faster than using XPath. I haven't done any tests to see just how much faster but it is significant enough that I can see the difference.

I run a test suite using XPath locators. I can see significant delays where there appears to be nothing happening on the screen. I refactor the code to use CSS and the delays disappear. I would estimate that 3 to 5 second delays (XPath) become too small to measure with the naked eye (CSS).

The only feature I have been unable to do in CSS are locators which use the XPath text() function. CSS seems to be all about the tag and its attributes but not the text contained within the tag.

The one thing it took me a little while to get used to when switching from XPath to CSS was compound statements. For example, I might have an XPath like:

    "//div[contains(@class,'prefspanel')]/table[@id='sizer1']"

So how do I convert this to CSS?

    "div[class~='prefspanel']>table#sizer1"

Shorter and pretty much the same attributes. The ~= isn't quite the same as the contains() function. If I have:

    class='prefspanel foo bar'

the ~= will find prefspanel because it is a 'word' separated by whitespace. The contains() function will find 'prefs', 'prefspan', 'prefspanel' and even 'panel' because these are all substrings of the original. In CSS3 they introduced *= which is just like contains().

I also notice that many attributes will change dynamically. However, the start of the attribute or the end of the attribute will be consistent. In XPath I have to use the contains() function to find the attributes which end with the unique identifier. With CSS I can use ^= to see if the attribute begins with a substring or $= to see if the attribute ends with a substring.

One other place that XPath seems to work better is when you are reversing up the DOM. For example, if you have the following:

    <div id='pair'>
        <span>
            <p>Label:</p>
            <input size='25' type='text' value=''/>
        </span>
    </div>


I would typically find the input using:

    "//p[contains(text(),'Label:')]/../input"

There is no easy way to do the same thing with CSS. With CSS I would find the input from the div tag. However, I usually find the p and input are paired together and the XPath always works but the input relative to the div changes occasionally.

No comments: