Test Automation of Natural for Ajax Applications

This document covers the following topics:


General Information

Natural for Ajax is based on running HTML pages in a browser. These pages are designed as XML page layouts.

Test automation tools like Selenium (see http://docs.seleniumhq.org/) need to locate specific HTML elements in an HTML page to either check or adapt the content or to trigger corresponding events. In a Selenium test program, the developer usually passes identifiers using the Selenium Java API which enable Selenium to locate the elements for testing.

For stable automated tests, it is extremely important to use stable identifiers. For instance, rearranging controls in a layout or adding an additional control must not change the identifiers. For the most common controls, Natural for Ajax automatically generates stable identifiers, the so-called "test tool IDs". They are generated as data-testtoolid attributes into the HTML page. Test tools like Selenium can use this data-testtoolid attribute to locate the element.

The following gives a brief introduction for using stable identifiers in Natural for Ajax applications.

Enabling the Applications for Test Automation

All Natural for Ajax applications automatically generate stable identifiers for the most common controls. So a developer need not do anything to set them.

Let us have a look at the helloworld.xml page layout of the njxdemos. The most interesting controls for automated tests are the FIELD and BUTTON controls.

FIELD Control

In the following example, you see that the valueprop property is set in the FIELD control, but the testtoolid property is not explicitly set.

FIELD control

If a value for the testtoolid property is not explicitly set in a FIELD control, the HTML will contain a data-testtoolid attribute with the value of the valueprop property. This is shown in the HTML snippet below. You do not need to understand all the HTML details. The snippet just shows that a data-testtoolid attribute is automatically generated for a FIELD control; you do not have to do anything.

...
<input id="F_13" name="CC" class='FIELDInputEdit'
data-testtoolid='yourname' type="text" style="width: 185px;">
...

Caution:
The above HTML code contains the id attribute with the value F_13. Do not use this in your test tool. It will break your tests sooner or later because it is not stable. For example, if you add another FIELD control in front of the yourname FIELD control, the id of the yourname FIELD control will change its value to F_14.

BUTTON Control

In the BUTTON control, the method property is set. Again, the testtoolid property is not explicitly set.

BUTTON control

For a BUTTON control, a data-testtoolid attribute with the value of the method property is automatically generated as shown in the HTML snippet below. Again, you need not understand all the HTML details, just look at the data-testtoolid attribute.

...
<button type="button" id="B_17" data-testtoolid='onHelloWorld'
    	   style="width: 185px; height: 80px;" name="CC" 
        class="BUTTONInput">
...

XPATH Expression

With the Selenium tool, for example, you can locate the FIELD and BUTTON controls using an XPATH expression which contains the data-testtoolid value. This XPATH expression can be passed to the Selenium locator org.openqa.selenium.By.ByXPath:

By myfieldlocator = new ByXPath(".//*[@data-testtoolid='yourname"]");
By mymemthodlocator = new ByXPath(".//*[@data-testtoolid='onHelloWorld"]");

See http://docs.seleniumhq.org/ for more information about the Selenium Java API.

Explicit testtoolid

In some cases, you may not want to use the valueprop property of a control as the testtoolid. Instead, you want to specify your own testtoolid. Examples for this are layouts in which several controls are bound to the same Natural data field. You can then simply set an explicit testtoolid property for each of these controls.

Explicit testtoolid

...
<input id="F_13" name="CC" class='FIELDInputEdit'
testtoolid='myowntesttoolid' type="text" style="width: 185px;">
...

Advanced testtoolid Settings in Complex Controls

For complex controls, a single testtoolid is not enough to locate the individual parts of the control. The following table provides examples for the most common XPATH expressions for some complex controls.

Control testtoolid XPATH
ICONLIST testtoolid="myiconlist"
.//*[@data-testtoolid='myiconlist0'], 
.//*[@data-testtoolid='myiconlist1'],...
BUTTONLIST testtoolid="mybuttonlist"
.//*[@data-testtoolid='mybuttonlist0'], 
.//*[@data-testtoolid='mybuttonlist1'],...
ROWTABLEAREA2 testtoolid="lines"
.//*[@data-testtoolid='lines_table']

Rows/columns:

.//*[@data-testtoolid=’lines.items[0].<col1testtoolid>’]
.//*[@data-testtoolid=’lines.items[0].<col2testtoolid>’]...

.//*[@data-testtoolid=’lines.items[1].<col1testtoolid>’]
.//*[@data-testtoolid=’lines.items[1].<col2testtoolid>’]...
ROWTABSUBPAGES testtoolid="mytabs"
.//*[@data-testtoolid='mytabs0'], 
.//*[@data-testtoolid='mytabs1'],...
MULTISELECT testtoolid="mychoice"

XPATH for entries:

.//*[@data-testtoolid='mychoice0'], 
.//*[@data-testtoolid='mychoice1'],...

XPATH for buttons:

.//*[@data-testtoolid='mychoicebutton0'], 
.//*[@data-testtoolid='mychoicebutton1'], 
.//*[@data-testtoolid='mychoicebutton2'], 
.//*[@data-testtoolid='mychoicebutton3']...

In complex controls, you need not explicitly set the testtoolid property in the page layout. If you do not specify any testtoolid, the corresponding *prop properties such as valueprop, griddataprop, iconlistprop or pagesprop will be used.

Here is the table from above when not specifying a testtoolid explicitly:

Control *prop XPATH
ICONLIST iconlistprop="myiconlist"
.//*[@data-testtoolid='myiconlist0'], 
.//*[@data-testtoolid='myiconlist1'],...
BUTTONLIST buttonlistprop="mybuttonlist"
.//*[@data-testtoolid='mybuttonlist0'], 
.//*[@data-testtoolid='mybuttonlist1'],...
ROWTABLEAREA2 griddataprop="lines"
.//*[@data-testtoolid='lines_table']

Rows/columns:

.//*[@data-testtoolid=’lines.items[0].<col1testtoolid>’]
.//*[@data-testtoolid=’lines.items[0].<col2testtoolid>’]...

.//*[@data-testtoolid=’lines.items[1].<col1testtoolid>’]
.//*[@data-testtoolid=’lines.items[1].<col2testtoolid>’]...
ROWTABSUBPAGES pagesprop="mytabs"
.//*[@data-testtoolid='mytabs0'], 
.//*[@data-testtoolid='mytabs1'],...
MULTISELECT valueprop="mychoice"

XPATH for entries:

.//*[@data-testtoolid='mychoice0'], 
.//*[@data-testtoolid='mychoice1'],...

XPATH for buttons:

.//*[@data-testtoolid='mychoicebutton0'], 
.//*[@data-testtoolid='mychoicebutton1'], 
.//*[@data-testtoolid='mychoicebutton2'], 
.//*[@data-testtoolid='mychoicebutton3']...