Does WebDriver Support an Equivalent to Selenium's user-extensions.js file?

2,028 views
Skip to first unread message

MikeC

unread,
Feb 17, 2011, 3:37:40 PM2/17/11
to Selenium Developers
Hi,

I've built a test automation framework on top of Selenium v1. It uses
the Ruby selenium-client gem to communicate with the selenium RC
server in order to drive functionality on the web browser. In
addition, I've created a user-extensions.js file that contains a lot
of custom JS code in order to do some complex functionality.

Knowing that Selenium 2 uses WebDriver, I was wondering if WebDriver
supported the ability to load custom JS just like Selenium 1 did.
Basically, I would really like to upgrade to Selenium 2 in order to
take advantage of all that WebDriver has to offer, but this is a real
sticking point for me that I need answered before I can move ahead.
I'd prefer not having to rewrite all the logic located in my user-
extensions.js file.

Doing a quick scan of the WebDriver code, I noticed that the
org.openqa.selenium.remote.RemoteWebDriver class implements the
JavascriptExecutor interface which has a executeScript method. I'm not
entirely sure, but it seems that the JS is executed within the same JS
virtual domain that the web application's JS has also been loaded
into. If that's the case, then two things:

1) Is there a way to load JS that will remain in the browser and that
you can call later on?

2) Can the JS you execute via WebDriver be executed in a separate JS
virtual domain in order to avoid potential conflicts with the web
app's JS, yet can still acquire access to the web app's JS virtual
domain space? Kind of like how you can load JS in one frame that can
access JS loaded in another frame, so long as they both belong to the
same origin.

Thanks for any help on this.

Cheers,

Mike

Daniel Wagner-Hall

unread,
Feb 17, 2011, 6:28:30 PM2/17/11
to selenium-...@googlegroups.com, MikeC
JavascriptExecutor will execute the script you pass it in the
javascript environment of the page you're on (so will have access it
its globals, and can override them). You don't have access to any
other javascript environment, but you could e.g. inject an iframe with
javascript, if that would be useful to you.

> --
> You received this message because you are subscribed to the Google Groups "Selenium Developers" group.
> To post to this group, send email to selenium-...@googlegroups.com.
> To unsubscribe from this group, send email to selenium-develo...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/selenium-developers?hl=en.
>
>

MikeC

unread,
Feb 17, 2011, 6:57:57 PM2/17/11
to Selenium Developers
Hmm. With or without an iframe, it basically it looks like I'll have
to take all the code currently in my user-extensions.js file, refactor
it, and then add it to a JS bootstrap file that gets dynamically
loaded into the web page after the page finishes loading. It would be
better if WebDriver could create a new JS virtual domain in the opened
browser to load all the JS into. That way, when you go to another web
page within the same origin, you won't have to reload the bootstrap.

... Arg.

-Mike

On Feb 17, 6:28 pm, Daniel Wagner-Hall <dawag...@gmail.com> wrote:
> JavascriptExecutor will execute the script you pass it in the
> javascript environment of the page you're on (so will have access it
> its globals, and can override them).  You don't have access to any
> other javascript environment, but you could e.g. inject an iframe with
> javascript, if that would be useful to you.
>

Jari Bakken

unread,
Feb 17, 2011, 7:37:02 PM2/17/11
to selenium-...@googlegroups.com
On Thu, Feb 17, 2011 at 9:37 PM, MikeC <michael....@gmail.com> wrote:
>. In
> addition, I've created a user-extensions.js file that contains a lot
> of custom JS code in order to do some complex functionality.
>

You'll have to excuse my lack of Se1 experience, but could you explain
the use case for this? What's the benefit of having this logic in the
browser as opposed to in your test code (i.e. Ruby)?

Aditya Ivaturi

unread,
Feb 17, 2011, 7:56:10 PM2/17/11
to selenium-...@googlegroups.com, Jari Bakken
>
> You'll have to excuse my lack of Se1 experience, but could you explain
> the use case for this? What's the benefit of having this logic in the
> browser as opposed to in your test code (i.e. Ruby)?
>

Performance. For e.g. if you have a table with lots of rows & columns
& you want to read that information - it is far easier & actually
faster to just offload that to user-extensions & have JavaScript
process that information & send it over the wire. All of this can be
achieved in a single call. Otherwise you'll have to do multiple calls
to get the same information. Of course, you could probably grab the
source from the page, send it over to your test code & process it
there. But I think using user-extensions is a much cleaner solution.
In my case, we use user-extensions quite a bit to add our own custom
commands like getCSSCount etc, besides some other hacks we did to
improve IE performance.

--aditya

MikeC

unread,
Feb 17, 2011, 10:00:18 PM2/17/11
to Selenium Developers
@Aditya: Yes, exactly. Performance it one of the main concerns. Having
to constantly send complex JS functions over the wire to the remote
server is a big performance hit as I have definitely witnessed through
my own experience.

In addition to performance, it is far easier and much cleaner to write
JS code in a separate file that can be loaded into another JS virtual
domain in order to not just access DOM elements, but also to interact
with loaded JavaScript frameworks that require you to access various
objects and such.

There are a lot of JS objects and functions in my user-extensions file
that encapsulation complex functionality in order to do things things
simply when writing test scripts.

With Selenium v1, you can load all your JS functionality via the user-
extensions file at the beginning when your start a new browser
session. Once loaded, you did not have to keep reloading the file
since all the JS code is loaded into the test command window. And
since the test command window and the application window came from the
same origin, you had the following benefits:

1) Separate JS domains which helped avoid clobbering and other nasty
side effects
2) Ability to access both DOM elements and JS functionality in the
application window from the command window
3) Avoided increasing the memory footprint of the loaded web page

Without this ability, the options I'm left with using Selenium 2 is
either to: 1) read in the code from the user-extensions.js file myself
and send everything over to the browser via the executeScript command;
or 2) break apart the logic within the user-extensions.js file and
refactor everything so that large chunks of JS logic are constantly
being sent over to the browser via executeScript. Of the two, the
first option is the lesser of two evils. However, when applying the
first option, I have to be mindful of when a new web page loads or
when there is a frame to access or when a window pops up. In each case
I have to reload all the JS code for that given window that I'm
accessing, which can be a big performance hit when running your test
scripts against a complex web app.

