Qooxdoo And Selenium IDE, alternate testing system

Qooxdoo is a great framework, but the unit testing system is not so great for graphical results.
In this case, Qooxdoo’s team suggest you to use the Simulator instead, which is a great tool, but complex to start, and you still need to code many things by hands. This is painfull for rapid development.

I will show you here a new way to use Selenium with Qooxdoo, a more « normal » way :

  • We will use only Selenium IDE, the point & click version of Selenium (only one Firefox extension to install)
  • The system must have a testing environment (may be different of debug env.) and a production environment, the only difference must be Selenium ready or not
  • We want the minimum code modification from an existing Qooxdoo system
  • In general, we want the minimum code to get the fastest way to write unit test

Following thoose rules, the simulator is ok, but too long to install, too long to code too, and may require few times to get used to it. Selenium IDE is a point & click version, so a lot more faster way to write unit test.

Installing Selenium Unit test system

First of all, we will use here Firefox (it seems chrome is ready too). Firefox got a Selenium IDE plugin which is the fastest way to get a Selenium system ready. You can download and install it from here.

When it is installed, you should start it like that :
Selenium Start

Now selenium should be ready :
Selenium Ready
If you have this, everything went fine, you are now ready to build unit test for any web application (simple like full HTML one, or complex like Qooxdoo one). We can move on Qooxdoo part (we will see after everything setting up how to use Selenium).

Creating basic Qooxdoo environment

Preparing config

If you try running a simple test with Selenium, you will see Selenium completely lost, this is a Qooxdoo problem : Qooxdoo use a lots of div, most of them unamed (if I remember well, absolutely none of them are named with id or class). This makes Selenium unable to catch anything, the best he can do is to understand there is some div here, that’s all…
So, we have to create a better environment for him. Let’s start to make a simple config for it.

In the config.json of your application, we will create a « seleniumSupport » environment variable :

/* You can add this environment variable in any job, I recommand you to keep build job fresh and without selenium, the build should be the final system not the temp/testing one... So, here i use the default source job for adding selenium support to it */
"jobs" :{
  "source-script":{
    "environment":{
      "seleniumSupport":true
    }
  }
}

That’s all, this will create into qx.core.Environment a key named seleniumSupport, we will use that key to check the existence of selenium support, or not.

Preparing widget

Now the config is ready, it is not enough, we still cannot set any HTML id to help Selenium, this is how we do in Qooxdoo :

myWidget.getContentElement().getDomElement().id = "myNewId";

This got two major issue : first, it’s pretty long to type, second, if the widget is not started yet (doesn’t appear yet), the system will raise a null error exception on getDomElement, so, to correct that you should do :

if(myWidget.getContentElement().getDomElement() !== null){
  myWidget.addListenerOnce("appear", function(){
    this.getContentElement().getDomElement().id = "myNewId";
  }, myWidget);
}else{
  myWidget.getContentElement().getDomElement().id = "myNewId";
}

This start to become pretty long for a single id… If you have like 5 or 6 id because you have few elements to use with selenium, you are entering in the code matrix !

You can do almost what you want for that (keeping or not this version), I personnaly don’t like to keep it like this, so, let’s PATCH Qooxdoo.
Patch is a unused feature of Qooxdoo, it allow to patch any class of the core system (or your own), add feature, remove, or change behaviour for some class. Here we will patch one of the first UI class of Qooxdoo : the widget. We will add two properties to go faster, let’s make a Mixin for that :

/* ************************************************************************

	Licence : LGPLv3

	Version: 0.1

	Authors: deisss

	Date: 2012-08-24

	Date of last modification: 2012-08-24

	Description: This mixin allow to patch the widget ui to add HTML id supports easily. This help selenium for making better unit tests.

************************************************************************ */
/** This mixin allow to patch the widget ui to add HTML id supports easily. This help selenium for making better unit tests. */
qx.Mixin.define("MyNamespace.MPatchWidgetHtml",{
	properties:{
		/** The html id to set for container */
		containerId:{
			nullable:	true,
			init:		null,
			check:		"String",
			apply:		"_applyContainerId"
		},
		/** The html id to set for content */
		contentId:{
			nullable:	true,
			init:		null,
			check:		"String",
			apply:		"_applyContentId"
		}
	},

	members:{
		/**
		 * Set the id to the container
		 * @param value {String} New value to set
		*/
		_applyContainerId:function(value){
			if(qx.core.Environment.get("seleniumSupport") === true && value !== null){
				if(this.getContainerElement() !== null && this.getContainerElement().getDomElement() === null){
					this.addListenerOnce("appear", function(){
						this.getContainerElement().getDomElement().id = value;
					}, this);
				}else{
					this.getContainerElement().getDomElement().id = value;
				}
			}
		},

		/**
		 * Set the id to the content
		 * @param value {String} New value to set
		*/
		_applyContentId:function(value){
			if(qx.core.Environment.get("seleniumSupport") === true && value !== null){
				if(this.getContentElement() !== null && this.getContentElement().getDomElement() === null){
					this.addListenerOnce("appear", function(){
						this.getContentElement().getDomElement().id = value;
					}, this);
				}else{
					this.getContentElement().getDomElement().id = value;
				}
			}
		}
	}
});

