Special support for various web frameworks

Modern web applications are generally very interactive and their look and feel is comparable to desktop applications. Behind these applications is a whole zoo of web frameworks that drive them, each with a different focus and unique set of widgets. 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 worse than useless for regression testing.
  • 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 web frameworks 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.

QF-Test ships with optimized CustomWebResolver configuration for a number of frameworks:

Framework nameHomepageShort name
Angular Materialmaterial.angular.ioangular
Ext JSsencha.com/products/extjsextjs
Fluent UI Reactdeveloper.microsoft.com/en-us/fluentui#/fluentui
Flutter Webflutter.dev/multi-platform/webflutter
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
W3C ARIAw3.org/WAI/ARIA/apgaria
ZKzkoss.orgzk
Table 50.7:  Supported web frameworks

The given short name can be used in the 'Install CustomWebResolver' node category base, see subsection 50.1.2.3. 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. The short name autodetect activates this mechanism.

Web framework 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 to use a 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 development of a web framework continues, the associated CustomWebResolver may also have to be updated. Therefore, the built-in CustomWebResolvers are marked with a version number that corresponds to the version number of the framework for which the resolver was originally designed. As long as there are no incompatible changes, this CustomWebResolver can also be used for newer versions of the framework.

Older CustomWebResolvers in QF-Test still use a versioning scheme that is independent of the framework version. These will be updated to the new versioning scheme on their next update.

Web framework resolvers are activated via the 'Install CustomWebResolver' node where you can 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.