To be honest, while WebDriver has its pluses, especially with handling
various native UI elements that you can't deal with properly or at all
via JS, I'd would probably continue to stick with Selenium v1 simply
because of the user-extensions file feature and the JS code getting
loaded into a separate JS domain. The only reason why I'm now looking
at Selenium 2 is because I need my scripts to run against IE9 and
Firefox 4, and only v2 handles both.

-Mike

Santiago Suarez Ordoñez

unread,
Feb 17, 2011, 10:23:48 PM2/17/11
to selenium-...@googlegroups.com
On Fri, Feb 18, 2011 at 12:00 AM, MikeC <michael....@gmail.com> wrote:
The only reason why I'm now looking
at Selenium 2 is because I need my scripts to run against IE9 and
Firefox 4, and only v2 handles both.

I'm all in to find out a solution to make Selenium 2 support needs like yours, but just to clarify, I have both IE9 and FF4 working with Selenium 1. I tested it with version 2.0a7 and both later betas all of them work just fine (big win for JS atoms and free browser support!).

Santi

MikeC

unread,
Feb 17, 2011, 10:29:26 PM2/17/11
to Selenium Developers
Santi,

Excellent!! That's definitely great to know. How did you get IE9 and
FF4 to run with Selenium 1? I'm running into errors on my end when
using the selenium RC server.

Mike

On Feb 17, 10:23 pm, Santiago Suarez Ordoñez <santi...@gmail.com>
wrote:

Santiago Suarez Ordoñez

unread,
Feb 17, 2011, 10:33:57 PM2/17/11
to selenium-...@googlegroups.com, Jari Bakken
Hey Aditya,

Your comment makes total sense. I'd love to see some discussion around JS injection and different ways to avoid the test impact of loading files over and over again.

Here's my take:

You only use JavascriptExecutor to create a new <script> node in the DOM with a reference to the JS file you want to inject (it has to be stored online somewhere). This way, you don't have to transfer a big file over the wire each time if you're using Remote WebDriver + the file gets cached by the browser the first time and all the following will be loaded instantly, reducing the load impact. 
Of course, this won't save you from having to redo on page refreshing, but at least reduces the complexity. 
For this last issue, I'd just add some logic to my test framework to check for some global variable to be present (defined by the JS injected), and then proceed by injecting if missing, before moving to the real action depending on this code.

Hope it makes sense, I'd love to hear better alternatives.

besides some other hacks we did to
improve IE performance.

Yo! Share some of that sauce, my friend! We're all interested in improving IE performance with JS hacks!

Best,
Santi

Santiago Suarez Ordoñez

unread,
Feb 17, 2011, 10:36:14 PM2/17/11
to selenium-...@googlegroups.com
Excellent!! That's definitely great to know. How did you get IE9 and
FF4 to run with Selenium 1? I'm running into errors on my end when
using the selenium RC server.

I Don't want to derail this conversation much, the process was not long but definitely not fun. 
Let's do something, I promise I'll write the process in detail in Sauce Labs' blog next friday!
Would that work?

Santi
 

Mike

On Feb 17, 10:23 pm, Santiago Suarez Ordoñez <santi...@gmail.com>
wrote:
> On Fri, Feb 18, 2011 at 12:00 AM, MikeC <michael.lee.co...@gmail.com> wrote:
> > The only reason why I'm now looking
> > at Selenium 2 is because I need my scripts to run against IE9 and
> > Firefox 4, and only v2 handles both.
>
> I'm all in to find out a solution to make Selenium 2 support needs like
> yours, but just to clarify, I have both IE9 and FF4 working with Selenium 1.
> I tested it with version 2.0a7 and both later betas all of them work just
> fine (big win for JS atoms and free browser support!).
>
> Santi

MikeC

unread,
Feb 17, 2011, 11:00:56 PM2/17/11
to Selenium Developers
Santi,

Yes, absolutely! That would be perfect. I'm already bouncing up and
down desperate for the information!

As for your take on the JS Executor, yes, there are tricks you can
perform in order to cache and avoiding clobbering, but there are a few
issues with it:

1) The person working with the Selenium framework is now being forced
to apply these tricks (read: hacks) when the framework itself should
be handling these issues. And aside from applying these tricks to make
up for what the latest Selenium is lacking, it also leads to brittle
and not very maintainable code.

2) Even with the trick applied and working, you're still injecting JS
code into the very same memory space that the web page that has been
loaded into. This can: a) have a performance or execution impact on
the web app itself, which can affect things like benchmarking metrics
(something my team is *very* conscience of); and b) is undesirable
from a pure testing perspective since the testing mechanism shouldn't
in any way alter the environment under test; or, if it has to, to do
so at the very minimum possible.

With all that being said, please don't get me wrong. I really like
using Selenium as it's made my lift a lot easier to develop my own
test automation framework on top of it, but I really want to make sure
Selenium is moving in the right direction and does not end up
neglecting or removing features which I find very important in order
to get my job done and continue to keep things maintainable.

-Mike

On Feb 17, 10:36 pm, Santiago Suarez Ordoñez <santi...@gmail.com>
wrote:
> > Excellent!! That's definitely great to know. How did you get IE9 and
> > FF4 to run with Selenium 1? I'm running into errors on my end when
> > using the selenium RC server.
>
> I Don't want to derail this conversation much, the process was not long but
> definitely not fun.
> Let's do something, I promise I'll write the process in detail in Sauce
> Labs' blog <http://saucelabs.com/blog> next friday!

MikeC

unread,
Feb 17, 2011, 11:43:11 PM2/17/11
to Selenium Developers
Just to extend on the user-extensions.js file, it would be great if
Selenium 2 could be updated such that when you start up the remote
server you can provide any number of JS files via the command console
and Selenium will automatically load all of them into a web page once
the page has been fully loaded. Even better is if Selenium 2 could be
updated to make sure all of those JS files are simply separated out
into their own JS virtual domain but still live within the same origin
in order to allow for communication across domains; therefore, you
only have to load all of those files into the browser once per
session, and not for each page you end up loading during a given
session.

