Saturday, 13 March 2010

A simple getCSSCount for use with Selenium-RC

We know that XPath runs slowly in IE, but XPath has the getXPathCount method. And CSS runs quickly but Selenium doesn’t have a corresponding getCSSCount method.
I looked around for a simple way of getting count from a CSS selector.
I found this blog post by Aditya Ivaturi, but since I like to keep my Selenium setup and tests pretty simple, I wanted a much lower maintenance way of implementing the getCSSCount functionality.


So rather than amending the core in the jar file as Aditya did, or using user-extensions, I took the key JavaScript functionality presented in Aditya’s blog post and ran it with a get_eval.
Thus the following helper method:
private int getCSSCount(String aCSSLocator){
    String jsScript = "var cssMatches = eval_css(\"%s\", window.document);cssMatches.length;";
    return Integer.parseInt(selenium.getEval(String.format(jsScript, aCSSLocator)));
}
Which you could use:
assertEquals(6, getCSSCount("*"));
assertEquals(1,getCSSCount("p[id='para1']"));
This satisfied the itch I needed to scratch and it seems pretty low maintenance between Selenium versions.

8 comments:

  1. Awesome! Your posts on CSS selectors are very timely for me.

    So the C# version is:
    private int getCSSCount(String aCSSLocator)
    {
    String jsScript = "var cssMatches = eval_css(\"" + aCSSLocator + "\", window.document);cssMatches.length;";
    return int.Parse(browser.GetEval(jsScript));
    }

    Where I call the following C# to return the number of options in a element named "realm":
    int numOptions = getCSSCount("select[name='realm'] option");
    or
    int numOptions = getCSSCount("select[name='realm']>option");

    Thanks for converting it into C#, I hope that can help someone else too.

    ReplyDelete
  2. hi, thank you for this. Can you please also explain how to add "Get CSS count" into the userextensions.js file so that it can be its own function within selenium?

    best,
    S

    I don't use the IDE or userextensions.js so everything I do is based around simple Java. I've approved your comment in case someone else sees it and can help.

    But looking at the official docs http://seleniumhq.org/docs/08_user_extensions.html

    It looks like it might be as simple as adding

    Selenium.prototype.getCSSCount = function(locator, text) {
    var cssMatches = eval_css(locator, window.document);
    return cssMatches.length;
    };

    or possibly

    Selenium.prototype.getCSSCount = function(locator, text) {
    var cssMatches = eval_css(locator, this.browserbot.getDocument());
    return cssMatches.length;
    };

    But I haven't tried either of those code snippets so I'm coding blind based on the docs and based on Aditya's blog post.

    ReplyDelete
  3. Thank you for the attempt to help, but I couldn't get that extension to work.
    However--there is some good news. the kind folks at the google python user group have helped convert your original function into python. So now if anyone wants to use it, they would just place this code within their unittest class.

    def count_css_matches(self, css_locator):
    java_script_code = '''
    var cssMatches = eval_css("%s", window.document);
    cssMatches.length;''' % css_locator
    return self.selenium.get_eval(java_script_code)

    print self.count_css_matches("[id='listGuests'] > option") # where option is the name of the options elements in dropdown with id='listGuests'


    Suweeeeet!!! :)

    ReplyDelete
  4. oops sorry forgot to put back the int conversion
    return int(self.selenium.get_eval(java_script_code))

    So the code is :


    def count_css_matches(self, css_locator):
    java_script_code = ”’
    var cssMatches = eval_css(”%s”, window.document);
    cssMatches.length;”’ % css_locator
    return int(self.selenium.get_eval(java_script_code))

    print self.count_css_matches(”[id=’listGuests’] > option”) # where option is the name of the options elements in dropdown with id=’listGuests’

    ReplyDelete
  5. Thanks for article, useful to know. From stack overflow, there's also another way to do it in javascript, not sure which is more robust & cross platform:

    window.document.querySelectorAll("%s").length

    pass that as your javascript to eval to get same result

    http://stackoverflow.com/questions/1573170/how-can-i-count-the-number-of-elements-that-match-my-css-selector

    also, below is PHP version of the code, a bit more simplified.

    function getCssCount($cssSelector){
    return $selenium->getEval("var cssMatches = eval_css(\"".$cssSelector."\",window.document);cssMatches.length;");
    }

    echo $this->getCssCount(”[id=’listGuests’] > option”);

    Nice to see Python translation posted, but wonder why they didn't simplify it further into just one line like the PHP sample. Same goes for Java and .NET. But I guess the long way is more programmatically readable than condensed form.

    ReplyDelete
  6. one thing to note about this method, unlike regular Selenium RC API commands, you omit "css=" as prefix for the locator.

    ReplyDelete
  7. Thanks for the additional information David.

    PS, I've just subscribed to your blog too.

    Alan

    ReplyDelete
  8. Your welcome Alan. Hope my blog posts are useful for you too.

    I was curious about the eval_css() method used for getCSSCount() and neither your post nor the original article you refer to elaborate about eval_css. So I contacted the author of the original article and got this insightful info:

    "Yup, eval_css is not a standard javascript method. eval_css is a
    method of Browserbot & you can access it only if you're using 1.x RC
    server. Browserbot is not available in 2.x server. But I think that
    method was later added by the devs in to selenium project. If that is
    not there you can kind of emulate that same functionality by
    implementing (or copying) eval_css in your own javascript. Also jquery
    or sizzle might have eval_css if I'm correct."

    ReplyDelete