This library implements an object mapper for Rational Robot. | |
Used internally by the library but not exported | |
Functions that are exported by the library | |
Process a screen of an application and generate the map for that screen | |
Creates a GUI dialog that is used to control the application mapping process. | |
Loads an application map DOM. | |
Once a map has been loaded, this function is used to retrieve the recognition string for an object. | |
Functions that are not exported by the library | |
Initializes the LogLevelNames array | |
Returns a date/time stamp for the current time, like the standard ISO 8601 date/time format minus the timezone (CCYY-MM-DDTHH:MM:SS) | |
A simple logging funtion to log strings to the global LogFile. | |
A simple logging funtion to log strings to the console. | |
This is the callback function used to process the dialog generated by the CreateAppMapDialog function. | |
This function checks to make sure all the form values have been filled in correctly | |
Returns the attributes for the given map file | |
Gets the default map path, which is {SQA_DIR_PROJECT}\testdata\maps. | |
It happens sometimes that Robot finds a child with a Name property that looks like ‘Name=parentName.childName’. | |
This helper function for getObjectNameFromRecognition performs the actual search of the recognition string for the elements that will be used to create the object name. | |
Make sure the friendly object name we’re about to use is unique. | |
This function will attempt to generate a user-friendly unique name for an object. | |
This function will create a new dom element (using the node name we supply). | |
This function will create a new dom element (using the node name we supply). | |
Stores the objects properties (as returned by SQAGetPropertyNames) into the object node | |
This function stores the coordinates of the object. | |
Get’s all the objects details that we want to save and stores them in to objectNode. | |
This function is at the heart of the mapper. | |
Uses the Snapshot function defined in the QuickSnap library to take a snapshot of an application given the applications parent window rec string. | |
Creates a new Map DOM document with the core processing instructions and the map node with the application name. | |
Open the map file given in the file name parameter and return it as an XMLDomDocument object. | |
Returns a new empty screen map node for the current screen. | |
Attempts to save the new map DOM to file on disk. |
This library implements an object mapper for Rational Robot. It produces detailed maps of an applications UI and provides routines for working with object maps in scripts.
The TestFoundry application mapping library provides routines for creating application maps as well as for using the generated maps in scripts. A seperate application, the Mkulu Map Manager is used to view and manage the actual map files that are created.
The following definitions are used in this documentation
The mapping functions (CreateAppMap, CreateAppMapDialog) are used to create or update an application map. At it’s highest level, an application map consists of one or more screen entities. Each screen entity is a logical grouping of related objects, each of which has a unique set of properties. Each object can contain zero or more child objects. The relationship between the objects in a map exactly duplicates the relationship between the objects in the UI.
Each screen has a version number associated with it. When a screen in an existing map is mapped again, the screen is stored into the map with a new version number. The map is always backed up before being written to, so it is possible to use the map manager tool to compare two maps and see what has changed between builds.
There are two ways to build a map; Visually, using CreateAppMapDialog, or programatically, using CreateAppMap.
CreateAppMapDialog provides a simple form that can be used to map an application in real time. In order to use the visual mapper, the following simple script will suffice.
'$Include "mkMapper.sbh"
'$Include "mkMapper_X.sbh"
Sub Main
Dim Result As Integer
Result = CreateAppMapDialog
End Sub
On running the above script, a dialog will appear that is grouped in to two sections, Map Settings and Screen Settings. The Map Settings are only changed once, at the begining of the map run. The Screen Settings are changed for every screen that is mapped. The settings are as follows.
Once all the fields have been filled in, clickon the Map Screen button to map the screen. At this point, the mapper dialog becomes disabled. When the screen has been mapped, the mapper dialog is re-enabled, but the three fields in teh Map Settings portion are now read only. Change the parameters in the Screen Settings section to map the next screen. When all the screens have been mapped, click Close Mapper.
The CreateAppMap does the exact same thing as CreateAppMapDialog (in fact CreateAppMapDialog calls CreateAppMap to do all the actual work). However, it doesn’t provide a UI. CreateAppMapDialog is ideal for embedding in a navigation script that traverses the application and automatically maps every screen. A trivial example appears below.
Option Explicit
'$Include "mkMapper.sbh"
'$Include "mkMapper_X.sbh"
Const APPLICATION_NAME = "Windows Calculator"
Const WINDOW_CAPTION = "Calculator"
Sub Main
Dim Result As Integer
Dim screenName As String
' Start Windows calculator
StartApplication "calc"
' Navigate to and map the standard view screen
Window SetContext, "Caption=Calculator", ""
MenuSelect "View->Standard"
screenName = "Standard View"
CreateAppMap APPLICATION_NAME, screenName, WINDOW_CAPTION
' Navigate to and map the scientific view screen
Window SetContext, "Caption=Calculator", ""
MenuSelect "View->Scientific"
screenName = "Scientific View"
CreateAppMap APPLICATION_NAME, screenName, WINDOW_CAPTION
Window SetContext, "Caption=Calculator", ""
Window CloseWin, "", ""
End Sub
Once a map has been created, the LoadMap and GetRecFromMap functions can be used to work with the map in a script or library. Loadmap is used to load a map into memory. Once a map has been loaded, GetRecFromMap can be used to retrieve the recognition string for an object. Note, only one map can be loaded at a time
You can pass either the exact location of the map XML file or the name of the mapped application in to the LoadMap routine. GetRecFromMap takes two arguments; the name of the screen that hosts the object we’re interested in, and the name of the object we want. This name is the friendly name for the object. When the map is created, each object is provided with a unique name to identify it. You can view and even change these names using the map manager. Note that the screen and object names passed in to GetRecFromMap are case sensistive.
Here’s a simple example, using the application map created in the CreateAppMap example above.
'$Include "mkMapper.sbh"
'$Include "mkMapper_X.sbh"
Sub Main
Dim Result As Integer
Dim rec As String
Dim calcResult As Variant
On Error GoTo HandleError
LoadMap "Windows Calculator"
StartApplication "calc"
Window SetContext, "Caption=Calculator", ""
MenuSelect "View->Standard"
PushButton Click, GetRecFromMap("Standard View", "PushButton8")
PushButton Click, GetRecFromMap("Standard View", "PushButton2")
PushButton Click, GetRecFromMap("Standard View", "PushButton+")
PushButton Click, GetRecFromMap("Standard View", "PushButton3")
PushButton Click, GetRecFromMap("Standard View", "PushButton6")
PushButton Click, GetRecFromMap("Standard View", "PushButton=")
result = SQAGetProperty(GetRecFromMap("Standard View", "EditBox1"),"Text",calcResult)
if result <> SQASuccess then
SQAConsoleWrite "result is " & result
Exit Sub
end if
SQACOnsoleWrite ""
SQAConsoleWrite "calcResult = " & CStr(calcResult)
Exit Sub
HandleError:
SQAConsolewrite "Error " & CStr(Err) & " @line " & Cstr(Erl)
End Sub
This module has the following dependencies
Copyright (C) 2005 Chad Ullman
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Used internally by the library but not exported
WindowOffsetX | the X offset of the main window from the windows desktop |
WindowOffsetY | the Y offset of the main window from the windows desktop |
LogFile | handle to the global log file, opened in CreateAppMap and used by logEntry |
RegEx | global VB RegExp object used for all our regular expressions |
MapFileExists | does the map file already exist? Set in openMapFile and used in saveMapFile to determine if we have to create a back up |
AtParentLevel | used by getObjectCoordinates to determine if we need to save the values for WindowOffsetX and WindowOffsetY |
MapDomDoc | the XMLDomDocument that represents our map. Needed to create any new XML elements for our map or to retrieve any elements from the map |
LoggingLevel | the level to log at, defaults to LOG_WARN |
LogLevelNames | an array of strings holding the friendly names for the logging levels |
ScreenVersion | holds the version of the screen node we’re creating |
DlgApplicationName | holds the application name from the mapper dialog |
DlgScreenName | holds the screen name from the mapper dialog |
DlgWindowCaption | holds the window caption from the mapper dialog |
DlgOutputPath | holds the file output path from the mapper dialog |
DlgLogLevel | holds the log level from the mapper dialog |
DlgRunOKOnce | tracks if we’ve succesfully executed the mapper dialog once |
AllObjectNames | associative array of all object names, used to ensure no two objects have the same friendly name in a screen |
Functions that are exported by the library
Process a screen of an application and generate the map for that screen | |
Creates a GUI dialog that is used to control the application mapping process. | |
Loads an application map DOM. | |
Once a map has been loaded, this function is used to retrieve the recognition string for an object. |
function CreateAppMap ( applicationName As String, screenName As String, windowCaption As String, Optional logLevel As Variant, Optional outputPath As Variant ) As Integer
Process a screen of an application and generate the map for that screen
alphanumerics, spaces, | and _ |
alphanumerics, spaces, | and _ |
Integer; sqaSuccess on success, >0 on failure
Function CreateAppMapDialog As Integer
Creates a GUI dialog that is used to control the application mapping process. Using this dialog, the user can navigate through the application and map multiple screens visually.
Integer; sqaSuccess on success, >0 on failure
Sub LoadMap ( map As String, Optional logLevel As Variant )
Loads an application map DOM. Once the map has been loaded, you can use GetRecFromMap to retrieve the recognition for an object.
You can specify the exact location of the map file in the map parameter, or you can use the application name that was used when generating the map, in which case the routine will automatically look for the map file in the default map file location.
Function GetRecFromMap( screenName As String, objectName As String ) As String
Once a map has been loaded, this function is used to retrieve the recognition string for an object. The recognition string is retrieved by using the screen and object names to generate an XPath expression that is applied to the map DOM.
The function requires that the map DOM has been loaded using the LoadMap routine before you attempt to call it.
Functions that are not exported by the library
Initializes the LogLevelNames array | |
Returns a date/time stamp for the current time, like the standard ISO 8601 date/time format minus the timezone (CCYY-MM-DDTHH:MM:SS) | |
A simple logging funtion to log strings to the global LogFile. | |
A simple logging funtion to log strings to the console. | |
This is the callback function used to process the dialog generated by the CreateAppMapDialog function. | |
This function checks to make sure all the form values have been filled in correctly | |
Returns the attributes for the given map file | |
Gets the default map path, which is {SQA_DIR_PROJECT}\testdata\maps. | |
It happens sometimes that Robot finds a child with a Name property that looks like ‘Name=parentName.childName’. | |
This helper function for getObjectNameFromRecognition performs the actual search of the recognition string for the elements that will be used to create the object name. | |
Make sure the friendly object name we’re about to use is unique. | |
This function will attempt to generate a user-friendly unique name for an object. | |
This function will create a new dom element (using the node name we supply). | |
This function will create a new dom element (using the node name we supply). | |
Stores the objects properties (as returned by SQAGetPropertyNames) into the object node | |
This function stores the coordinates of the object. | |
Get’s all the objects details that we want to save and stores them in to objectNode. | |
This function is at the heart of the mapper. | |
Uses the Snapshot function defined in the QuickSnap library to take a snapshot of an application given the applications parent window rec string. | |
Creates a new Map DOM document with the core processing instructions and the map node with the application name. | |
Open the map file given in the file name parameter and return it as an XMLDomDocument object. | |
Returns a new empty screen map node for the current screen. | |
Attempts to save the new map DOM to file on disk. |
Sub logEntry ( logLevel As Integer, entry As String )
A simple logging funtion to log strings to the global LogFile. Checks each log entrie’s logging level against the LoggingLevel global and if it’s less then or equal to it logs the message. Use the global LogLevelNames array to add the log level to the log message
Sub logToConsole ( logLevel As Integer, entry As String )
A simple logging funtion to log strings to the console. Checks each log entry’s logging level against the LoggingLevel global and if it’s less then or equal to it logs the message. Use the global LogLevelNames array to add the log level to the log message
Function processMapDialog ( objectID As String, action As Integer, extraInfo As Long ) As Integer
This is the callback function used to process the dialog generated by the CreateAppMapDialog function.
Integer; We always return 0
This table details how to interpret the value of extraInfo depending on the type of the control registering the event
+=============|===============================================================+
|Control | Meaning |
|=============|===============================================================|
|List box | Number of the item selected, 0-based. |
|-------------|---------------------------------------------------------------|
|Check box | 1 -> selected |
| | 0 ->cleared |
| | -1 -> grayed |
|-------------|---------------------------------------------------------------|
|Option button| Number of the option button in the option group, 0-based |
|-------------|---------------------------------------------------------------|
|Text box | Number of characters in the text box |
|-------------|---------------------------------------------------------------|
|Combo box | If action is 2, the number of the item selected (0-based) |
| | If action is 3, the number of characters in its text box |
|-------------|---------------------------------------------------------------|
|OK button | Always returns 1 |
|-------------|---------------------------------------------------------------|
|Cancel | Always returns 2 |
+-------------|---------------------------------------------------------------+
Function getDefaultMapPath As String
Gets the default map path, which is {SQA_DIR_PROJECT}\testdata\maps. As a side effect, if the default map path doesn’t exist, creates it.
This function uses the fact that the MkDir function returns a trappable exception if the directory it’s trying to create already exists.
String; the default map path
Raises an exception if the default map path doesn’t exist and can’t be created or if we can’t get the default project path
Function stripParentFromChildInName( recStr As String ) As String
It happens sometimes that Robot finds a child with a Name property that looks like ‘Name=parentName.childName’. For some reason, Robot chokes when trying to actually use this returned recognition string. This function looks for any instances of this pattern in the recognition string and strips out the parent portion of the name.
Uses the global RegEx object to do the actual replacement.
String; the cleaned recognition string
Function searchRecognitionForName ( recStr As String, elementRE As String ) As String
This helper function for getObjectNameFromRecognition performs the actual search of the recognition string for the elements that will be used to create the object name.
We strip off any parent info and only concern ourselves with the last child in the recognition string hierarchy
The algorithm used in this function is based on the fildChildRefElement function by Carl Nagle, found in the RRAFS ProcessContainer library.
String; A name for the object if it could be found given the element search expression provided, or an empty string if it couldn’t
Function ensureUniqueObjectName ( objectName As String ) As String
Make sure the friendly object name we’re about to use is unique. If it’s not, make it unique by adding a suffix. We use the global AllObjectNames dictionary to test for uniqueness
String; The unique name for the object
Function getObjectNameFromRecognition( recStr As String ) As String
This function will attempt to generate a user-friendly unique name for an object. It applie a series of patten matches against the recognition string for the object until it gets what seems to be a workable name. Then, it checks to see that the name has not already been used in this screen. If it has, it will append a number to the name to generate a unique name.
The algorithms used to determine the object name are based on the GetDefaultChildReference function by Carl Nagle, found in the RRAFS ProcessContainer library.
Once we’ve got the object name we send it through ensureUniqueObjectName to make sure no two objects in this screen have the same name
String; The name for the object defined by recStr
Function storeCDATAIntoNode ( nodeName As String, CDATA As String ) As Object
This function will create a new dom element (using the node name we supply). It then creates a new CDATA element which it stores in to the newly created node.
Object; the new node if created succesfully or Nothing on failure
Function storeTextIntoNode ( nodeName As String, data As String ) As Object
This function will create a new dom element (using the node name we supply). It then saves the text into the element. If the text is going to contain any potentially illegal characters, use the storeCDATAIntoNode function instead
Object; the new node if created succesfully or Nothing on failure
Function storeObjectProperties ( recStr As String, objectNode As Object ) As Integer
Stores the objects properties (as returned by SQAGetPropertyNames) into the object node
Integer; sqaSuccess if OK, >0 on failure
Function getObjectCoordinates( recStr As String ) As Object
This function stores the coordinates of the object. It stores the co-ordinates relative to the parent window. This means that we have to modify the results we get from Robot’s ScreenRect property, which are relative to the windows desktop.
We do this by capturing the window offsets. We know we’re dealing with the parent window because this is the only time that AtParentLevel is 1.
Object; either a new coordinates node or Nothing on failure
Function getObjectDetails( recStr As String, objectNode As Object ) As Integer
Get’s all the objects details that we want to save and stores them in to objectNode. First it get’s all the special object properties that Robot provides. Then, it calls the getObjectCoordinates and <getObjectProperties> functions to get the rest of the object properties and store them in to the object node.
Integer; sqaSuccess on pass, >0 on fail
Function processObject ( recStr as String, parentNode As Object ) As Integer
This function is at the heart of the mapper. Starting at the parent container object, it will recursively process every object and add the details to the map. After getting the object details, it always sets the global AtParentLevel to false.
Integer; sqaSuccess if everything’s OK, >0 on failure
Function takeSnapshot ( recStr As String, screenShotPath As String ) As Integer
Uses the Snapshot function defined in the QuickSnap library to take a snapshot of an application given the applications parent window rec string. Stores the screenshot as a bitmap
Integer; sqaSuccess if alls well, else something else on failure
function createNewMapFile ( applicationName As String ) As Object
Creates a new Map DOM document with the core processing instructions and the map node with the application name. The basic XML structure is
<?xml version='1.0' encoding='UTF-8'?>
<map applicationName="appname">
</map>
object; A new XMLDomDocument with the XML structure noted above
function openMapFile ( mapFilePath As String, applicationName As String ) As Object
Open the map file given in the file name parameter and return it as an XMLDomDocument object. If the file doesn’t exist, create new DOM document and return that instead
object; An XMLDomDocument
function getScreenNode ( screenName As String ) As Object
Returns a new empty screen map node for the current screen. It checks the current map to see if the screen already exists. It it does, it will get the current version number for that screen. Then it deletes the node from the DOM and creates a new empty screen node with the incremented version number.
If the screen node dosen’t exist, it will set the version of the newly created node to 1
The function takes care of adding the new screen node to the map DOM for you.
Even though XML is case sensisitive, this funcion is not when determining if a screen node matches with the screenName parameter.
As a side effect, this function sets the global ScreenVersion
<screen modified="YYYY-MM-DDTHH:MM:SS-/+HH:MM" name="NAME" version="?">
Object; a new DomElement node for the screen
function saveMapFile ( mapFilePath As String ) As Integer
Attempts to save the new map DOM to file on disk. If the MapFileExists flag is set, it will first try to rename the existing file to fileName-yyymmdd_hhmmss.xml. Then it will save the new file to disk.
There is an explicit assumption here that the file name passed in is going to work, which should be OK because in theory it’s already been checked by openMapFile. If the file path is bad, the call to mapDomDoc.save will cause Robot to crash most spectaculary, likely taking Windows explorer with it.
Integer; 1 if the map file could be saved, 0 if there was a problem
Process a screen of an application and generate the map for that screen
function CreateAppMap ( applicationName As String, screenName As String, windowCaption As String, Optional logLevel As Variant, Optional outputPath As Variant ) As Integer
Creates a GUI dialog that is used to control the application mapping process.
Function CreateAppMapDialog As Integer
Loads an application map DOM.
Sub LoadMap ( map As String, Optional logLevel As Variant )
Once a map has been loaded, this function is used to retrieve the recognition string for an object.
Function GetRecFromMap( screenName As String, objectName As String ) As String
Initializes the LogLevelNames array
Sub initLogLevelNames
Returns a date/time stamp for the current time, like the standard ISO 8601 date/time format minus the timezone (CCYY-MM-DDTHH:MM:SS)
Function getDateStamp As String
A simple logging funtion to log strings to the global LogFile.
Sub logEntry ( logLevel As Integer, entry As String )
A simple logging funtion to log strings to the console.
Sub logToConsole ( logLevel As Integer, entry As String )
This is the callback function used to process the dialog generated by the CreateAppMapDialog function.
Function processMapDialog ( objectID As String, action As Integer, extraInfo As Long ) As Integer
This function checks to make sure all the form values have been filled in correctly
Function checkDialogInput As String
Returns the attributes for the given map file
Function getMapFileAttributes ( mapFile As String ) As Integer
Gets the default map path, which is {SQA_DIR_PROJECT}\testdata\maps.
Function getDefaultMapPath As String
It happens sometimes that Robot finds a child with a Name property that looks like ‘Name=parentName.childName’.
Function stripParentFromChildInName( recStr As String ) As String
This helper function for getObjectNameFromRecognition performs the actual search of the recognition string for the elements that will be used to create the object name.
Function searchRecognitionForName ( recStr As String, elementRE As String ) As String
This function will attempt to generate a user-friendly unique name for an object.
Function getObjectNameFromRecognition( recStr As String ) As String
Make sure the friendly object name we’re about to use is unique.
Function ensureUniqueObjectName ( objectName As String ) As String
This function will create a new dom element (using the node name we supply).
Function storeCDATAIntoNode ( nodeName As String, CDATA As String ) As Object
This function will create a new dom element (using the node name we supply).
Function storeTextIntoNode ( nodeName As String, data As String ) As Object
Stores the objects properties (as returned by SQAGetPropertyNames) into the object node
Function storeObjectProperties ( recStr As String, objectNode As Object ) As Integer
This function stores the coordinates of the object.
Function getObjectCoordinates( recStr As String ) As Object
Get’s all the objects details that we want to save and stores them in to objectNode.
Function getObjectDetails( recStr As String, objectNode As Object ) As Integer
This function is at the heart of the mapper.
Function processObject ( recStr as String, parentNode As Object ) As Integer
Uses the Snapshot function defined in the QuickSnap library to take a snapshot of an application given the applications parent window rec string.
Function takeSnapshot ( recStr As String, screenShotPath As String ) As Integer
Creates a new Map DOM document with the core processing instructions and the map node with the application name.
function createNewMapFile ( applicationName As String ) As Object
Open the map file given in the file name parameter and return it as an XMLDomDocument object.
function openMapFile ( mapFilePath As String, applicationName As String ) As Object
Returns a new empty screen map node for the current screen.
function getScreenNode ( screenName As String ) As Object
Attempts to save the new map DOM to file on disk.
function saveMapFile ( mapFilePath As String ) As Integer