-Mike

Simon Stewart

unread,
Feb 18, 2011, 12:02:34 AM2/18/11
to selenium-...@googlegroups.com
Time to dive in.

User extensions seem to fall into one of a handful of categories:

* Adding new element locating mechanisms
* Adding new commands.

So far in this discussion, these categories have been bundled
together. That's unfortunate, because the way that they're handled
differs.

The first use case, that of adding new element locating mechanisms, is
quite often a generalization of a specific requirement, which is to
somehow hook into the JS library used within the rest of the
application (typically jquery) In the case where the required library
is already loaded by the app, it's enough to just use the
JavascriptExecutor. There's no loss of efficiency, and you can return
web elements.

It should be noted that one of the reasons why custom locators are
used in selenium is that it can be hard to identify and reference
elements from one another. In the case of finding the third cell in
the second row of a table, a Selenium 1 user would have faced either a
complex xpath or a custom locator. The same thing using the webdriver
APIs would look like:

WebElement table = driver.findElement(By.id("table"));
WebElement row = table.findElements(By.tagName("tr")).get(1);
WebElement cell = row.findElements(By.tagName("td")).get(2);

Put another way, the newer API quite often makes it easy to avoid
needing a custom locator in the first place. Better yet, since you can
now keep a reference to the element, rather than looking it up every
time you call it, the cost of extra calls to do the initial find can
often be ameliorated very quickly (in this case, within about one or
two method calls)

The second use case (adding more commands) is handled by the fact that
webdriver offers an API. New methods and commands can generally be
built using the primitives offered by the driver. For an example of
this in action, take a look at the Select class in the support
package. This models a SELECT tag, and allows a test to interact with
one in an efficient way. The first version of this implemented a very
simple approach, and as we identified bottlenecks and issues, this
approach was refined. The nice thing is that the user-facing API
hasn't changed during this refinement.

In my experience with several very large projects, moving to the new
APIs has resulted in clearer code and faster test times, even when
replacing custom user extensions.

Regards,

Simon

MikeC

unread,
Feb 18, 2011, 12:50:29 AM2/18/11
to Selenium Developers
Hey Simon,

I was wondering if and when you were going to chime in on this
thread ;-).

In any case, you make a bunch of interesting points. First, I should
say that locating elements is a relatively simple case for me, and one
that I'm not as much hung up about, or, for that fact, basic actions
like a select on a HTML form field. Rather, what matters more to me is
being able to access a rich set of JavaScript functionality that is
part of the web application.

To be a bit more clear, I've created a test automation framework named
Lebowski, which is a framework designed to help people write and
execute full integration and feature tests for web applications that
have been built with SproutCore. SproutCore is a rather large and
complex MVC JavaScript framework that is inspired by Apple's Cocoa
framework making use of KVO/KVC, bindings and so on.

SproutCore's view architecture abstracts a view's in memory
representation from its rendered DOM representation. Much of the
interaction with views typically requires a complex set of actions
where you really need to access SproutCore's event and root responder
modules -- both of which are JavaScript. And it's not just accessing
various types of views in memory, but also model objects, the
datastore, controller objects, statecharts, and so on. Again, all of
this is JavaScript. As for actually accessing views, controllers and
model objects, that is done via SproutCore property paths, not CSS
selectors or XPath statements.

I would have to contend with your argument about cleaner code. Through
my own experience, it is far easier for me to write a lot of logic in
JavaScript to do complex interactions with SproutCore directly and do
simple function calls via Selenium with in something like Ruby. This
also creates a nice separation of concerns versus having to create a
lot of composite commands in Ruby/Java/C# that wraps JS code. And JS
code in such wrapper objects ends up getting represented as strings,
which does me little good when it comes to using tools like JSLint in,
say, TextMate to assure the correctness of the code. I'd rather not
have to wait for runtime errors to appear in order to inform me of
coding mistakes when JSLint can help me with that.

I can certainly understand that many people who use Selenium apply it
against more traditional web applications, and are focused on
accessing DOM elements under those more traditional circumstances. So
the approach you note make sense since the set of composite commands
is relatively small to average in size. However, for my particular
circumstance, the approach your are enforcing is not ideal and only
makes thing more difficult to code and maintain.

At the end of the day, I'd personally like to see Selenium offer both
approaches to handling JavaScript. It then offers and appropriate
level of flexibility to those who need the right type of control over
Selenium and what is being built on top of it.

-Mike

-----
http://frozencanuck.wordpress.com/
http://github.com/FrozenCanuck/Lebowski
http://github.com/FrozenCanuck/Ki
http://www.sproutcore.com

Aditya Ivaturi

unread,
Feb 18, 2011, 2:13:14 AM2/18/11
to selenium-...@googlegroups.com, Santiago Suarez Ordoñez, Jari Bakken
>
> Yo! Share some of that sauce, my friend! We're all interested in improving
> IE performance with JS hacks!

Here you go - http://www.ivaturi.org/home/hackingseleniumtoimproveitsperformanceonie.

NOTE - this is not necessarily a universal hack, but two other folks
that have tried this approach have told me that it did improve
performance for them dramatically.

--aditya

Aditya Ivaturi

unread,
Feb 18, 2011, 2:39:50 AM2/18/11
to selenium-...@googlegroups.com, Simon Stewart
>
> It should be noted that one of the reasons why custom locators are
> used in selenium is that it can be hard to identify and reference
> elements from one another. In the case of finding the third cell in
> the second row of a table, a Selenium 1 user would have faced either a
> complex xpath or a custom locator. The same thing using the webdriver
> APIs would look like:
>
> WebElement table = driver.findElement(By.id("table"));
> WebElement row = table.findElements(By.tagName("tr")).get(1);
> WebElement cell = row.findElements(By.tagName("td")).get(2);
>
> Put another way, the newer API quite often makes it easy to avoid
> needing a custom locator in the first place. Better yet, since you can
> now keep a reference to the element, rather than looking it up every
> time you call it, the cost of extra calls to do the initial find can
> often be ameliorated very quickly (in this case, within about one or
> two method calls)

