How to run javascript method 'document.evaluate' in WebDriver ?

2,082 views
Skip to first unread message

SantoshSarma

unread,
May 17, 2013, 12:51:01 PM5/17/13
to seleniu...@googlegroups.com
Hi,

I've tried to execute xpath in javascript and it is working fine in firebug.

Executed below logic in firebug and it is giving correct number anchor tags.

var paragraphCount = document.evaluate( 'count(//a)', document, null, XPathResult.ANY_TYPE, null );
alert
( 'This document contains ' + paragraphCount.numberValue + ' paragraph elements' );

And now I want to execute the same thing in WebDriver using JavascriptExecutor.
I've tried below logic but it is returning null object

JavascriptExecutor js = (JavascriptExecutor) driver;

Object obj=js.executeScript("document.evaluate('count(//a)', document, null, XPathResult.ANY_TYPE, null)");

tried this also
obj=js.executeScript("return document.evaluate('count(//a)', document, null, XPathResult.ANY_TYPE, null)");
it is not even executing this step. (keep on waiting at this step)

I know that we can get no of links using below logic
int linkCount=driver.findElements(By.tagName("a")).size();

but, my doubt is why it is not returning proper value by executing above javascript method and after adding return why that step is taking infinite time to execute?

Thanks & Regards,
SantoshSarma

David

unread,
May 17, 2013, 7:03:21 PM5/17/13
to seleniu...@googlegroups.com
Interesting discussion, wonder why it "hangs" with that code. 

You do need to add the "return" keyword to get back a result.

But also, why do you need to use document.evaluate()?

Another JS solution to do same thing is:

"return document.getElementsByTagName(\"a\").length;"
Also, in either case, I'd cast the return value back to int via ((Integer) obj).intValue() or something like that. Or even make the return object and int and cast the return value of executeScript.

SantoshSarma

unread,
May 18, 2013, 4:31:09 AM5/18/13
to seleniu...@googlegroups.com
Hi David,

Thank you for your reply..!

Above I mentioned logic is just for example. I want to execute xpath something like below using javascript

"//div[contains(text(),'some text content')]"

I'm just trying to use document.evaluate to execute xpath in javascript.

I just want to verify how fast it is than WebDrivers isElementPresent implementation.


Thanks & Regards,
SantoshSarma

SantoshSarma

unread,
May 20, 2013, 10:38:16 AM5/20/13
to seleniu...@googlegroups.com
Did anyone tried this ?  If so, please post your valuable suggestions/ideas here.

David

unread,
May 20, 2013, 5:57:06 PM5/20/13
to seleniu...@googlegroups.com
I just tried your code, what exactly is your document.evaluate() supposed to return? As in the result and the data type.

Here are my observations testing the JS code via Python bindings of Selenium:

I get what appears to be a browser hang executing your code as is.

If I execute "return document.getElementsByXPath('//a').length;" I get count of links found. This does require executing the snippet of code listed here to call document.getElementsByXPath:


and borrowing on the idea above, if I change your code a bit to use "XPathResult.ORDERED_NODE_SNAPSHOT_TYPE" I get exception that the expression cannot be convertd to return the specified type.

You might want to try document.getElementsByXPath().length (or without length, if you want the whole list of WebElements back) as an alternative to your JS query.

There's also document.getElementsByCssSelector() if you look at the blog post above.

I'm guessing document.evaluate() works in Selenium but depending on what you're evaluating it may hang the browser, so you're better off avoiding it and using different JS code to do what you want.

SantoshSarma

unread,
May 21, 2013, 3:24:38 AM5/21/13
to seleniu...@googlegroups.com
Thank you so much David for your detailed answer.

but, below logic did magic and returned required value.

Object obj=js.executeScript("var aCount = document.evaluate('count(//a)', document, null, XPathResult.ANY_TYPE, null );return aCount.numberValue;");
System.out.println("a tags count:"+obj);


Regards,
SantoshSarma. 

David

unread,
May 21, 2013, 5:31:57 PM5/21/13
to seleniu...@googlegroups.com
Hi Santosh,

Good to know you found the solution.

I guess it appears returning the object itself may have been the problem and returning a specific member of the object will be ok. This might be due to how you map a javascript object/data type to Java equivalent. There is no known object (I think) that document.evaluate() returns that can be mapped to a default (not custom) defined Java object.

But the numberValue member/property is ok since that's a primitive (int or String) that can be returned.

I don't know about Python or other languages, but you might have a bit more flexibility with languages that are not strongly typed so that they may deal w/ object mapping easier, though maybe not still since my test in Python showed it hung as well.

So in the future, you might want to confirm what kind of data your javascript returns beforehand so you know if it will work or cast properly back to Java.
Reply all
Reply to author
Forward
0 new messages