User defined data types or object variables within Robot Framework Was: How to use the element reference in javascript

1,371 views
Skip to first unread message

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,

On 10/29/2013 01:26 PM, Dennis Marwood wrote:
> 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}')
>

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.

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: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.

Only my 2 cent,
Markus


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