In my case, I typically end up with tables with over few hundred rows
rather frequently (and annoyingly might I add). And the way I reduce
my overhead is by writing a simple JavaScript routine that uses XPath
with "context" nodes in user-extensions. If I'm not wrong, your above
given example does the same thing, i.e. "WebElement table" is your
context node. This still requires me to make further calls to Selenium
to get rest of the nodes (rows and eventually table cells). On the
other hand, by offloading the processing to user-extensions, I always
end up with just one call. The user-extension I wrote, creates a JSON
representation & sends over the final table structure & data to my
code. I haven't really created a custom locator per se, but rather
reduced the chatter between Selenium & my test code.

AFAIK the concept of user-extensions provides flexibility & options
for users and definitely allows us to "hack" without actually
recompiling RC, which to me is a very big plus.

--aditya

Santiago Suarez Ordoñez

unread,
Feb 18, 2011, 1:24:45 PM2/18/11
to Aditya Ivaturi, selenium-...@googlegroups.com, Jari Bakken
On Fri, Feb 18, 2011 at 4:13 AM, Aditya Ivaturi <iva...@gmail.com> wrote:

Here you go - http://www.ivaturi.org/home/hackingseleniumtoimproveitsperformanceonie.

NOTE - this is not necessarily a universal hack, but two other folks
that have tried this approach have told me that it did improve
performance for them dramatically.

Thanks for sharing!

Santi

Patrick Lightbody

unread,
Feb 19, 2011, 12:33:54 PM2/19/11
to selenium-...@googlegroups.com, MikeC
Mike & Simon,
Thanks for the thoughts here. I'm glad it got brought up externally -
Simon and I (and many other devs) have had this debate a bunch of
times in the last year or so, but never really got anywhere.

At a minimum, I have urged Simon that if we're going to tell people to
inject JavaScript in to the page, we need to provide some sort of
callback hook to notify the end user when a new page loads (so that
they know to inject it again). Simon - We don't yet have that, AFAIK?

But still, we can't have a solid backwards compatibility story until
we address user-extensions head on. I run in to folks who use
user-extensions all the time. Simon clearly doesn't use them or prefer
them, but part of the Selenium 2 story included a strong commitment to
backwards compatibility, so I want us to at least try to honor that
and potentially try to really understand users like Mike and see if we
can fit them in to Selenium 2 in a way that is more than just
compatibility.

I don't want this conversation to fade away like our user-extension
discussions have in the past but I also don't want to go make
suggestions since I know I won't be the one to code them. Hoping that
Simon and Mike can keep the healthy discussion going, but that we can
see some input from some of the other devs.

Patrick

MikeC

unread,
Feb 19, 2011, 3:24:22 PM2/19/11
to Selenium Developers
Hey Patrick,

Good to know that there has at least been prior discussion about the
user-extensions.js file, even if it was more of an internal
discussion. And rest assured that I won't be lettering go of this
particular topic considering the outcome of Selenium 2 can affect my
own framework, Lebowski, greatly.

The thing that I'm witnessing as a user of the Selenium framework and
an observer of where it is potentially going, is one of both
overcoming technical limitations and a philosophical shift in how one
is expected to work with the framework.

It's clear that Selenium 1, while good, simply was not able to have
the kind of control over the browser that WebDriver does have in order
to overcome various issues. Therefore, bringing in WebDriver to
supplant Selenium's original architecture can be seen a positive. That
being said, WebDriver has its own particular philosophy as to how you
are expected to build on top of it in order to communicate with the
browser.

Both Selenium 1 and WebDriver have a common intersect with respect to
both accessing individual DOM elements via some kind of locator and
providing an API to raise basic types of events against those
elements. Technically though, the API provided by each framework is
different; however, the mental transition between the two isn't too
bad.

Where things really start to diverge is how both frameworks allow you
to handle executing your own JavaScript. With WebDriver you have the
executeScript method at the rawest level, but the idea of using it
really rests upon the composite-command design pattern. Selenium 1 too
has a low-level method to execute raw JS, but, in turn, it also
provides an alternative for how JS can be injected via an external
user-extensions.js file. Of course, Selenium 1 does not enforce the
use of any composite-command design pattern. And this is where the
real problem starts to pop-up.

It's that shift in how raw JS is supposed to be handled that can cause
a lot of potential refactoring of JS code to go from using a user-
extensions.js file to splitting everything up into a bunch of
commands. This might not be so bad for those who have small user-
extensions.js file, but for those who have a *lot* of JS logic,
refactoring all that code is, well, to keep it simple and polite --
not very nice. And I've already pointed out the positives of keeping
all that JS logic within a separate JS file.

To be clear, I'm not fundamentally opposed to the composite-command
pattern in and of itself. I think there is certainly merit to using
it; however, the idea of leveraging another framework to overcome
technical issues but then ends up enforcing a new way of doing things
is not ideal, especially considering the large base of users who have
come to heavily rely on Selenium 1. If this type of migration needs to
happen to Selenium, then the core Selenium team needs to very
carefully take into consideration as to how people have really been
using Selenium 1.

To me, this shift that Selenium 2 has taken from an API point-of-view
is too much of a jolt. People can have their respective differences in
how they believe raw JS should be injected into the browser via
Selenium, but at the end of the day, Selenium, as a framework and as a
community, needs to be flexible to allow for those differences of
opinion.

I'd honestly be happier to simply stick with Selenium 1 and see it get
patched so that IE9 and FF4 can be easily launched, and wait until
Selenium 2 gets everything sorted out with respect to how raw JS is
supposed to be handled properly.

-Mike

On Feb 19, 12:33 pm, Patrick Lightbody <patr...@lightbody.net> wrote:
> Mike & Simon,
> Thanks for the thoughts here. I'm glad it got brought up externally -
> Simon and I (and many other devs) have had this debate a bunch of
> times in the last year or so, but never really got anywhere.
>
> At a minimum, I have urged Simon that if we're going to tell people to
> inject JavaScript in to the page, we need to provide some sort of
> callback hook to notify the end user when a new page loads (so that
> they know to inject it again). Simon - We don't yet have that, AFAIK?
>
> But still, we can't have a solid backwards compatibility story until
> we address user-extensions head on. I run in to folks who use
> user-extensions all the time. Simon clearly doesn't use them or prefer
> them, but part of the Selenium 2 story included a strong commitment to
> backwards compatibility, so I want us to at least try to honor that
> and potentially try to really understand users like Mike and see if we
> can fit them in to Selenium 2 in a way that is more than just
> compatibility.
>
> I don't want this conversation to fade away like our user-extension
> discussions have in the past but I also don't want to go make
> suggestions since I know I won't be the one to code them. Hoping that
> Simon and Mike can keep the healthy discussion going, but that we can
> see some input from some of the other devs.
>
> Patrick
>
> ...
>
> read more »

Patrick Lightbody

unread,
Feb 19, 2011, 8:41:23 PM2/19/11
to selenium-...@googlegroups.com, MikeC
My personal feeling is that with a few extra APIs (primarily a
callback function that can allow you to inject JavaScript on page
loads) you could probably easily rig up a system very similar to
user-extensions. Interested to hear Simon's and other opinions on
this!

Patrick

Simon Stewart

unread,
Feb 20, 2011, 8:48:33 AM2/20/11
to selenium-...@googlegroups.com, Patrick Lightbody, MikeC
The only problem with a callback system is that webdriver is very
clearly documented as not being thread-safe: we'll need to be careful
with how we implement this. You probably want to be tracking this
issue:

http://code.google.com/p/selenium/issues/detail?id=71

It's never been high on my list of priorities for a couple of reasons.
Firstly, because, as pointed out, I already use a different level of
abstraction, secondly because I already know when I expect a page load
to happen and can therefore inject pieces efficiently as needed.

Simon

Patrick Lightbody

unread,
Feb 20, 2011, 12:25:05 PM2/20/11
to Simon Stewart, selenium-...@googlegroups.com, MikeC
> The only problem with a callback system is that webdriver is very
> clearly documented as not being thread-safe: we'll need to be careful
> with how we implement this. You probably want to be tracking this
> issue:
>
> http://code.google.com/p/selenium/issues/detail?id=71
>
> It's never been high on my list of priorities for a couple of reasons.
> Firstly, because, as pointed out, I already use a different level of
> abstraction, secondly because I already know when I expect a page load
> to happen and can therefore inject pieces efficiently as needed.

I appreciate your point here, but I've run in to a lot of cases where
I don't have enough information to expect a page load to happen (ie:
I'm waiting on a page for an external event to cause a page to
reload). I'm glad that there is an issue for this and I hope it gets
addresses eventually, though I understand it probably makes things a
bit more complex.

That all said, wondering what Mike thinks about all this - would the
ability to check for page load events and then inject in JS address
his core concern? Could that be a viable path for users of
user-extensions?

Patrick

RamMan

unread,
Feb 18, 2011, 9:43:40 AM2/18/11
to Selenium Developers
I have the distinction of being the first user of MikeC's Lebowski
framework which by the way I highly recommend. Lebowski (available as
a Ruby Gem) is an engineering marvel and the user-extensions.js file
clocks in at over 2k SLOC. Firefox 4 RC is due at the end of the
month. Since the Selenium 2 migration path looks like a steep climb,
if you have a short path to getting FF4 and IE9 support under Selenium
1 then I would be very grateful to also hear it.

On Feb 17, 10:36 pm, Santiago Suarez Ordoñez <santi...@gmail.com>
wrote:
> > Excellent!! That's definitely great to know. How did you get IE9 and
> > FF4 to run with Selenium 1? I'm running into errors on my end when
> > using the selenium RC server.
>
> I Don't want to derail this conversation much, the process was not long but
> definitely not fun.
> Let's do something, I promise I'll write the process in detail in Sauce
> Labs' blog <http://saucelabs.com/blog> next friday!

Simon Stewart

unread,
Feb 22, 2011, 3:40:21 AM2/22/11
to selenium-...@googlegroups.com
Sounds like I need to write up how to migrate from Selenium 1 to
Selenium 2. As a hint, take a look at switching "DefaultSelenium" for
"WebDriverBackedSelenium"

Simon

Adam Goucher

unread,
Feb 22, 2011, 6:03:34 AM2/22/11
to selenium-...@googlegroups.com
But that is only for Java...

-adam


> Sounds like I need to write up how to migrate from Selenium 1 to
> Selenium 2. As a hint, take a look at switching "DefaultSelenium" for
> "WebDriverBackedSelenium"
>
> Simon
>
> On Fri, Feb 18, 2011 at 11:43 PM, RamMan<mike....@eloqua.com> wrote:
>> I have the distinction of being the first user of MikeC's Lebowski
>> framework which by the way I highly recommend. Lebowski (available as
>> a Ruby Gem) is an engineering marvel and the user-extensions.js file
>> clocks in at over 2k SLOC. Firefox 4 RC is due at the end of the
>> month. Since the Selenium 2 migration path looks like a steep climb,
>> if you have a short path to getting FF4 and IE9 support under Selenium
>> 1 then I would be very grateful to also hear it.
>>

>> On Feb 17, 10:36 pm, Santiago Suarez Ordo�ez<santi...@gmail.com>


>> wrote:
>>>> Excellent!! That's definitely great to know. How did you get IE9 and
>>>> FF4 to run with Selenium 1? I'm running into errors on my end when
>>>> using the selenium RC server.
>>> I Don't want to derail this conversation much, the process was not long but
>>> definitely not fun.
>>> Let's do something, I promise I'll write the process in detail in Sauce
>>> Labs' blog<http://saucelabs.com/blog> next friday!
>>> Would that work?
>>>
>>> Santi
>>>
>>>
>>>
>>>
>>>
>>>> Mike

>>>> On Feb 17, 10:23 pm, Santiago Suarez Ordo�ez<santi...@gmail.com>

Eran M.

unread,
Feb 22, 2011, 6:32:32 AM2/22/11
to selenium-...@googlegroups.com, Patrick Lightbody, Simon Stewart, MikeC
Disclaimer: I've used Selenium 1 very little and not claim to be familiar with all of its use cases. I'm writing this based on the discussion here and my familiarity with the differences between Selenium 1 and 2.

