Application Maps
for
RRAFS and the SAFS Framework

Contents: Window DefinitionsApplication ConstantsDDVariables for Dynamic RecognitionEmbedding DDVariables for Dynamic RecognitionCoordinate-Based ReferencesModifying Child Definitions
Last Updated: 08/03/2006

Window Definitions

Application Maps for SAFS engines are implemented using the Windows INI file format. With this format the file is broken up into named sections with named items in each section. The RRAFS library's ProcessContainer tool is a very useful tool aiding in the creation of these application maps for Rational Robot. In addition, ProcessContainer stores critical information in separate reference files about the Window, its children, all the available properties, and the menu structure of the Window (if a standard menu is present). It can also help by appending data to existing INI file format application maps OR output this data to Excel for Excel-based application maps. (Use the .XLS filename extension for Excel-based application maps.)

Comparable ProcessContainer tools are being developed for Rational Functional Tester, Abbot, and other SAFS testing engines.

A sample application map Window section:

   [LoginWindow]
   LoginWindow="Type=Window;Caption=Login"

Notice that this begins a Window definition section and also contains the Window item itself. The section is denoted by the name of the Window in the brackets. The first item in the section is the same Window name followed by the string the engine needs to uniquely identify that Window during runtime. For a Window, the section name and the item name must match.

The string that uniquely identifies the Window item is specific to Robot and the newer SAFS Component Recognition algorithm. RRAFS' ProcessContainer tool usually provides the most correct string to uniquely identify a Window or child component. However, modifications might have to be made in order for the engine to consistently find the object in all situations. Of critical importance is the 'Type=<component type>' portion of this string. It is almost always required for consistent performance. For RRAFS, consult Rational's documentation for Object Scripting Recognition Methods to become familiar with the proper formatting of component recognition strings.

Now, referencing the above Window in a sample data file:

Fields:
  #1 ---- 2 --------- 3 ---------- 4 ---------- 5 ------ 6 --
   T LoginWindow LoginWindow VerifyProperty "Caption" "Login"

References are located in the application map by first identifying which section to search for an item followed by which item to retrieve. The sample above would be interpreted as follows:

"In the LoginWindow section find the LoginWindow item and verify the property called 'Caption' contains 'Login'."

If the Window has child components they would be placed in the Window section below the Window item. The example below shows the Window and child objects typically found in a simple Login prompt:

   [LoginWindow]
   LoginWindow="Type=Window;Caption=Login"
   UserIDLabel="Type=Label;Text=UserID:"
   UserIDBox="Type=EditBox;ObjectIndex=1"
   PasswordLabel="Type=Label;Text=Password:"
   PasswordBox="Type=EditBox;ObjectIndex=2"
   OKButton="Type=PushButton;Text=OK"
   CancelButton="Type=PushButton;Text=Cancel"

Referencing these items in another sample data file:

Fields:
  #1 ----- 2 ---------- 3 ----------- 4 ------------ 5 --------- 6 --
   T, LoginWindow, LoginWindow, VerifyProperty,  "Caption"  , "Login"
   T, LoginWindow,  UserIDBox ,  SetTextValue , "MyUserName"
   T, LoginWindow, PasswordBox,  SetTextValue , "MyPassword"
   T, LoginWindow,  OKButton  ,     Click

Those four lines will make the Login Window the active Window, verify the Caption is 'Login', set the username and password, and finally click the OK button. Of course, since the Window Caption happens to be part of its recognition string (not all Windows will use their Caption as part of their recognition string), the line verifying the Caption is performing a redundant test. But the line is retained here for demonstration purposes.

Contents: Window DefinitionsApplication ConstantsDDVariables for Dynamic RecognitionEmbedding DDVariables for Dynamic RecognitionCoordinate-Based ReferencesModifying Child Definitions


ApplicationConstants

Currently there is another section that is typically defined (but not required) in an Application Map. That is the ApplicationConstants section.

   [ApplicationConstants]

There are currently no predefined or required items that go in this section. However, some of the engine's routines will look in this section for certain parameters. If it finds the item in this section, it will use the value stored for that item.

One example of this is StepDriver's driver command 'LaunchApplication'. The parameter for the full pathname to the application can be a literal string OR an item stored in the ApplicationConstants section of the Application Map. The routine will first look for the item in the map, if it finds the item, it will use the item's value which will be the stored pathname. If it doesn't find the item, it will treat the string as the literal pathname for the application to launch.

A sample ApplicationConstants section in our Application Map:

   [ApplicationConstants]
   AppExecutable="c:\SomeDirectory\MyApplication.EXE"
   AnotherConstant="Something Else"

Thus, the following two data file records produce the same result:

Fields:
  #1 ------- 2 ------------ 3 -----------------------------
   C LaunchApplication AppExecutable
   C LaunchApplication "C:\SomeDirectory\MyApplication.EXE"

Details for constants that can be referenced within the Application Map will be found in the documentation for the individual commands that use them.

In addition to the above, if an engine is seeking a particular Window or Component Definition and it is not found in the expected section then the routine will resort to searching the ApplicationConstants section for the sought definition. Thus, a single definition stored in ApplicationConstants could be shared by multiple Windows.