You should of course change « MyNamespace » with your own project namespace to get it working. To use it, go into the Application (the root of your Qooxdoo App), You should get something like that (in MyNamespace.Application class) :

main : function(){
	// Call super class
	this.base(arguments);

	// Enable logging in debug variant
	if (qx.core.Environment.get("qx.debug")){
		// support native logging capabilities, e.g. Firebug for Firefox
		qx.log.appender.Native;
		// support additional cross-browser console. Press F7 to toggle visibility
		qx.log.appender.Console;
	}

	//Patching the widget class to add the mixin for HTML id's support, for selenium tests
	if(!qx.Class.hasMixin(qx.ui.core.Widget, MyNamespace.MPatchWidgetHtml)){
		qx.Class.patch(qx.ui.core.Widget, MyNamespace.MPatchWidgetHtml);
	}

The last « if » do the job : if the mixing is not patched to the qx.ui.core.Widget, we patch it. It means now every widget after this line, get the two properties contentId and containerId.
If you look at the Mixin, you will see the mixin has effect only when seleniumSupport is set to true, in other case it will be transparent.

So, the code you may write for Selenium will not appear in build environment, but only source one. In this case you can run selenium only in a source compile, not in build.

Preparing you class

To help Selenium, now you need to add some extra id where you want Selenium to write/use something, let’s take a field (like textField element), we will add to it an id :

login.setContentId("login-text-login");

Now Selenium will be able to use this field.
Note : you can use childControl also if you need, this will do like this (not used in our example, just for purpose) :

login.getChildControl("icon").setContentId("login-text-login-icon");

Let’s make a fully working example with a login page :

Selenium Testing

Now you set many ids everywhere to help selenium, lets make a full example how it works, imagine this page :
Login form
You got two fields (login and password one, with ids both), a valid and cancel buttons (with id also), and some extra buttons.

We want to test that system :

Field Id
Field Login login-text-login
Field Password login-text-password
Button valid login-submit

We want to set a login and a password, and click on valid button, and check the page changes to the good one.
Before doing this, we should wait the page to load, and check selenium is ready on Qooxdoo environment. Here is the text version of the Selenium IDE test :

Command Target Value
open YOUR URL
waitForTitle Your page title
assertEval this.browserbot.getUserWindow().qx.
core.Environment.get(« seleniumSupport »)
true
type id=login-text-login login value
type id=login-text-password password value
keyDown id=login-submit 13

Here is what it may show :
Selenium final words
The first line load the page, the second wait for Qooxdoo to load the panel login.
After that, the 3rd one check the Qooxdoo environment variable seleniumSupport, this is good to check if selenium is enabled or not for this Qooxdoo app.
After, we type something in login and password, and send « Enter » key on buttons (keycode 13).

Instead of sending a « Enter key », lets try to use the click instead : the Selenium click is not taken by Qooxdoo because a click event on Qooxdoo is not just a click event : according to Qooxdoo doc, a click event is composed of focus, mouseover, mousedown, mouseup and finally click. This is why the system does not handle the Selenium click.

So, you can create your own click like that :

Command Target Value
focus id=login-submit
mouseOver id=login-submit
mouseDown id=login-submit
mouseUp id=login-submit
click id=login-submit

Alternate way, would be to use the qxClick. In fact, the simulator just extend the Selenium to add some Qooxdoo features to it, and, especially the QxClick which allow to perform all of thooses events in a single line.
Lets try to understand how to import the simulator extension into Selenium IDE.

First of all, you have to locate the extension, basically it will be inside %QOOXDOO_FRAMEWORK%/component/simulator/tool/user-extensions/user-extensions.js, this file contains a normal Selenium extension, featuring QxClick and many others (like drag & drop). You need now just to say for Selenium where is that file :
In the selenium IDE base page, go to « Options » (on top) => « Options… », you should see the option panel, feel the user-extension.js field with the simulator file :
Selenium extension

Now you need to restart selenium (close and re-open it, don’t need to fully restart browser), after that in the list of command you should see the qxClick available :

Command Target Value
qxClick id=login-submit

And that’s it, you can use waitForTitle again to check the system was able to login correctly and change pages !

Now you have a fully working selenium unit test, with the minimum writing possible. And still clean in build version…

Final words : this article is here to show how to use normal Selenium IDE with Qooxdoo, but, Qooxdoo provide Inspector and Simulator, which are already modified version of Selenium, to work with Qooxdoo. Prefer thooses versions for a more robust test system.

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :