Special support for various web frameworks

The acronym AJAX for "Asynchronous JavaScript and XML" is generally associated with modern web applications that provide a more interactive look and feel than classical <FORM> based applications, almost comparable to desktop applications. Behind this common acronym there is a whole zoo of web frameworks that drive those applications, each with different key aspects and unique widget sets. Such frameworks pose a problem for QF-Test and in fact any automated testing tool for several reasons:

  • The actual component hierarchy is created automatically from abstract widgets like Buttons or Lists. Often each widget is implemented as a number of <DIV> nodes. This leads to very deeply nested hierarchies with very little structure.
  • IDs are either not assigned at all or automatically created and thus with regression tests worse than useless.
  • The asynchronous communication with the web server and dynamic creation of DOM nodes may cause timing-related problems.

There is no panacea to address these problems in a generic way. In most cases QF-Test can interact with AJAX applications out-of-the-box, but component recognition and performance are not ideal. Optimal testability can only be achieved with special case handling that exactly fits a given framework and takes advantage of its peculiarities.

Video The video 'Dealing with the explosion of complexity in web test automation' gives you a good idea of how QF-Test handles a deeply nested DOM structure.

For the following list of frameworks QF-Test provides resolvers for optimized handling:

Framework name HomepageShort name
Angular Materialmaterial.angular.ioangular
Ext JSsencha.com/products/extjsextjs
Google Web Toolkit (GWT)gwtproject.orggwt
ICEfacesicesoft.orgicefaces
jQuery UIjqueryui.comjqueryui
jQuery EasyUIjeasyui.comjeasyui
Kendo UI for jQuerywww.telerik.com/kendo-jquery-uikendoui
Prime Facesprimefaces.orgprimefaces
Qooxdooqooxdoo.orgqooxdoo
Rich Ajax Platform (RAP)eclipse.org/raprap
RichFacesjboss.org/richfacesrichfaces
Smart GWTsmartclient.comsmartgwt
Vaadinvaadin.comvaadin
ZKzkoss.orgzk
Table 48.6:  Supported web frameworks

QF-Test is even able to automatically detect whether one of those frameworks is used in your web application and to install the respective resolver.

AJAX resolver concepts

A web framework resolver is a set of resolvers and other methods implemented specifically for a given web framework. Most notably QF-Test tries to assign individual classes matching the high-level widgets to DOM nodes and remove intermediate nodes that are just an implementation detail. 'Name', 'Feature' and 'Extra feature' attributes are determined in a way suitable for the framework and events are simulated on the correct DOM node in a way that most closely matches user interaction. These measures drastically reduce the component hierarchy and increase the reliability and performance of component recognition and replay. Timing and synchronization are also addressed.

As a necessary consequence the components and events recorded for a given web application vary drastically with and without an active web framework resolver and are not compatible with each other. Thus the decision whether or not to use an web framework resolver should be made as early as possible, otherwise tests will either need to be reimplemented after activating the resolver or tests with and without resolver must be cleanly separated. If a resolver is available for your application you should practically always use it. The only exception is if the existing test-base is already too large, mostly complete and stable.

Implementing web framework resolvers is an ongoing process. As changes to a resolver can have consequences in terms of how components are recorded and recognized we need to make sure that you can update your QF-Test version without losing backwards compatibility with existing tests. To that end, web framework resolvers have their own three-digit versioning scheme, starting with version 1.0.0, with the following meaning:

  • A change in the minor version, e.g. 1.0.1, means that compatibility is not affected.
  • Medium version changes, e.g. 1.1.0, imply that tests recorded with a lower medium version should still replay, but recording additional sequences may record components in a different way. This is not critical, but you may want to avoid it in case the benefits of the newer version don't outweigh it.
  • A major version change, e.g. 2.0.0, can be incompatible even for replay so that manual updates or new recording of the affected components may be required.

Web framework resolvers are activated via the procedure qfs.web.ajax.installCustomWebResolver in the standard library qfs.qft where you have to provide the version to use. You can choose to specify only the major version, in which case QF-Test uses the latest medium.minor version available for this major version. This is normally the best option and used in the SUT startup sequences created with QF-Test's Quickstart Wizard (see chapter 3). Alternatively you can specify major.medium version or even major.medium.minor to use an exact version and thus run your tests with the resolver version with which they were created.

Setting unique IDs

Any web framework has its custom way of setting unique IDs. Please find details about the supported ones in the following chapter:

Angular Material

The simplest solution is to set the 'ID' attribute <div id="myId"/> for any required component.

Ext JS

You can set IDs like
var container = Ext.create('Ext.container.Container', {
id: 'MyContainerId',
... });
.

As alternative you can also call container.getEl().set({ 'qfs-id': 'myId' });. In this case you will need to implement a NameResolver for reading 'qfs-id' as name for QF-Test.

GWT

The simplest way is calling the method widget.getElement().setId("myId"); for the required widgets.

As an alternative you can also call widget.ensureDebugId("myId"). But if you want to use that method you need to modify your xxx.gwt.xml file to enable debug IDs. Add <inherits name="com.google.gwt.user.Debug"/> to the file.

It's also possible to set a custom identifier which can then be used via a NameResolver.For example call setAttribute("qfs-id", "myId") to set an 'qfs-id' attribute.

ICEfaces

The simplest solution is to set the 'ID' attribute <p:inputText id="myId"/> for any required component in the xhtml definition.

jQuery UI

The simplest solution is to set the 'ID' attribute <p:inputText id="myId"/> for any required component. Additionally, you can give an existing element an id with: $(element).attr("id","myId");

jQuery EasyUI

The simplest solution is to set the 'ID' attribute <p:inputText id="myId"/> for any required component.

Kendo UI for jQuery

You need to set the 'ID' attribute in your source code or graphical editor.

PrimeFaces

The simplest solution is to set the 'ID' attribute <p:inputText id="myId"/> for any required component in the xhtml definition.

Qooxdoo

There is no default mechanism. You can either apply a custom attribute to the generated DOM nodes or add a custom attribute to the setData method of the widget. You can evaluate those attributes in a resolver.

RAP

Starting with RAP version 2.2 a name set via widget.setData("name", "myId") is retrieved automatically by QF-Test, just as for SWT. This field can only be used if it is registered with WidgetUtil.registerDataKeys("name"); before.

For RAP versions older than 3.0.0 the following technique is also available. It is discouraged because it deviates from the SWT standard and requires additional settings for the webserver:

Call the method widget.setData(WidgetUtil.CUSTOM_WIDGET_ID, "myId"); for the required widgets.

After applying IDs to components you need to modify your webserver environment and specify the following parameter -Dorg.eclipse.rap.rwt.enableUITests=true before launching the webserver.

Note: The VM argument was renamed in RAP 2.0. For RAP versions older than 2.0 its name is -Dorg.eclipse.rap.rwt.enableUITests=true.

RichFaces

You need to set the 'ID' attribute in your source code or graphical editor.

Smart GWT

The simplest solution is to call widget.setID("id") for any required component.

Vaadin

The simplest solution is to call widget.setId("id") (widget.setDebugId("id") for Vaadin version < 7) for any required component.

You can also set a custom stylesheet class, which you could read with a NameResolver. Therefore call widget.setStyleName("qfs-id=myId").

ZK

QF-Test uses the widget ID, which is also used in the zul files, so you should get meaningful IDs for most of the objects.

The ZK framework also offers a custom IDGenerator to set such IDs. But implementing this could be quite exhaustive. In this case it might be a better choice to rely on the default mechanism of QF-Test.