Example for WebCarConfigurator

As this approach is quite difficult to understand just via reading, we describe a sample implementation using the WebCarConfigurator in this section. You can find the WebCarConfigurator test-suite at qftest-4.7.2/demo/carconfigWeb/carconfigWeb_en.qft.

Figure 45.6:  WebCarConfigurator

As stated in the previous section we need to figure out which attribute provides the required information. This information will then be used to point to a generic class of QF-Test.
Simple class mapping

To begin with the example, we resolve the recognition of the '-5%' button in the right bottom corner. The figure below shows our goal. On the left we find the current recording without simplification steps, on the right we see the desired recording.

Current recording Simplified recording
Current recording Simplified recording
Figure 45.7:  Simplification due to simple class mapping

First you should record a simple text check or a mouse click to that button. Then jump to the recorded components via »Locate component«. There you can see that you got a component of the class DIV and an empty name. The other attributes don't provide anything useful. Please note especially QF-Test didn't record the actual text of '-5%' in any attribute. This means QF-Test has no good information for recognizing that component. There is just the geometry and the structure information. Now let's make this component more readable to us and the component recognition more robust.

Figure 45.8:  Recording of '-5%' button in WebCarConfigurator

When analyzing the recorded component more in detail we discover that there is an extra feature class with the value button. Now we can assume that a button in our project will have that particular attribute. Especially after verifying the assumption for further buttons.

So, please insert a procedure call to qfs.web.ajax.installCustomWebResolver from the standard library qfs.qft below the Extras node. As we detected the class attribute contains the class information for QF-Test. Having detected this, we can set the parameter genericClasses to button=Button. The expression button=Button means that any component of the class button will be assigned a generic class called Button. This will make QF-Test record the default features for buttons when we re-record the components. Run the procedure qfs.web.ajax.installCustomWebResolver and re-record the component. You will get the following recording:

Figure 45.9:  Recording with genericClasses in WebCarConfigurator

As you can see you got a click on component button-5_. When you jump to the recorded component you can see the class Button has been assigned the '-5%' for the feature as well and and we even got the extra feature qfs:label with that text. This component will now be treated as button by QF-Test. Of course, you should advise the development team to assign a dedicated ID to that button as well.

This simple assignment of one value can be sufficient for lots of cases, especially for buttons, menu-items or checkboxes. If your web-page doesn't contain that information in the attribute class, but in the attribute role, then you need to fill the parameter attributesToGenericClasses with the value role=button=Button instead of genericClasses. In some cases the information about the specific class will not be part of the leaf component, but in a parent component. The next section shows how to cope with this challenge.
Advanced class mapping

After the simple case in the previous section we will take a look at a more complex scenario now. Let's analyze how the textfields showing the selected price information are treated, e.g. the final price textfield. Like in the previous section we need to record some mouse clicks or text checks on those textfields. Then we need to navigate to the recorded components and analyze them. The figure below shows the current situation and our goal again.

Current recording Simplified recording
Current recording Simplified recording
Figure 45.10:  Simplification due to advanced class mapping

We got some SPAN nodes recorded. Here we have no class attribute, but an id attribute assigned. So, we can conclude that the id is very specific to the particular field. When you select its parent component, which is a TD node, you will find a class attribute with the value textfield, which corresponds to the actual component class. When you select that component QF-Test also highlights the entire textfield on the web-page. So we can assume that a component with the value textfield for the class attribute represents a textfield from a business perspective.

Figure 45.11:  Recording of SPAN textfields

So, now let's extend the parameters of our procedure call of qfs.web.ajax.installCustomWebResolver. We need to map the textfield value as generic class TextField. Therefore, we extend the parameter genericClasses to textfield=TextField,button=Button. As you can see the genericClasses parameter holds a comma-separated list.

When you delete the previously recorded component, re-run the procedure qfs.web.ajax.installCustomWebResolver, reload the web page and re-record the component you will get the following recording:

Figure 45.12:  Recording TextFields in WebCarConfigurator

The textfields will be recorded as expected and we even get rid of one level in the component hierarchy. In addition, the textfields have QF-Test specific attributes like the extra feature qfs:label assigned.

Note This example uses the parameter genericClasses like the previous one. You can edit the values of the parameter using the 'Edit row' button of the table and insert line-breaks after every comma to increase readability.

The next section show a translation for components which contain data and how to access that data afterwards. Such components represent data-tables, trees or lists and are handled as complex components by QF-Test.
Mapping of complex components like data-tables