The SAFSMAPS service provided by the SAFS Framework will take this AppMap processing one step further. If the item is not found in the ApplicationConstants section the routine will look for it in an unnamed section which, by definition, must be at the top of the AppMap file before any sections are defined.

A SAFSMAPS supported constant with no section in our Application Map:

   ;top of file
   ;can hold constants with no section definition

   DefaultConstant="Some Value"

   [ApplicationConstants]
   AppExecutable="c:\SomeDirectory\MyApplication.EXE"
   AnotherConstant="Something Else"

Contents: Window DefinitionsApplication ConstantsDDVariables for Dynamic RecognitionEmbedding DDVariables for Dynamic RecognitionCoordinate-Based ReferencesModifying Child Definitions


DDVariables for Dynamic Recognition

RRAFS and the SAFS Framework now support the lookup of component recognition strings via DDVariables. While the framework has always supported the dynamic assignment of the componentID with DDVariables, there was not a good way to dynamically create or modify recognition strings used for any given AppMap component.

The following shows how DDVariables could be used to change the componentID of a given record. The AppMap segment shows the field for entering a userid named "UserIDBox". That is the item that must ultimately be retrieved from the AppMap.

AppMap Segment:

   [LoginWindow]
   LoginWindow="Type=Window;Caption=Login"
   UserIDBox="Type=EditBox;ObjectIndex=1"

Dynamic ComponentID Usage:

   C, SetVariableValues, ^UserIDField="UserIDBox"

   T, LoginWindow, ^UserIDField , SetTextValue , "MyUserName"

In the above example, the framework will find the value of the ^UserIDField to be the literal string "UserIDBox". The framework will then use that value to lookup the recognition string inside the AppMap in the LoginWindow section. Notice, though, we have not dynamically altered the recognition string of any component. We have merely changed which component it is we want to lookup. To dynamically change a components recognition string, we need to tell the framework that the recognition string itself is to be retrieved via a DDVariable lookup.

In order to retain our ability to use dynamic component IDs and enable dynamic recognition strings we actually replace the recognition string in the AppMap itself. By inserting a predefined "_DDV:" prefix to the stored value in the AppMap we can tell the framework to do a lookup in our DDVariable storage instead.

Below are examples of just how this should work.

AppMap Segment:

   [DataWindow]
   DataWindow="Type=Window;Caption=TableViewer"
   TableCell1="_DDV:"
   TableCell2="_DDV:CellID"

Note the two TableCell entries show different usage. TableCell1 does not list a DDVariable name after the prefix. This tells the framework to use the given ComponentID as the name of the DDVariable to lookup. The framework will retrieve the value of a DDVariable named "TableCell1" and use that value as the recognition string for the component TableCell1.

The TableCell2 entry does list the name of a DDVariable, so the framework will use that name instead of the given ComponentID. The framework will retrieve the value of a DDVariable named "CellID" and use that value as the recognition string for the component TableCell2.

This is what we might find in a test table assuming the AppMap segment above.

   C, SetVariableValues, ^CellID="Type=HTMLTableCell;Index=" & ^cellIndex

   T, DataWindow, TableCell2 , Click

The framework will lookup the value of TableCell2 in the AppMap. Because of the presence of the "_DDV:" prefix the framework knows it must subsequently find the real recognition string of TableCell2 by looking up the value of DDVariable "CellID". The framework will then use that value as the recognition string for TableCell2.

Contents: Window DefinitionsApplication ConstantsDDVariables for Dynamic RecognitionEmbedding DDVariables for Dynamic RecognitionCoordinate-Based ReferencesModifying Child Definitions


Resolving DDVariables for Dynamic Recognition

The SAFS Framework SAFSMAPS service now supports resolving DDVariable references directly in an AppMap entry. That is, instead of replacing the entire recognition string with the value of a DDVariable as discussed in the last section, the AppMap entry can contain static recognition information with references to one or more DDVariables that will be resolved and embedded to complete the recognition string. Below is an example of such an entry:

   [ApplicationConstants]
   does_not_contain="contains"

   [Section1]
   EmbedVar="This string {^does_not_contain} an embedded string."
   LoginLink="Type=HTMLLink;HTMLText={^login_link}"

As a result of this feature the final 'EmbedVar' value retrieved will be:

   "This string contains an embedded string."

The second example using LoginLink shows how this feature can be useful for NLS (localization) testing. The recognition string can be provided in an App Map that is shared by all NLS test configurations. The text associated with the link--which will be different for each language tested--will be embedded dynamically at runtime based on the value of the ^login_link variable.

It is important to note the following:

Contents: Window DefinitionsApplication ConstantsDDVariables for Dynamic RecognitionEmbedding DDVariables for Dynamic RecognitionCoordinate-Based ReferencesModifying Child Definitions


Coordinate Based References

One of the problems often faced in automated testing is dealing with unsupported components.  Sometimes the tool knows they are there, but doesn't know how to deal with them.  Sometimes, the components are merely painted controls the tool doesn't even know are there.  When unsupported controls are encountered the testing tool usually resorts to actions based on X/Y coordinates of the components in the Window.