It's very nice to see Selenium used for building of other tools - after all, Selenium is Yet Another Library so combining it with other libraries can create very interesting results. I find that ne of Selenium 2's strong points is it's focused API - and several large testing infrastructures were built on top of it. Off the top of my head, I can think of BidiChecker and Crawljax (both are Javascript-intensive).

Regarding the user-extensions.js, I think that Selenium 1's support of such a feature is accidental - It does not seem like supporting user-provided javascript is a core capability that is essential to a browser automation framework. Instead, it is there simply because Selenium 1 was implemented using an HTTP proxy and injecting javascript so it could inject user-provided javascript. In this sense I find this to be a truly accidental property of Selenium. This is even more true of the separate namespace the scripts were loaded into (I find that it is equally risky to load user-provided scripts into Selenium's namespace as it is to load them to the webapp's namespace - in both namespaces things may change and conflict with the user-provided script). Note that the question whether these features should be supported in Selenium 2 is a separate question.

There is another issue with the suggested solution of providing notifications of page loads - it's hard. Especially when native events are involved and when different versions of different browsers should be taken into consideration. This, of course, was easy with Selenium 1, which was implemented using a proxy.

There are several alternatives I could think of, to still enable javascript-heavy frameworks to be created using Selenium 2:
  • Using any language bindings to create a higher-level API (depending on the role of the framework) and providing the additional functionality by injecting bits of Javascript based on the need. In other words, there's no point in loading a large collection of javascript functions if each test is using only several of them on every page.
  • Going the Selenium 1 route and using a Proxy to inject the required Javascript functionality. If you really must have all of your javascript code present in every page, I think that's the most reliable way - every GET request will go through the proxy. It's also possible to serve the original GET request in an iframe of it's own and inject the additional JS code to a separate one. Then it's easy to use Selenium 2's switchTo().frame(...) calls to pick specific functions from either frames.
  • Create a browser-specific extension that will provide the needed functionality. This is a lot more work, of course, but it fits with the model of Selenium as a component (Selenium 2 supports loading additional extensions for Firefox, for example). Performance-wise, this should provide the best performance, as the code lives in the browser and is not injected at all (neither through a proxy nor executeScript).

Overall I'd love to see that Selenium 2 is a usable library for building other tools for testing and I think that such scenarios should be taken into consideration when developing Selenium 2. I just find that supporting user-extensions.js in the way Selenium 1 just doesn't fit well with Selenium 2's APIs and ultimately compromises its conceptual integrity, which is a rather important consideration [1].  I am interested to see which additional suggestions for a solution will be produced by this thread.

- Eran


[1] - Fred Brooks, The Mythical Man Month, Chapter 4, pages 42 and forward. 


--

Jim Evans

unread,
Feb 22, 2011, 7:13:39 AM2/22/11
to Selenium Developers
And C# (insofar as it works).

On Feb 22, 6:03 am, Adam Goucher <a...@goucher.ca> wrote:
> But that is only for Java...
>
> -adam
>
>
>
> > Sounds like I need to write up how to migrate from Selenium 1 to
> > Selenium 2. As a hint, take a look at switching "DefaultSelenium" for
> > "WebDriverBackedSelenium"
>
> > Simon
>
> > On Fri, Feb 18, 2011 at 11:43 PM, RamMan<mike.ram...@eloqua.com>  wrote:
> >> I have the distinction of being the first user of MikeC's Lebowski
> >> framework which by the way I highly recommend.  Lebowski (available as
> >> a Ruby Gem) is an engineering marvel and the user-extensions.js file
> >> clocks in at over 2k SLOC. Firefox 4 RC is due at the end of the
> >> month.  Since the Selenium 2 migration path looks like a steep climb,
> >> if you have a short path to getting FF4 and IE9 support under Selenium
> >> 1 then I would be very grateful to also hear it.
>
> >> On Feb 17, 10:36 pm, Santiago Suarez Ordo�ez<santi...@gmail.com>
> >> wrote:
> >>>> Excellent!! That's definitely great to know. How did you get IE9 and
> >>>> FF4 to run with Selenium 1? I'm running into errors on my end when
> >>>> using the selenium RC server.
> >>> I Don't want to derail this conversation much, the process was not long but
> >>> definitely not fun.
> >>> Let's do something, I promise I'll write the process in detail in Sauce
> >>> Labs' blog<http://saucelabs.com/blog>  next friday!
> >>> Would that work?
>
> >>> Santi
>
> >>>> Mike
> >>>> On Feb 17, 10:23 pm, Santiago Suarez Ordo�ez<santi...@gmail.com>

Ross Patterson

unread,
Feb 22, 2011, 9:49:43 AM2/22/11
to selenium-...@googlegroups.com

Se1’s user-extensions.js doesn’t appear to be an accidental property at all.  There’s an entire chapter in the documentation about them (http://seleniumhq.org/docs/08_user_extensions.html), and judging from the number of hits on Google, they’re certainly not in rare use.  In my experience and observation, the common use case is to implement some new in-browser testing capability, whether that’s a new command, a new kind of locator for existing commands, or additional safety checks.  And it’s been part of RC since almost the beginning of RC.

 

As to page load detection, well, that’s an orthogonal issue.  But I wouldn’t be surprised if the ability to inject some JavaScript early in the page-loading process would do the job for most of the people who need it – those who have AJAX applications and which are often based on a JavaScript framework that has a concept of “done loading” (e.g., Dojo’s addOnLoad(), jQuery’s ready(), YUI’s onDOMReady()) .

 

Ross

RamMan

unread,
Feb 22, 2011, 1:23:28 PM2/22/11
to Selenium Developers
Lebowski uses Ruby.

MikeC

unread,
Feb 25, 2011, 11:20:57 AM2/25/11
to Selenium Developers
Hey Patrick,

I kind of went MIA there for the last few days. Back now.

From the thread, it appears that how a page load is handled can be
tricky business in Selenium 2 in order to inject code from a user-
extension.js file. Not just that, but every time you have to make a
context switch to another frame or window, you have to load all the JS
code again if it's not already loaded, which kind of sucks. In any
case, the JS code injection should ideally be handled implicitly by
the Selenium framework, just like what happened in Selenium 1. I'm not
entirely sure what the appropriate solution is for Selenium 2 at the
moment. I'll have to give this a bit more thought given the
limitations. Let me look into this some more.

Simon: If you have migration knowledge that eases the pain when
transitioning from Selenium 1 to WebDriver, then I'm certainly all
ears to know what needs to be done. Note that my Lebowski framework is
built on Ruby, not Java, so I'll assume any advice you provide will
equally apply when using the selenium-webdriver gem.

-Mike

Aditya Ivaturi

unread,
Mar 1, 2011, 2:44:08 PM3/1/11
to Selenium Developers

> I Don't want to derail this conversation much, the process was not long but
> definitely not fun.
> Let's do something, I promise I'll write the process in detail in Sauce
> Labs' blog <http://saucelabs.com/blog> next friday!
> Would that work?
>

Any updates on this?

Santiago Suarez Ordoñez

unread,
Mar 2, 2011, 5:01:07 PM3/2/11
to selenium-...@googlegroups.com, Aditya Ivaturi
Sorry for the delay, you know how things work in the open source world :)
I'm planning to get this blog post out by the end of next week. I'll keep you guys updated in the dev list.