The previously described approach will work for most standard components as buttons or checkboxes. But besides those components there are also complex components in our GUI. Those components represent data and we would like to address their content by the sub-item syntax provided by QF-Test. Those components could be tables, trees or lists. For those components we need to map the dedicated class as well as the sub-item class.

Current recording Simplified recording
Current recording Simplified recording
Figure 45.13:  Simplification for complex components

Our example is the table showing the cars of the WebCarConfigurator. Again, we need to record some clicks on the shown cars and analyze the recording. The standard recording looks like this:

Figure 45.14:  Recording of table in WebCarConfigurator

The click was recorded on a TD component, which is the child of a TR component, which is part of a TABLE component. The recorded TD component contains an extra feature class with the value dataCell. The TR component has the value dataRow, and the TABLE has the value dataTable for that attribute.

When we select the nodes and observe the component highlighting in the SUT we notice the following:

A TD node represents a cell, a TR node represents a row of a table and a TABLE node represents an entire table. Exactly those nodes need to be investigated now in order to create a good mapping to generic classes. QF-Test requires those three classes plus the header row and a header cell to resolve a table, see Mapping of Tables and TreeTables for details.

Let's start with the TABLE node. This node has a class attribute with the value dataTable. This seems to be a clear sign that any dataTable represents a table. So we select the call to the qfs.web.ajax.installCustomWebResolver again and we extend the parameter genericClasses to dataTable=Table,textfield=TextField,button=Button.

The next step is the row of the table. After selecting the TR node we can see that there is another class attribute with the value dataRow. This seems to be a clean-cut case. Now we need to add that value to the procedure call of qfs.web.ajax.installCustomWebResolver again and we extend the parameter genericClasses to dataRow=TableRow,dataTable=Table,textfield=TextField, button=Button.

Last but not least we need to analyze the TD node. Suprisingly, we find another class attribute, this time with the value dataCell. So, let's add this to our procedure call as before. Now genericClasses looks dataCell=TableCell,dataRow=TableRow,dataTable=Table, textfield=TextField,button=Button. Note that you are allowed to enter line breaks after each comma to ensure a better readability.

We will now delete the previously recorded components, run the qfs.web.ajax.installCustomWebResolver, re-load the web-page and re-record a click again.

As result we get a click with the typical QF-Test item syntax on a component like VehicleTable@Model&0 (or any other row, depending what you clicked on). In the recorded components area you will just see the Table object and no child component anymore as they are now treated by QF-Test as items of a table.

Figure 45.15:  Recording of resolved table item in WebCarConfigurator

After resolving this complex component we can proceed to the next section for the next steps.
Next steps

As shown in the previous sections our first task for testing web-projects is to figure out how QF-Test recognizes the components and to create a corresponding dictionary. This task looks rather difficult at the first glance, but its result will drastically reduce the maintenance work due to component changes or hierarchy changes in later stages of your project. This is because QF-Test uses the relevant properties of your HTML components only, and not any information available.

chapter 55 shows a full list of all generic classes for standard components and complex components like lists or trees. We recommend that you map only those components which are really required and not every existing component. It's rather simple to extend the mechanism later.

Repeating the steps of the previous example we would now continue to map other components like menu items or tabs. As the mapping would be too much for this manual we provided a full sample in the demo test-suite qftest-4.7.2/demo/carconfigWeb/carconfigWeb_en.qft in the test-case CarConfiguratorWeb Demo.Usage of CustomWebResolver.Create Vehicle with CustomWebResolver.

In order to use the created dictionary at every start of your web application you should move the procedure call to qfs.web.ajax.installCustomWebResolver into your Setup node directly after launching the browser. In case you created the Setup node via the Quickstart Wizard of QF-Test you will find a template call of the procedure in the sequence Install CustomWebResolver. That call can be parametrized accordingly.
Final steps

Besides the pure translation of web-page specifics into QF-Test classes, it's also possible to ignore certain components during recording. This is done via the parameters ignoreTags and ignoreByAttributes. However, you should do it only after you mapped most of the business components.

Finally, we would like to show the differences in the recording of the component tree as it was originally and after implementing the custom web resolver as in the demo test-case of the demo test-suite. The figure below shows the recording without any resolvers on the left and the simplified tree on the left.

Current recording Simplified recording
Current recording Simplified recording
Figure 45.16:  Simplification of WebCarConfigurator demo