This project provides an automation and testing environment for qooxdoo applications. It can be used to simulate user interaction in an actual web application. The Simulator is hosted as a project in qooxdoo-contrib.
It uses the well-known Selenium test tools. For more information about Selenium, see its homepage (http://www.openqa.org/selenium).
This page details various pieces that were added around the Selenium technology to integrate it with qooxdoo.
Specifically, the project currently contains:
- extensions to the Selenium Remote Control (Selenium RC or short SRC) language bindings that let you take advantage of the core qooxdoo extensions
- actual tests (or "simulations") that make use of these language bindings to automate qooxdoo applications through Selenium RC
- a small Skeleton-based qooxdoo application with an embedded Selenium RC shell
All these elements are further elaborated on now. But before we dive in…
Quick links to stuff that goes beyond the contents of this page:
- SVN repository view; for check-out use
svn co https://qooxdoo-contrib.svn.sourceforge.net/svnroot/qooxdoo-contrib/trunk/qooxdoo-contrib/Simulator
The Simulator project provides a qooxdoo-specific user extension to Selenium Core. It is based on a version originally developed by Robert Zimmermann. There is a brief page on the Selenium wiki for this user extension, which is basically a pointer to the current page. Old versions of the user extension are kept there for historical reasons (please don't use them). While some parts of the Simulator project might be instructional and even working without the user extension, the whole purpose of the project is actually to leverage it. User extensions are Selenium's way to add custom code to the Selenium Core, e.g. to provide specific commands or locators (this is Selenium speak). The actual contents of qooxdoo's user extension for Selenium is documented on its own page.
There are several ways to deploy the qooxdoo-specific user extension.
In Selenium IDE, the Selenium Integrated Development Environment, it's easy to add the user extensions. Just open Options | Options… and enter the path to the qooxdoo-specific user extension file in "Selenium core extensions (user-extension.js)".
Note that the Firefox addon
All-in-One Gestures is not compatible with some Selenium commands.
An easy way to integrate the qooxdoo Selenium extensions in Selenium RC is to start the server with the -userExtensions command line parameter:
java -jar selenium-server.jar -userExtensions user-extensions.js
Note that the file name must be
user-extensions.js, so you'll need to either copy and rename the
user-extensions-qooxdoo.js file from the Simulator contrib or create a symbolic link.
Alternatively, you can include the user extensions in the server JAR file:
- Download and extract the Selenium RC package as described in the manual.
- Next you will have to repackage the server JAR file in order to include the qooxdoo selenium user-extension. There are two ways, depending on your operating system:
On any of those Unix-like systems you can use the Makefile in your Simulator SVN checkout to automatically repackage the Selenium server JAR file:
- Update the variables in
Makefile.localwith your system paths
- Run the
On plain Windows, follow these steps, making sure to use the correct path of your Selenium RC installation:
- Go to the
tooldirectory of your Simulator SVN checkout and create a directory
scriptwith a subdirectory
- In the new
selenium-serverdirectory, unpack the Selenium RC server jar file:
jar xf C:\selenium-remote-control-0.9.2\selenium-server-0.9.2\selenium-server.jar
- Copy the contents of
tool\selenium\user_extension\user-extensions-qooxdoo.jsinto the file
- Create an updated JAR file:
jar cmf selenium-server\META-INF\MANIFEST.MF selenium-server.jar -C selenium-server .
When you now start the Selenium RC server, the qooxdoo user extensions will be available. This is the usual way to start the server:
java -jar selenium-server.jar
The sever will open and listen on a port (default: 4444) on your machine. You can send HTTP requests to this port which will instruct the server what to do. Among the things the server is able to do are starting a web browser, opening a URL in this browser and simulating user interactions on the loaded page. You can start multiple (browser) sessions on the same server. It also features an interactive mode where the server reads commands from the shell where you started it (add
-interactive to the above command).
java -jar selenium-server.jar -interactive
For a full list of available server commands see the Selenium homepage (e.g. http://release.openqa.org/selenium-core/0.8.0/reference.html) and the server documentation that comes with the download package. Unfortunately, this Javadoc documentation is not available online. Check the Javadoc for the Java language bindings and look for the
DefaultSelenium class documentation. Even more unfortunate, you will realize that the list of Selenium core commands and the list of server commands and the list of commands provided by the API are not identical …
Driving the Selenium RC server through its interactive mode or through hand-crafted HTTP requests is possible but tedious and a case of re-inventing the wheel over and over. For real test scripts you would want to have an API (or language binding) you can program against.
The QxSelenium Perl bindings extend the WWW::Selenium module, available e.g. from CPAN. Tests are written using a QxSelenium instance:
use QxSelenium; my $sel = QxSelenium->new( host => "localhost", port => 4444, browser => "*firefox3", browser_url => "http://demo.qooxdoo.org" ); $sel->start; $sel->open("http://demo.qooxdoo.org/current/feedreader/index.html"); $sel->qxClick("qxhv=*/[\@label=\"Add\"]"); $sel->pause(5000); $sel->stop;
In order to deploy the Python-specific interface class all you need to do is to put both the standard Python API classes as well as the
qxSelenium class in your
PYTHONPATH. This will allow you to import the Python interface like
from qxSelenium import qxSelenium sel = new qxSelenium("localhost",4444,"*firefox","http://localhost/")
In order to deploy the Java-specific interface class you first have to compile the Java source code, e.g. like
javac -cp <PATH_TO_selenium-java-client-driver.jar> QxSelenium.java
You then add the resulting
.class file to the
selenium-java-client-driver.jar, in the
com/thoughtworks/selenium folder. This allows you to continue using the
selenium-java-client-driver.jar, now with qooxdoo support added. Some sample commands to achieve this with
jar, the Java archiver:
jar xvf selenium-java-client-driver.jar com/thoughtworks/selenium cp QxSelenium.class com/thoughtworks/selenium jar uvf selenium-java-client-driver.jar com/thoughtworks/selenium/QxSelenium.class
To use the new interface class, instantiate it in your tests code (the Java client driver package has lots of test samples).
Download and unpack Rhino from its web site. All you need to actually invoke Rhino is its jar file,
js.jar. To use Rhino's interactive shell, start Rhino with a classpath that includes both Rhino and the Selenium Java client driver:
You can now import and instantiate a driver object that supports the qooxdoo extensions:
importClass(Packages.com.thoughtworks.selenium.QxSelenium); var sel = new QxSelenium("localhost",4444,"*firefox","http://localhost");
See a sample
.js file in the
test section of the Simulator distribution contains actual test/simulation scripts that use all this infrastructure to drive qooxdoo applications through Selenium RC.
The most important thing to note here is that all test scripts require a running instance of the Selenium RC server, so this has to be started beforehand (see above).
This assumes that the necessary libraries are in your CLASSPATH environment variable (so you can omit the
-cp option to java). Here is how you would set this on bash/ksh like shell:
<PATH_TO> points to the directory where you have stored the respective jar file.
So far, we have touched on various components in a Selenium-based scenario:
- the Selenium RC server
- the test/simulation scripts
- the browser that is started by Selenium RC to run the tests in
- the "application under test" (AUT), i.e. the web application to be tested which is hosted on a web server
From those components, only the Selenium RC server and the browser instance have to run on the same machine. Both the AUT and the test scripts can be remote to the Selenium RC server. This means you can run the test script on one machine, talking to a Selenium RC server on a second machine, which starts a local browser, in which a web app is being loaded from a third machine. On the other hand, everything can be run on the same machine (For a diagrammatic overview, see http://wiki.openqa.org/download/attachments/2005/selenium-rc-overview.pdf).
Instead of running complete test scripts you might want to start with playing with the Selenium server commands. The final part of the project is a small Skeleton-based qooxdoo application. It adds only a few more widgets to the standard Skeleton, but features also an internal window with a simple interactive Selenium RC shell that allows you to send commands to a running Selenium RC server. This allows you to play with the server commands and remote execution of qooxdoo widgets. Here is a recipe on how to use it:
- Run a
make buildin the
Simulator/trunkdirectory. This will create a self-contained version of the sample application.
- Export the built application by a running web server. This is necessary for the Selenium server to retrieve the application. For the sake of this example, let's assume this web server is running on your local machine.
- In order to make use of the remote command window, a Selenium RC server instance has to be running on your system, and the sample app has to be loaded through it. For easiest setup, start the Selenium server in interactive mode:
java -jar selenium-server.jar -interactive
- From the server shell, launch a new browser session providing localhost as the base test domain (assuming you are using Firefox for testing):
This should bring up a new browser window with three frames, two of which are already occupied by Selenium output.
- Then, also from the server interactive command line open the test URL:
This should load the sample app in the third frame of the browser window.
- Use the pop-up window entitled "Selenium Shell" to enter Selenium commands that will be executed in the current application. This is what you could enter:
Command: qxClick Param1: button [Send] Command: qxClick Param1: First [Send] Command: qxClick Param1: Second [Send]
- To terminate your test session, enter the following command:
command: testComplete [Send]
This will close the browser window.
- In order to terminate the Selenium server, on the server shell type:
Writing Selenium tests for qooxdoo apps is treated in their own dedicated pages.
This page gives a fundamental introduction to writing tests for qooxdoo apps which treats the various aspects that are specific to those apps and how to go about them.
To aid you with creating suitable locators (the most crucial task when writing Selenium tests) you can use qooxdoo's Inspector, which features a dedicated Selenium tool. The manual for the Inspector has more about it.
One of the features of SRC is its ability to take screen shots. We have tried to enhance this ability (everything in this section refers to the SRC 0.9.2 release).
- The default
captureScreenshotcommand captures the whole screen. This makes it hard to compare screenshots of the same web page taken at different times since you have all this visual line noise of desktop, browser chrome and other windows around.
- Therefore, we wanted to capture only the part of the browser that actually renders the page content (sometimes referred to as the 'viewport'). Since SRC uses Java AWT to capture regions of the screen, we just had to add a server method that takes an additional parameter that specifies the region to capture.
- To that end we have created a modified version of the
SeleniumDriverResourceHandler.javaclass file of the Selenium server. License issues are currently being sorted out, but meanwhile there is a patch file that when applied will add the new functionality to the server. You can get it here.
The patch file from the above link covers more than one source file. Beyond the extension of the Selenium RC server code, there are minor fixes in the client drivers for Java and Python. All files belong to the standard SRC 0.9.2 release, but since the SRC package contains other archives which in turn contain the source code, there is no canonical source tree to apply patches to. So the best way seems to be to collect the various files in a single directory, and then apply the patch to them.
Currently, the following files are affected by the patch:
selenium.py, from the selenium-python-client-driver-0.9.2 directory
DefaultSelenium.java, from the selenium-java-client-driver-sources.jar
SeleniumDriverResourceHandler.java, from the selenium-server-sources.jar
- To make use of it, locate the source files in the SRC distribution. Copy the files to the Simulator contrib tree, in the
- Apply the patch to the files and run the make target
selenium. Make will spot the Java files and include them into the custom jar's (server and client driver) that are being created. Now the two-argument version of the captureScreenshot command will be available in the custom server.
- There will also be a patched version of the Java client driver. (This fixes the core functionality of the client driver, and is not to be confused with the derived class in
tool/selenium/client_driverfolder of the Simulator, which builds on top of that and supports extra commands).
- If you rather use Python for the client access, copy the
selenium.pysomewhere in your PYTHONPATH. (Again, to make use of the extra functionality provided with Simulator, you also need the derived class
tool/selenium/client_driverin your PYTHONPATH).
- This new
captureScreenshotmethod takes an X11 '-geometry' like string as its second argument. They look like
1200x600+100+250, and this reads "Take the region of width 1200 pixel, height 600 pixel, right and downward from the point at 100 pixel off the left and 250 pixel off the top of the screen boundary".
- The next issue was to automatically compute those screen coordinates of the browser viewport. To that end we have created a new SRC custom command in the user-extension.js file, namely
getViewport. This command computes the current geometry of the browser viewport, but in order to do this you have to - manually! - click into the viewport pane. This is necessary to trigger an external mouse event that bears all necessary data. But you have to do this only once, as long as do not move or resize the browser test window afterwards.
- Due to this dependency on an external click event, the
getViewportcommand cannot immediately return the geometry string. Rather, it gets stored in an SRC internal variable,
storedVars['ViewportStr'], which can be retrieved with another SRC built-in command,
getEval(that's where the other fixes from the patch get in).
- Now you have everything you need to call
captureScreenshotwith the geometry string. Here is a snippet of code that shows all that (using Python as the client driver). Since this uses custom SRC commands, you will also need the appropriate client driver class from the Simulator project.
## create a Selenium object and launch the browser q=qxSelenium("localhost",4444,"*firefox","http://qooxdoo.org/") q.start() ## the next one is not strictly necessary, but sensible q.open("http://qooxdoo.org") ## start getting the viewport screen coordinates q.get_viewport() ## now click with the mouse in the test window! ## you can use something like the next one to enforce this: # q.wait_for_condition("storedVars['ViewportStr']", 5000) ## this will bomb after 5secs, if the click is missing! ## after the click, we can retreive the geometry string geom=q.get_eval("storedVars['ViewportStr']") ## and take the screen shot q.capture_screenshot("/tmp/s1.png",geom)
Being some sort of an extension project, the bits and pieces of the Simulator are highly dependent on other software component. To make sufficient use of it here is an overview of its requirements:
- a Selenium RC server (obviously)
- a JDK; though it is not strictly mandatory (to run the Selenium RC server, a JRE suffices), it is highly recommended. It is mandatory, if you want to use the Java language bindings.
- Python, if you want to use the Python bindings
- a local web server, if you want to run tests against the contained sample application
Mind that in a production setting not all those components have to be available on the same machine (although that helps during development); see the section Distribution Aspects. For more and more detailed information about prerequisites see the
trunk/README file in the SVN package.
- On Unix-like systems and Cygwin, you can use Hans Lub's excellent rlwrap to add GNU readline/line editing support to the various shells that were mentioned on this page, like the Rhino shell or the Selenium RC server interactive mode. rlwrap adds command line editing with arrow key support and Emacs-style key bindings (
Ctrl-a→ go to line beginning,
Ctrl-e→ go to line end), command history with incremental and repetitive search (
Ctrl-r), and history retention across multiple sessions. After installation, just put
rlwrapin front of the normal invocation, e.g.
rlwrap java -jar selenium-server.jar -interactive