Santi

Simon Stewart

unread,
Mar 3, 2011, 9:00:04 AM3/3/11
to selenium-...@googlegroups.com
Hi Mike,

I've got as far as checking the lebowski code out of git so that I can
have an amble through it and give some concrete suggestions. For now,
some generalities will have to suffice.

There's a couple of avenues to explore. The first thing that we do
with the webdriver-backed selenium. In this case, we make use of the
closure compiler (though any minifier would work) to extract
individual methods that can be executed as standalone scripts. This
avoids the overhead of having to parse and deal with unnecessary
functions in the JS.

The second thing is to take advantage of the JS already in the app.
For example, a common request from users is to be able to use jquery
for finding elements. A vast number of sites already use jquery
(indeed, it's the desire to use existing locators that tends to drive
the "I'd like to use jquery" requests), so there's no need to inject
it into the page: a simple "executeScript" is all that's needed. This
mechanism is more useful when using the webdriver apis because
"executeScript" can take arguments (so no more string concatenation)

This second approach also hints at another alternative, which is to
make use of proxy that will inject the scripts into pages under test.
The BrowserMob proxy was spun out of the one in the selenium project,
and so might well be able to handle this use case.

Of course, there will still be problems to do with isolating the AUT
from the JS that's being executed. In this case, we might have to
explore browser-specific approaches such as making use of firefox or
chrome extensions. I guess that Safari can do the same thing too.

The final thing to do is to emulate the behaviour of Selenium 1. That
is, use JS to open a window separate from the AUT, and load the
equivalent of the user-extension into that. The load is done once for
the lifetime of the app. Having done this, however, you're going to be
constrained to abiding by the rules of the JS sandbox. This isn't too
onerous, as this limitation is already present for user-extensions.

So, there's some ideas. What are your thoughts?

Simon

MikeC

unread,
Mar 17, 2011, 2:27:22 PM3/17/11
to Selenium Developers
Hey Simon,

Thanks for you feedback. Sorry about not getting back to you sooner on
this. Moving from the east coast to the west coast can be dizzying
experience :P.

I'm going to mull over you suggestions some more and will get back to
you shortly.

-Mike

MikeC

unread,
Mar 24, 2011, 5:12:21 PM3/24/11
to Selenium Developers
Hey Simon,

Finally had a chance to mull over your suggestions.

Accessing DOM elements is the simple case. It's all the additional JS
functionality I've written in the user-extensions file to simplify
working with the SproutCore framework. With that being said, the last
option you raise to emulate Sel1 seems the most appropriate to me, at
least for the time being. This at least means that all the JS code in
the user-extensions file doesn't have to keep being reloaded each time
you switch context to an opened window or frame. I'm fine with being
constrained by the JS sandbox for now since this at least makes the
transition to WebDriver easier.

As for the other suggestions, the idea of injecting the user-extension
JS code to the page under test concerns me since it pollutes and may
have nasty side-effects. I rather keep the user-extension code
isolated from the page under test despite some of the limitations.
Regarding the use of WebDriver's executeScript, again, the problem
with using it to execute individual snippets of JS code is that all of
the code in the user-extensions file has to be chopped up and turned
into strings planted in a Java/Ruby/C# file. Not great since it limits
your ability to do static checking with something like JSLint,
scatters the JS code across multiple files, and removes the ability to
use other JS features that come with common code editors.

-Mike
> > > tricky business in Selenium 2 in order to inject code from auser-> > extension.jsfile. Not just that, but every time you have to make a

Simon Stewart

unread,
Mar 24, 2011, 7:05:06 PM3/24/11
to selenium-...@googlegroups.com
Hi Mike,

Thanks for the replies. I've spent a (very short) bit of time looking
at the lebowski code. I'm wondering whether you've already come across
the Closure Compiler? It's a javascript compiler that takes JS as
input and outputs more JS. It provides a lot of the functionality of
something like JsLint, and it's what we use on the selenium project to
allow us to take nicely formatted and annotated JS and compress the
heck out of it. From my scan of the code, it looks like Lebowski could
work with this with some manageable changes.

That's a really long way of saying that the concern about chopping up
the JS need not be the problem you're suggesting.

http://closure-compiler.googlecode.com

Cheers,

Simon

MikeC

unread,
Mar 27, 2011, 8:34:40 PM3/27/11
to Selenium Developers
Hmm, interesting. I'll have to look into the Closure Compiler.

I think from a high-level approach, it would be nice if you supply
Sel2 with an optional user-extensions parameter in the command line
which will trigger WebDriver to first open a new window that will
contain all the user-extensions JS code. In turn, another window is
opened to contain the page under test (PUT) but so long as the user-
extension JS code in the other window can access the JS/DOM in the
PUT. Since there is still some useful functionality in the Selenium JS
core, it would be great if it can also be loaded, minus any code
related to polling the selenium server like in Sel1. That would help
with the transition over to sel2.

In any case, it appears that you and I are coming to a common
consensus on what probably needs to be done to Sel2, so that's good
news. Thanks for all your feedback on the matter :-).

-Mike

