This section is maintained by the qooxdoo community. Here is how you can contribute.

Simulator

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

The following instructions apply to Selenium RC versions >=0.9.x.

This page details various pieces that were added around the Selenium technology to integrate it with qooxdoo.

:contrib:project:feedreader_selenium-500x400.png Selenium testing the qooxdoo Feed Reader

Specifically, the project currently contains:

  • a so-called user extension to Selenium Core. It is written in Javascript and adds commands and so-called "locators" to Selenium Core
  • 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:

Selenium User Extension for qooxdoo

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.

Installing in Selenium IDE

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.

Installing in Selenium Remote Control

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:

Linux, Mac OSX or Cygwin

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.local with your system paths
  • Run the make command:
make selenium-server-ext

Windows

On plain Windows, follow these steps, making sure to use the correct path of your Selenium RC installation:

  • Go to the tool directory of your Simulator SVN checkout and create a directory script with a subdirectory selenium-server.
  • In the new selenium-server directory, 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.js into the file tool\script\selenium-server\core\scripts\user-extensions.js
  • Create an updated JAR file:
jar cmf selenium-server\META-INF\MANIFEST.MF selenium-server.jar -C selenium-server .

Starting the Selenium RC 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
Available Server Commands

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 …

Web Proxying

Another important aspect of Selenium RC is its working as a web proxy. This is to overcome the Same-Origin-Policy. The browser that is launched by the Selenium server uses this server as a proxy for all web requests. Selenium provides an initial URL from the domain to be tested, so further page requests to this domain appear as if from the same domain whereas the initial page (a frameset) is fully controlled by Selenium. This allows pages retrieved later to be controlled by the Selenium JavaScript engine.

Selenium RC Language Bindings

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.

This effort has been factored out to a large extend, and the Selenium RC package comes with a growing set of language bindings (Java, PHP, Perl, Python, …). These language bindings usually provide a language-specific API so you can easily write code that communicates with the server. The API takes care of the underlying application protocol, marshalling of commands and parameters, HTTP-specific issues and so on. Obviously, the standard language bindings only support the standard commands of Selenium. Since we want to make use of the qooxdoo user extension to Selenium core, we have to provide a thin layer on top of the standard API that adds support for the additional commands. Currently, this is provided for Python, Perl and Java, and - by using Rhino - also for JavaScript.

Perl

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;

Python

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/")

Java

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

JavaScript

The fact that Selenium RC has a Java client driver (now with qooxdoo support) means that you can also write your tests in JavaScript, using Mozilla's Rhino.

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:

java -cp  'selenium-java-client-driver.jar:js.jar' org.mozilla.javascript.tools.shell.Main

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 simulation section of the Simulator distribution, and the Selenium JavaScript language binding page for more information on testing from JavaScript.

Automated Simulation

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

After that you can invoke e.g. a JavaScript-based test like this:

java org.mozilla.javascript.tools.shell.Main test_showcase.js

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:

export CLASSPATH=<PATH_TO>/selenium-java-client-driver.jar:<PATH_TO>/js.jar

where <PATH_TO> points to the directory where you have stored the respective jar file.

Distribution Aspects

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

Interactive Simulation

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 build in the Simulator/trunk directory. 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):
    cmd=getNewBrowserSession&1=*firefox&2=http://localhost

    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:
    cmd=open&1=http://localhost/path/to/Simulator/trunk/build/index.html

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

Writing Selenium Tests for qooxdoo Apps

Writing Selenium tests for qooxdoo apps is treated in their own dedicated pages.

Overview

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.

Inspector

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.

Enhanced Screenshots

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 captureScreenshot command 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.java class 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.

Applying the Patch File

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
  • Selenium.java and DefaultSelenium.java, from the selenium-java-client-driver-sources.jar
  • SeleniumDriverResourceHandler.java, from the selenium-server-sources.jar
Procedure
  • To make use of it, locate the source files in the SRC distribution. Copy the files to the Simulator contrib tree, in the tool/selenium/server path.
  • 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_driver folder 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.py somewhere in your PYTHONPATH. (Again, to make use of the extra functionality provided with Simulator, you also need the derived class qxSelenium.py from tool/selenium/client_driver in your PYTHONPATH).

Getting on with the new captureScreenshot command

  • This new captureScreenshot method 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 getViewport command 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 captureScreenshot with 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)

Related Information

  • Selenium Users Google group that mention qooxdoo
  • qooxdoo mailing list postings that mention Selenium

Requirements

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.
  • Rhino, if you want to use JavaScript for test scripts, which in turn depends on the JDK
  • 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.

Tips and Tricks

  • 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 rlwrap in front of the normal invocation, e.g.
    rlwrap java -jar selenium-server.jar -interactive