How to use the element reference in javascript

2,366 views
Skip to first unread message

Dennis Marwood

unread,
Oct 29, 2013, 1:26:22 PM10/29/13
to robotframe...@googlegroups.com
Is there a way to store a located element in RIDE?

I want to find an element with Ride and then use that object in some js.

For example:

${my_element}=  Get Element (or something?)  xpath=//h1[1]
Execute Javascript  window.my_js_function(${my_element}')

Kevin O.

unread,
Oct 30, 2013, 1:07:53 PM10/30/13
to robotframe...@googlegroups.com
That is a rather strange thing to have to do. Is this a workaround for a shortcoming in Selenium? Selenium is primarily for simulating real users. If you are having trouble triggering something with the click keywords, I would try using Simulate.
Anyways, are some possible solutions:

Execute Javascript  window.my_js_function(document.getElementsByTagName('h1'[0]))

a more generic approach where any locator type could be used
Assign Id To Element    xpath=//h1[1]    wishthishadanid
Execute Javascript  window.my_js_function(document.getElementsById('wishthishadanid'))

To answer your question fully, yes there is ways find an element and then pass that as an argument to a script, but it would be using internals of Selenium2Library I would not want to encourage the general usage of. I think the above solutions should be sufficient.

Kevin O.

unread,
Oct 30, 2013, 1:09:34 PM10/30/13
to robotframe...@googlegroups.com
realized the parenthesis was in the wrong place, here is a correction:
Execute Javascript    window.my_js_function(document.getElementsByTagName('h1')[0])

Ed Manlove

unread,
Oct 30, 2013, 6:11:06 PM10/30/13
to robotframework-devel, robotframe...@googlegroups.com
I think what Dennis is asking here,
and what Kevin is raising with the proxy object is the idea of user
defined data types within Robot Framework. In other words when you have
a ${object} variable it remains of <type ...object...> instead of <type
'str'> as outlined in [1]. This would allow for libraries to store
"data" and pass it along through keywords. I can expand upon this idea
some more and give an more in depth example of its usefulness if necessary.

Ed

[1]
http://robotframework.googlecode.com/hg/doc/userguide/RobotFrameworkUserGuide.html?r=2.8.1#scalar-variables

David

unread,
Oct 30, 2013, 9:44:33 PM10/30/13
to robotframe...@googlegroups.com, robotframework-devel
I think an explicit example of what Ed mentions could be being able to get an object reference to a WebElement. I haven't looked at Selenium2Library in a long time to know what it fully offers.

But in the native language bindings of Selenium 2, you can work directly with WebElement objects returned by find element(s). And as such, using such WebElement objects, you can pass them in as arguments to execute (java)script. I'm assuming that's one such feature lacking in Selenium2Library, so you have to resort to what Kevin presented instead, where you lookup the (web) element within javascript rather than pass it in directly?

In the native language binding once passed in, javascript references it as arguments[n] where n is the argument/parameter index, and can fully manipulate a WebElement that's passed in as a DOM object.

Kevin O.

unread,
Oct 31, 2013, 9:41:24 AM10/31/13
to robotframe...@googlegroups.com
Yes, David, it is a feature lacking lacking in the library, but since it is open source you can find a way.
Using only the keywords in Selenium2Library, the only way to get reference to a WebElement is by returning it from a script, e.g.:
    ${elem}=    Execute Javascript    return document.getElementsByTagName('a')[0];

But this is crummy because you are forced to locate the element via JavaScript. Also you can't use that WebElement in Execute Javascript. In order to utilize S2L's awesome locator feature and also call a script with arguments, you can...
    Open Browser    http://www.google.com
    ${s2l}=    Get Library Instance    Selenium2Library
    ${elem}=    Call Method    ${s2l}    _element_find    xpath=//input    ${True}    ${True}
    Call Method    ${s2l._current_browser()}    execute_script    alert("my parent is a" + arguments[0].parentNode.tagName);    ${elem}

This is the kind of code I don't really want to encourage because it involves private methods that are not documented, and may change. I doubt _element_find will change, though.

Ed Manlove

unread,
Oct 31, 2013, 10:08:54 AM10/31/13
to robotframework-devel, robotframework-users
Selenium2Library actually offers a lot of functionality. So much so one should not have to resort to using javascript to find an element or doing most tasks on that element. If there is any missing keyword functionality please bring that to our attention and we can see what can be done to resolve this; a perfect example of this is the added support in the 1.2 release for jQuery selectors done by Paul Hicks, Filip Noetzel, and Jeremy Johnson.

Where I see the advantage of having these user defined object data types is repeated actions on an element or traversing elements; the goal being reducing the number of network calls. A simple example, repeated clicking an element, compare

| :FOR | ${n} | IN RANGE | 1 | 6 |
| ... | Click Button  | id=test_btn |

where each time we call click button we re-find the button. This compared to

| ${button_elem} = | Get Element | id=test_btn |
| :FOR | ${n} | IN RANGE | 1 | 6 |
| ... | Click Button  | ${button_elem} |

where we would get the element once and the act upon the python object, ${button_elem}. An example of traversing elements could be dealing with a html table element and performing actions on that table.  Selenium2Library has keywords to deal with tables but these work at a high level and have some performance issues. Those performance issues can be addressed directly within that code but I believe advantages can be gained from this type of functionality.

I raise this amongst these other discussions to bring out some ideas and questions I've had and open conversations. The advantages to the Selenium2Library might not be that great and the disadvantages to trying to rework Robot Framework might be too great.

Ed

Markus Bernhardt

unread,
Oct 31, 2013, 10:15:34 AM10/31/13
to korm...@gmail.com, robotframe...@googlegroups.com
First I would like to understand, why do you want to have the reference in Robot. Only to feed it into the next call to JavaScript, or do you plan to call methods of the WebElement itself.

If you only want to reuse it in subsequent calls to Javascript, wouldn't it be easier to simply store it on the JavaScript side?

Store Web Element In JavaScript
    Open Browser    http://www.google.com
    Execute Javascript    window.document.my_element = window.document.getElementsByClassName('gbqfba')[0];
    ${className}=    Execute Javascript    return window.document.my_element.className;
    Should Be Equal    ${className}    gbqfba

Only my 2 cent,
Markus

--
You received this message because you are subscribed to the Google Groups "robotframework-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to robotframework-u...@googlegroups.com.
To post to this group, send email to robotframe...@googlegroups.com.
Visit this group at http://groups.google.com/group/robotframework-users.
For more options, visit https://groups.google.com/groups/opt_out.

Markus Bernhardt

unread,
Oct 31, 2013, 10:48:14 AM10/31/13
to devP...@verizon.net, robotframework-devel, robotframework-users
Hi Ed,

wouldn't it be a good solution to implicitly cache locators and only reevaluate them on a StaleElementReferenceException? Or introduce some keywords like 'Add Element To Locator Cache' to manage the cache explicitly. Or both;-)

That way the performance issue goes away and no changes to Robot are needed.

Kevin O.

unread,
Oct 31, 2013, 1:07:01 PM10/31/13
to robotframe...@googlegroups.com, devP...@verizon.net, robotframework-devel
I still have doubts (and it looks like Markus does too), that there is even a valid use case for what Dennis is asking for because it sounds like the kind of testing that should be done in a unit testing framework for JavaScript. I just wanted to make the point to David that S2L is just a wrapper and so if you are willing to get your hands dirty, you can do anything in S2L you can with the bindings alone.

I have written quite a few tests and only resorted to using _element_find one time (to help a colleague). The issue was scraping the content of a large table in IE using XPath locators was taking way too long. Using WebElements, the execution time went from over one minute to 10 seconds. I think scraping the entire table was maybe not even necessary. In that situation, a Get Elements Text keyword would have overcame the whole performance issue, but I never bothered to request it.

Caching could have some nasty side-effects.
Say you grabbed the text of the last row with a locator like xpath=id('foo')//tr[last()]/td[1]. Then click a button that added a row to the table. If the the same locator that was meant to reference the last row was used again, it would now be grabbing the text of the second to last row. No StaleElementReferenceException would occur because the reference was still valid -- only the DOM around it changed.

David

unread,
Oct 31, 2013, 7:09:33 PM10/31/13
to robotframe...@googlegroups.com, devP...@verizon.net, robotframework-devel
I might be naive on the Selenium2Library keywords offered, but I'd assume it can't possibly offer/expose as keywords all the interesting things you can do in native javascript, to which you have to write up the javascript code and execute that with Execute Javascript keyword.

There are cases where due to current browser bugs/limitations or for whatever reason, the web app doesn't interact well with the native Selenium methods, so you have option of either not testing around those areas or use (dirty?) javascript workarounds to perform/simulate the action. That along with sometimes wanting to do additional test coverage that can only be done right now by calling javascript (like checking if an image has "rendered" or displayed on the browser, not just that the element/tag is loaded in the DOM as it could be a broken image icon).

I don't know if any RF/Selenium2Library user has come across such issues, but I have though I'm not an RF + Selenium2Library user. In such cases, I'd pass a reference of WebElement to the javascript call as an argument using find_element_by methods from native bindings rather than look up the element in pure Javascript since it's more flexible using the Selenium methods.

Until we never have to have a need to pass WebElements into javascript or where javascript lookup of web elements is real easy like with Selenium methods (for all types like link text, partial link text, XPath, CSS, ID, name), being able to pass a WebElement to Execute Javascript would be a nice feature to have (if it was technically possible).

Here's a blog post highlighting some examples where you would want to pass in a WebElement to javascript (or you can alternatively do the element lookup in javascript I guess):

Ed Manlove

unread,
Nov 1, 2013, 10:51:23 AM11/1/13
to robotframework-devel, robotframe...@googlegroups.com
Kevin O. wrote:
I still have doubts (and it looks like Markus does too), that there is even a valid use case for what Dennis is asking for because it sounds like the kind of testing that should be done in a unit testing framework for JavaScript. I just wanted to make the point to David that S2L is just a wrapper and so if you are willing to get your hands dirty, you can do anything in S2L you can with the bindings alone.

 
I agree. Robot framework is a high level keyword library. If you have to _use_ keywords to do low level functionality out in the open then you are probably doing something wrong or have a **temporary** hack or there is a bug/missing functionality in the library; i.e. something is not right.


I have written quite a few tests and only resorted to using _element_find one time (to help a colleague). The issue was scraping the content of a large table in IE using XPath locators was taking way too long. Using WebElements, the execution time went from over one minute to 10 seconds. I think scraping the entire table was maybe not even necessary. In that situation, a Get Elements Text keyword would have overcame the whole performance issue, but I never bothered to request it.


So what I am hearing from you Kevin is you don't see much of a need for having a webelement object as a variable. The only other example I see where having an RF variable be able to contain an object is in your Create Webdriver  code, rewritten here using a made up 'Create WebDriver Proxy' keyword,

${proxy}=  Create WebDriver Proxy  http_proxy=localhost:7777
Create Webdriver  Firefox  firefox  proxy  ${proxy}

where ${proxy}, as passed through robot framework's variable parser and seen inside of the library, is of type <class 'selenium.webdriver.common.proxy.Proxy'> as compared to type <type 'str'>. Finally answering your question Kevin I don't see a way to do this. RF, as far as I can tell, will always try to convert ${proxy} to a string.

Ed

Kevin O.

unread,
Nov 1, 2013, 5:31:30 PM11/1/13
to robotframe...@googlegroups.com, robotframework-devel
Dennis, let me apologize. I've been a bit cranky lately. I thought you were trying to pass a WebElement into the application's JS function.
Now I realize you were just copy/pasting the example code.

If you feel the Assign Id To Element workaround is insufficient, please raise an issue on Selenium2Library's issue tracker or explicitly ask for it here. Please elaborate on why the workaround is not sufficient, though.

Ed,
Thank you for contributing to the discussion. I'm not quite following on your part about the proxy.
The code sample you wrote is written in a way that would work, so I'm a bit confused? Anyways I got confirmation from Pekka that making varargs < 2.8 behave like kwargs is not possible (well at least it shouldn't be attempted). I will add kwarg support and leave the varargs for backwards compatibility soon.

I have not needed a Get Weblement(s) keyword, but I am just one person testing a few apps and should remember that. Someone else may have need of a keyword like that, but until someone asks for it, I am going to forget about it.

Kevin 
Reply all
Reply to author
Forward
0 new messages