On Mar 24, 4:05 pm, Simon Stewart <simon.m.stew...@gmail.com> wrote:
> Hi Mike,
>
> Thanks for the replies. I've spent a (very short) bit of time looking
> at the lebowski code. I'm wondering whether you've already come across
> the Closure Compiler? It's a javascript compiler that takes JS as
> input and outputs more JS. It provides a lot of the functionality of
> something like JsLint, and it's what we use on the selenium project to
> allow us to take nicely formatted and annotated JS and compress the
> heck out of it. From my scan of the code, it looks like Lebowski could
> work with this with some manageable changes.
>
> That's a really long way of saying that the concern about chopping up
> the JS need not be the problem you're suggesting.
>
> http://closure-compiler.googlecode.com
>
> Cheers,
>
> Simon
>

Leo Arias F.

unread,
Mar 30, 2011, 8:08:49 PM3/30/11
to Selenium Developers
Hello,

This has been a great discussion. But it is not clear to me what's the
proposed approach to add custom locators to Selenium 2.

The testing framework I'm working on has to use SmartClient (
http://www.smartclient.com/product/scOverview.jsp ), and it has a
crazy way for locating elements. They provide a user-extensions.js
with a custom locator to be able to use it with selenium 1. Right now
I'm trying to migrate to selenium 2, but I don't really now how to
migrate that custom locator.

thanks,
pura vida.

Simon Stewart

unread,
Mar 31, 2011, 6:10:53 PM3/31/11
to selenium-...@googlegroups.com
Is there a link to the custom locator?

Simon

Leo Arias F.

unread,
Mar 31, 2011, 3:17:15 PM3/31/11
to Selenium Developers
Nevermind, I've just found AddLocationStrategy (
http://code.google.com/p/selenium/source/browse/trunk/selenium/src/java/org/openqa/selenium/internal/seleniumemulation/AddLocationStrategy.java?r=7954
)

For my case using the BackedSelenium driver, something like this will
work:
Selenium selenium = new WebDriverBackedSelenium(driver, baseUrl);
selenium.addLocationStrategy("scLocator", "return
inWindow.isc.AutoTest.getElement(locator);");

And when I migrate completely to the RemoteWebDriver, the
implementation of elementFinder.add in that class gives me good
pointers to start.
A documentation page with the instructions to add a custom locator
would be really useful. I can help you with that later, when I start
implementing mine.

Thanks for the great work. Selenium2 rocks!

pura vida.

Adam Goucher

unread,
Apr 1, 2011, 12:13:54 PM4/1/11
to selenium-...@googlegroups.com
On 11-03-31 3:17 PM, Leo Arias F. wrote:
> Nevermind, I've just found AddLocationStrategy (
> http://code.google.com/p/selenium/source/browse/trunk/selenium/src/java/org/openqa/selenium/internal/seleniumemulation/AddLocationStrategy.java?r=7954
> )
>
> For my case using the BackedSelenium driver, something like this will
> work:
> Selenium selenium = new WebDriverBackedSelenium(driver, baseUrl);
> selenium.addLocationStrategy("scLocator", "return
> inWindow.isc.AutoTest.getElement(locator);");
>
> And when I migrate completely to the RemoteWebDriver, the
> implementation of elementFinder.add in that class gives me good
> pointers to start.
Would you not need to a browser-specific implementation of your locator
for each browser you want thought? So in the FF extension, and in C++
for IE? I seem to think I saw mention of that in a different thread.
With Se-RC you can just inject things willy-nilly, but due to how the
WebDriver stuff is created you cannot.

-adam

MikeC

unread,
Apr 5, 2011, 2:20:09 AM4/5/11
to Selenium Developers
Hey all,

Just an FYI that I had a chance to sit down with Simon at the Selenium
conference to work out this user-extensions file issue. To keep it
brief, there is thankfully a solution to migrate your code in the user-
extensions.js over to Selenium 2; however, it's admittedly not really
obvious without some guidance and knowledge of how WebDriver works. It
requires the use of both Google's Closure Compiler and WebDriver's
atoms feature. I'm going to migrate my JS code for my Lebowski
framework and will write a blog post explaining how to migrate the
code.

-Mike

On Apr 1, 9:13 am, Adam Goucher <a...@goucher.ca> wrote:
> On 11-03-31 3:17 PM, Leo Arias F. wrote:> Nevermind, I've just found AddLocationStrategy (
> >http://code.google.com/p/selenium/source/browse/trunk/selenium/src/ja...

Ross Patterson

unread,
Apr 5, 2011, 8:22:42 AM4/5/11
to selenium-...@googlegroups.com
Thanks, I'm looking forward to learning from your experience!

Ross

QA_manager

unread,
Apr 5, 2011, 8:49:12 AM4/5/11
to Selenium Developers
Please provide a link to your documentation here, so others can
benefit from your knowledge, and Thank You for contributing!

Leo Arias F.

unread,
Apr 6, 2011, 11:49:01 AM4/6/11
to Selenium Developers
On Apr 1, 10:13 am, Adam Goucher <a...@goucher.ca> wrote:
> Would you not need to a browser-specific implementation of your locator
> for each browser you want thought? So in the FF extension, and in C++
> for IE? I seem to think I saw mention of that in a different thread.
> With Se-RC you can just inject things willy-nilly, but due to how the
> WebDriver stuff is created you cannot.

I don't think I need a browser-specific implementation, because I'm
using the RemoteWebDriver.

What I did was a subclass of RemoteWebDriver with the following
function:

@Override
public WebElement findElementByScLocator(String using) {
if (using.contains("scLocator=")) {
using = using.replace("scLocator=", "");
}
using = using.replaceAll("\"", "'");
return (WebElement) executeScript(String.format(
"return window.isc.AutoTest.getElement(\"%s\")", using));
}

I also made an interface FindsByScLocator with the declaration of that
function, and a subclass of By copying the way that the
findElementByXXX function is called.

Is this the right way to add a custom locator?

Simon Stewart

unread,
Apr 11, 2011, 6:50:07 AM4/11/11
to selenium-...@googlegroups.com, Leo Arias F.
Subclassing By is absolutely the correct thing to do.

Simon

Reply all
Reply to author
Forward
0 new messages