This complicates testing and verification because the controls might be at different coordinates based upon the resolution of the computer running the tests or the position of the Windows on the screen.  When your application must resort to coordinate-based testing there are some things that must be done.

  1. The tests must be setup to run with a specific screen resolution.
  2. The tests must be setup to run with a specific color scheme (palette).
  3. The tests must be setup to run with a specific  color resolution
  4. Application windows should be set to a specific size and position if they contain coordinate-based items.
  5. At playback, the test computers must be forced to the screen resolution, color resolution, and color scheme used to develop the tests.

Once all of this is in place we can start working with coordinate-based testing with fairly good success.

The Application Map allows us to provide named references for items that are unsupported by Robot and use coordinate-based activities.  One great advantage of this is that changes to the position of these items do not break our test data files.  We need merely to update the coordinate-based information once in the Application Map and every instance of its use is inherently fixed.  Additionally, items can be referenced by a meaningful name rather than an X/Y coordinate on the screen.

Currently, the most frequent use for this type of reference is for the various Mouse Click commands on Windows and GenericObjects containing painted controls.  But it is also used when defining regions for RegionImage VPs and Window's SetPosition commands.  Invariably, other uses will be implemented.  You will need to consult the documentation for the specific  command or routine for information on the syntax and use of particular coordinate-based references.

There are generally two ways that these named references get placed into the Application Map.  

The first method is when the referenced item is actually considered a child of the Window itself (vs. being a sub-item in a child of the Window).  In this instance, the named reference will actually be placed inside the Window definition section for that Window.

Example: Defining a default size and position for the Window and an unrecognized painted checkbox in our Login Window section of the Application Map:

   [LoginWindow]
   LoginWindow="Type=Window;Caption=Login"
   DefaultSizeNPosition="10,10,700,500;Status=NORMAL"
   WeirdCheckbox="200,300"

Now using the references in commands for the Window in a data file:

Fields:
  #1 ----- 2 ---------- 3 ---------- 4 ------------ 5 -----------
   t, LoginWindow, LoginWindow, SetPosition, DefaultSizeNPosition
   t, LoginWindow, LoginWindow,    Click   , WeirdCheckbox

 The second method of coordinate-based referencing is used when the referenced item is actually considered a sub-item within a recognized child of the Window.  In this case, the child of the window will have a new section in the Application Map devoted for just such special case information. This is necessary because, generally, the child of the Window is recognized by Robot as a valid object of some type (not a painted control) and needs to have a valid Robot recognition string in the Application Map.  But Robot will not be able to recognize any of the sub-items in that object.  When this is the case, we use another section to reference these coordinate-based sub-items for the engine.

Example: Defining an unknown (but findable) Generic object in our Login Window section of the Application Map.  This Generic object also contains elements that we need to interact with but Robot can only do so with coordinate-based references:

   [LoginWindow]
   LoginWindow="Type=Window;Caption=Login"
   DefaultSizeNPosition="10,10,700,500;Status=NORMAL"
   WeirdGenericObject="Type=Generic;Class=SomeClass;ClassIndex=1"

   [WeirdGenericObject]
   ThePaintedButton="20,100"
   AnotherWidget="50,150"
   LastThingy="80,150"

Now let's do some things inside that Generic object with our data files:

Fields:
  #1 ----- 2 ------------- 3 -------------- 4 ------------ 5 -----------
   t, LoginWindow,    LoginWindow    , SetPosition, DefaultSizeNPosition
   t, LoginWindow, WeirdGenericObject,    Click   , ThePaintedButton
   t, LoginWindow, WeirdGenericObject, DoubleClick, AnotherWidget
   t, LoginWindow, WeirdGenericObject, RightClick , LastThingy

It's generally easier to comprehend what's going on when looking at lines like those above then it is when looking at Robot ciphers like these below:

    Window  SetPosition, "Type=Window;Caption=Login", "Coords=10,10,700,500;Status=NORMAL"
    GenericObject Click, "Type=Generic;Class=SomeClass;ClassIndex=1", "Coords=20,100"
    GenericObject Click, "Type=Generic;Class=SomeClass;ClassIndex=1", "Coords=50,150"
    GenericObject Click, "Type=Generic;Class=SomeClass;ClassIndex=1", "Coords=80,150"

Contents: Window DefinitionsApplication ConstantsDDVariables for Dynamic RecognitionEmbedding DDVariables for Dynamic RecognitionCoordinate-Based ReferencesModifying Child Definitions


Identifying and Modifying Child Definitions

All the above information might make it look fairly simple to create these Application Maps.  Without the ProcessContainer tool, or some other tool like it, it indeed might prove to be a daunting task.  Actually, maybe it is daunting regardless!   There still is and always will be the need for manual intervention and manipulation to make a good working Application Map.

The output of the ProcessContainer tool produces child definitions that need editing to be useful for our data files.  The reference on this tool contains very useful information on modifying child definitions produced by the tool.

Contents: Window DefinitionsApplication ConstantsDDVariables for Dynamic RecognitionCoordinate-Based References