Show TOC

Process documentationUsing Custom Code Patterns in CBASE Customization

 

CBTA 3.0 SP02 provides you with a set of patterns that the test engineer can reuse and adapt to create custom functions. In the Runtime Library Manager, you can write additional custom functions to be used in the test scripts to automate a test of business scenarios for which the common approach (based on default components) is not sufficient.

For more information, see Enhancing CBTA With Custom Code.

CBTA 3.0 SP2 supports the following UI technologies:

  • SAP GUI: UI framework used by SAP applications

  • WebCUIF: Layer which generates the content displayed by SAP CRM applications.

  • Unified Rendering Light Speed (LS): Layer which generates the content displayed by SAP applications, such as:

    • Web Dynpro application (ABAP)

    • Web Dynpro applications (Java)

    • Web GUI – SAP GUI content displayed in MS Internet Explorer

  • BSP: applications based on Business Server Pages

  • Java Web Dynpro: layer previously used by Java Web Dynpro applications

  • Plain HTML pages: content generated using regular HTML tags (with no, or few, scripting capabilities)

For test automation, each UI technology implicates specific challenges, most of which the test recorder and test player can handle. However, if the business scenario is highly dynamic, the default behavior is not always sufficient, so the test engineer needs to write custom functions.

Prerequisites

  • You have configured CBTA and installed the CBTA test tool on the client.

  • You have read SAP Note 1778899Information published on SAP site (CBTA – Collective Note).

  • You have read SAP Note 1926307Information published on SAP site (CBTA – Release Note for version 3.0 SP2).

Process

The following patterns are delivered by default with CBTA. SAP can deliver additional patterns via SAP Notes, depending on customer needs.

Pattern for Web Dynpro ABAP: CheckForMessages

This function searches for application messages in a message container. It verifies whether the applications report feedback, and checks for errors and warnings, for example.

Note Note

The CBTA_WEB_A_GETMESSAGEPARAM default component retrieves message parameters. It is generic and supports all Web UI technologies, but it cannot retrieve WebDynpro-specific information, such as the message type (such as error, warning, info).

End of the note.

CBTA cannot determine whether these messages are normal in the current business context, so the test script at runtime ignores them and continues. These messages may be unexpected, and there are situations in which it you should verify whether the test script can continue. As the test engineer, you can create the custom function to check the content of the message area, from the pattern, in the runtime library manager.

Signature of CheckForMessages Pattern

  • Input Parameters

    • MessageContainerUri

      URI of the HTML container displaying application messages. If empty, the function searches for messages in the message area displayed by the main document of the main window.

      Default value:: ls.rid=WDR_MESSAGE_AREA.MESSAGE_AREA.ROOTUIELEMENTCONTAINER

    • MessageType

      The message type parameter can have the following values: E = error, W = warning, and I= information

    • MessageRule

      The message rule parameter can have the following values: F = forbidden, R = required, and A= allowed

    • MessagePattern

      Not used – reserved for future use.

    • Options

      The option parameter can have the following values: /C = capture a screenshot and /e = capture a screenshot of the message area only.

  • Output Parameters

    • Output = number of messages matching the criteria

Use the CheckForMessages pattern to check whether application errors are being displayed, and to report any test execution failure. For example, the input parameters could be as follows:

  • MessageContainerURI = ls.rid=WDR_MESSAGE_AREA.MESSAGE_AREA.ROOTUIELEMENTCONTAINER

  • MessageType = E

  • MessageRule = F

  • MessagePattern = [empty]

  • Options = /c /e

Creating and Using a Custom Function

Assume that the custom function has been created by the runtime library manager, and the corresponding library Custom\CheckForMessages.vbs has been generated. The runtime library manager displays the following:

..............................

A CBTA test script can use the custom function, but it is not visible by default. You can call it by using one of the following components: CBTA_WEB_A_INVOKE_FUNCTION and CBTA_WEB_A_EXECUTE_STATEMENT.

In the following example, the CBTA_WEB_A_INVOKE_FUNCTION calls the custom code and checks for application errors:

..............................

To use the CBTA_WEB_A_INVOKE_FUNCTION component, the test engineer must specify the name of the custom library, the name of the custom function, and the values of its input parameters.

..............................

In this example, the following parameters are used:

  • LIBRARY = Custom\CheckForMessages.vbs

  • FunctionName = CheckForMessages

  • PARAMETER1 =empty because the MessageContainerUri parameter is optional

  • PARAMETER2 = message type E for Errors

  • PARAMETER3 = message rule F for Forbidden

  • PARAMETER4 =N/A

  • OPTIONS = /c /e to capture a screenshot of the message area

When you set MessageType to E (error) and MessageRule to F (forbidden), the test will fail as soon as the message container contains one or more applications errors.

The implementation has two functions (both names are replaced by the function name that the test engineer specifies when he creates the custom function):

  • The PATTERN_NAME function is a façade of the implementation; it includes exception handling which provides human-readable feedback in case of scripting errors.

  • The PATTERN_NAME_Impl function is the implementation.

Syntax Syntax

  1. Function PATTERN_NAME ( MessageContainerUri, MessageType, MessageRule, MessagePattern, Options )
  2.   On Error Resume Next
  3.   EventComponentBegin()
  4.   If ConditionsManager().CheckConditions() Then
  5.     PATTERN_NAME = PATTERN_NAME_Impl ( MessageContainerUri, _
  6.                                        MessageType, _
  7.                                        MessageRule, _
  8.                                        MessagePattern, _
  9.                                        Options )
  10.   End If
  11.   EventComponentEnd()
  12. End Function
  13. Function PATTERN_NAME_Impl ( MessageContainerUri, MessageType, MessageRule, MessagePattern, Options ) 
  14.   ...
  15. End Function
End of the code.

All SAP-delivered default components are built using this approach. This structure is recommended for all custom code. It includes the exception handling, and calls two functions that are required to make the custom code compliant with CBTA requirements.

Initialization Phase

The first statements (ImportLibrary...) of the implementation are only used to import the library the implementation depends on.

The custom function (PATTERN_NAME_Impl = "") can return a value, which is made available to the subsequent steps of the test scripts via the output parameter of the component. The code initializes the returned value to an empty string:

The next statements (IF ... END IF) validate the input parameters, and set them to their default values if they are not defined by the test script.

The function writes information to the technical traces (associated with the execution report), using the ReportDebugLog method. This can help you to troubleshoot execution problems.

Syntax Syntax

  1. ImportLibrary "WEB_WebController.vbs"
  2. ImportLibrary "WEB_WebControls.vbs"
  3. CBTA_WEB_A_INVOKE_FUNCTION
  4. PATTERN_NAME_Impl = ""
  5. If IsNull(MessageContainerUri) Then
  6.   MessageContainerUri="ls.rid=WDR_MESSAGE_AREA.MESSAGE_AREA.ROOTUIELEMENTCONTAINER"
  7. End If
  8. If IsNull(MessageType) Then
  9.   MessageType = ""
  10. End If
  11. If IsNull(MessageRule) Then
  12.   MessageRule = "F"
  13. End If
End of the code.

Implementation

The code shown below relies on the Query API to access the MS Internet Explorer window and search for UI elements in the HTML content.

For information on the Query API, see Query API for Testing of Dynamic Scenarios.

Syntax Syntax

  1. ' Preparation of the Query
  2. Dim query, filter
  3. Set query = LsController().CreateQuery()
  4. query.ParentControlUri = MessageContainerUri
  5. ' Specifying the criteria (using filters and conditions)
  6. Set filter = query.SetFilter()
  7. filter.AddCondition "tag", "=", "IMG"
  8. filter.AddCondition "ls.type", "=", "LN"
  9. filter.AddCondition "ls.application", "=", "WDR_MESSAGE_AREA"
  10. filter.AddCondition "ls.view", "=", "MESSAGE_AREA"
  11. filter.AddCondition "ls.field", "=", "MSG_LIST_ICON"
End of the code.

The query searches for images (<IMG> HTML Elements) that are children of the message container. The criteria also define conditions to only select the images that represent the message types. This is why Light Speed attributes are used here:

  • ls.type: type of the Light Speed control; LN for link

  • ls.application: Web Dynpro application name

  • ls.view: name of the view used to display application messages

  • ls.field: name of the field in the view

Additional conditions are set, depending on the message type that you are looking for. The conditions below check the name of a GIF file that represents the type of the message.

Why rely on this information to determine the type of the message because this is the only information that the Light Speed framework provides. So this code has not been delivered as a default component.

Syntax Syntax

  1. If MessageType="E" Then
  2.   filter.AddCondition "src", "{endsWith}", "ErrorMessage.gif"
  3. ElseIf MessageType="W" Then
  4.   filter.AddCondition "src", "{endsWith}", "WarningMessage.gif"
  5. ElseIf MessageType="I" Then
  6.   filter.AddCondition "src", "{endsWith}", "SuccessMessage.gif"
  7. Else
  8.   ' No filter - This will show all messages (and count them)
  9. End IF
End of the code.

The query is now defined. The next statement resolves the query and retrieves a collection of Light Speed controls that match the criteria:

Syntax Syntax

  1. Dim controlCollection
  2. Set controlCollection = query.Select()
  3. If controlCollection Is Nothing Then
  4.   ReportLog "FAILED", "PATTERN_NAME", "Operation Failed - Message container not found"
  5. Else
  6.   ...
  7. End If
End of the code.

If the collection is not empty, the implementation performs the verifications according to the MessageRule specified. The ReportLog method writes human-readable feedback in the execution report.

Syntax Syntax

  1. If MessageRule="R" Then 'Required
  2.   If controlCollection.Count = 0 Then
  3.     ReportLog "FAILED", "PATTERN_NAME", "Operation Failed - No message of type: " & MessageType
  4.   Else
  5.     ReportLog "PASSED", "PATTERN_NAME", "Message Type: " & MessageType & _
  6.                                         vbCrLf & "Number of Messages : " & controlCollection.Co
  7.   End If
  8. ElseIf MessageRule="F" Then 'Forbidden
  9.   If controlCollection.Count = 0 Then
  10.     ReportLog "PASSED", "PATTERN_NAME", "No messages of type: " & MessageType
  11.   Else
  12.     ReportLog "FAILED", "PATTERN_NAME", "Operation Failed - Message Type: " & MessageType & _
  13.                                          vbCrLf & "Number of messages: " & controlCollection.Cou
  14.   End If
  15. ElseIf MessageRule="A" Then 'Allowed
  16.   ReportLog "INFO", "PATTERN_NAME", "Number of messages: " & controlCollection.Count
  17. End If
End of the code.

This following section iterates through the collection of controls, to retrieve the text of the message associated with the IMG HTML element. The GetProperty method retrieves the innerText HTML property containing the text being displayed.

Syntax Syntax

  1. Dim childControl, associatedControl
  2. For i=0 To controlCollection.Count-1
  3.   Set childControl = controlCollection.ControlAt(i)
  4.   If Not childControl Is Nothing Then
  5.     Dim imgId, spanId
  6.     imgId = childControl.GetRelevantControl().GetLsId()
  7.     spanId = Replace( imgId, "MSG_LIST_ICON", "MSG_LIST_TEXTVIEW" )
  8.     Set associatedControl = childControl.FindElementById( spanId )
  9.     If Not associatedControl Is Nothing Then
  10.       ReportLog "INFO", "PATTERN_NAME", "Message #" & (i+1) & " - " & _
  11.                                          associatedControl.GetProperty( "innerText" )
  12.     End If
  13.   End If
  14. Next
End of the code.

The last part checks the Options parameter and captures a screenshot by calling the WEB_CaptureScreen method (associated to the WEB_CAPTURESCREEN Default Component).

Finally, the function sets the PATTERN_NAME_Impl to return the number of messages matching the MessageType.

Syntax Syntax

  1. If InStr(Options, "/c") Then
  2.   If InStr(Options, "/e") Then
  3.     WEB_CaptureScreen MessageContainerUri, "/e" ' Captures the Message Container only
  4.   Else
  5.     WEB_CaptureScreen MessageContainerUri, "" ' Capture the whole browser window
  6.   End If
  7. End If
  8.   
  9. PATTERN_NAME_Impl = "" & controlCollection.Count
End of the code.
Pattern for CRM Web Applications: SelectMenuItemByText

Some CRM applications associate a context menu that lets the user perform additional actions, to some controls. The test recorder can normally record such actions and perform them at runtime, by opening the context menu and simulating a mouse click the child item.

Unfortunately, for some scenarios the default behavior does not work, because the ID associated to the child item is not stable: The ID is different each time the CRM application runs.

So we search for the child item by text, using the SelectMenuItemByText pattern.

Use the CRM application, for example, to create an incident: business role SOLMANPRO and logical link SM-IM-CR.

The Object Spy or the Microsoft Developer Tool (F12 in MS Internet Explorer) indicate that the ID includes a server-generated GUID, so you cannot search for the item by its ID.

Signature of SelectMenuItemByText Pattern

Searches for application messages in a messages container. This function verifies whether the applications does report feedback, and checks for errors and warnings, for example.

  • Input Parameters

    • Uri: URI of the control with which the context menu is associated

    • Text: text of the child item that is to be selected. This text is case-sensitive except when the /u option is specified.

    • Parameter3: not used

    • Parameter4: not used

    • Options: several options influencing the behavior are available.

      • /u = upper-case, item selection is then case-insensitive

      • /click = When this option is set, the implementation opens the context menu by simulating a mouse click the main control, which is not done by default because a previous step of the test may have already done so.

  • Output Parameters

    • Output: set to DONE when the action has been performed. It supports the following values:

SelectMenuItemByText has 5 parameters to comply with the default component for calling custom functions: CBTA_CRM_A_INVOKE_FUNCTION. Leave Parameter3 and Parameter4 empty when calling this custom code.

Like for all other patterns, the implementation consists of two functions. The first one is a façade to the implementation which includes execution error handling statements. The second method actually performs the job.

The PATTERN_NAME fragment (see below) is automatically replaced by the final custom function name when using the Code Assistant feature of the runtime library manager.

Syntax Syntax

  1. Function PATTERN_NAME ( Uri, Text, Parameter3, Parameter4, Options )
  2.   On Error Resume Next ' Important - Exception Handling - Do not change it!
  3.   EventComponentBegin()
  4.   If ConditionsManager().CheckConditions() Then
  5.     PATTERN_NAME = PATTERN_NAME_Impl ( Uri, Text, Parameter3, Parameter4, Options )
  6.   End If
  7.   EventComponentEnd()
  8. End Function
  9. Function PATTERN_NAME_Impl( Uri, Text, Parameter3, Parameter4, Options ) 'internal
  10.   ImportLibrary "CRM_WebController.vbs"
  11.   ImportLibrary "CRM_WebControls.vbs"
  12.   PATTERN_NAME_Impl = "NOT DONE"
  13.   ...
  14. End Function
End of the code.

The first statements of the implementation initialize local variables, validate the input parameters, and write information to the traces, for troubleshooting:

Syntax Syntax

  1. Dim bodyControl, bodyElement, collection, childElement, anchors, anchor, currentText
  2. If IsNull(Uri) Then
  3.   ReportLog "FAILED", "PATTERN_NAME", "Operation Failed - Button Uri not specified"
  4. End If
  5. If IsNull(Options) Then
  6.   Options = ""
  7. End If
End of the code.

The next section checks the Options parameters, to determine whether it is necessary to open the context menu:

Syntax Syntax

  1. If InStr(Options, "/click" ) Then
  2.   CRM_WebControl_Click Uri
  3. End If
End of the code.

Note Note

The following implementation invokes the CRM_WebControl_Click method, which corresponds to the default component CBTA_CRM_CLICK.

End of the note.

Once the menu item is opened, the implementation can continue and search for child items. The following code first accesses the body of the work area, using the GetCrmControlByUri method that the CRM application controller exposes. This step waits for documents to be ready:

Syntax Syntax

  1. ' Gets the body of the current workarea
  2. Set bodyControl = CrmController().GetCrmControlByUri("crm.area=WorkArea; tag=body")
End of the code.

When the body of the document is ready, the content of the menu should be visible and the implementation can proceed. The following statements access the body HTML element using the GetHTMLElement method, and search for SPAN HTML elements using the MSHTML Microsoft API:

Syntax Syntax

  1. ' Gets the body of the current workarea
  2. Set bodyControl = CrmController().GetCrmControlByUri("crm.area=WorkArea; tag=body")
  3. If bodyControl is Nothing Then
  4.   ReportLog "FAILED", "PATTERN_NAME", "Operation Failed - Workarea not found"
  5. Else
  6.   Set bodyElement = bodyControl.GetWebControl().GetHTMLElement()
  7.   If bodyElement is Nothing Then
  8.     ReportLog "FAILED", "PATTERN_NAME", "Operation Failed - Workarea not found"
  9.   Else
  10.     Set collection = bodyElement.all.tags("SPAN")
  11.     If collection is Nothing Then
  12.       ReportLog "FAILED", "PATTERN_NAME", "Operation Failed - No SPAN HTML Elements"
  13.     Else
  14.       ReportLog "DONE", "PATTERN_NAME", "Count : " & collection.length
  15.       ...
  16.     End If
  17.   End If
  18. End If
End of the code.

The following statements do not rely on CBTA interfaces. The bodyElement implements some scripting interfaces (from the MSHTML API) and the all and tags properties return a set of objects that also implement scripting interfaces.

Syntax Syntax

  1. Set collection = bodyElement.all.tags("SPAN")
End of the code.

The collection variable contains a list of SPAN HTML elements in the work area of the CRM application. The implementation filters out the SPAN HTML elements that are not menu items by verifying whether the SPAN element has an ID including the T_MENU_ITEM fragment, and that it has at least one child element of type ANCHOR (<A> HTML tag).

The visible text of the item is associated with the ANCHOR element. Its value is retrieved by innerText property, and checked against the expected value.

Syntax Syntax

  1. For i=0 To collection.length-1
  2.   Set childElement = collection.item(i)
  3.   If Not IsNull(childElement.id) Then
  4.     If InStr( childElement.id, ":T_MENU_ITEM:") Then
  5.       Set anchors = childElement.all.tags("A")
  6.       If anchors Is Nothing Then
  7.         ReportLog "FAILED", "PATTERN_NAME", "Operation Failed - No Anchor HTML Elements"
  8.       Else
  9.         ReportLog "DONE", "PATTERN_NAME", "Child Anchors - Count : " & anchors.length
  10.         Set anchor = anchors.item(0)
  11.         CBTA.Report CBTA.INFO, "PATTERN_NAME", "Anchor Element - id=" & anchor.id, ""
  12.         currentText = anchor.innerText
  13.         If InStr(Options, "/u" ) Then
  14.             currentText = UCase(currentText)
  15.             Text = UCase(Text)
  16.         End If
  17.         If InStr( currentText, Text ) Then
  18.             anchor.FireEvent("onmousedown")
  19.             anchor.setActive()
  20.             anchor.focus()
  21.             anchor.FireEvent("onmouseup")
  22.             anchor.click()
  23.             PATTERN_NAME_Impl = "DONE"
  24.             Exit For
  25.         End If
  26.       End If
  27.     End If
  28.   End If
  29. Next
End of the code.

If the text matches the one being looked for, the implementation simulates a mouse click on the item, calling several methods exposed by the MSHTML API:

Syntax Syntax

  1. anchor.FireEvent("onmousedown")
  2. anchor.setActive()
  3. anchor.focus()
  4. anchor.FireEvent("onmouseup")
  5. anchor.click()
End of the code.

For more information, see Scripting Objects Interfaces from Microsoft under More Information.

Instead of calling methods exposed by the MSHTML API, the implementation could reuse the CRM_WebControl_Click method to select items, for example as follows:

Syntax Syntax

  1. Dim anchorUri
  2. anchorUri = "label=" & anchor.innerText & "; crm.area=WorkArea; tag=A; id=" & anchor.id
  3. CRM_WebControl_Click anchorUri
End of the code.

Limitations

The SelectMenuItemByText pattern searches for an HTML element in the body of an HTML document. The current implementation has the following limitations:

  • It does not support the selection of subitems (children of another child item).

  • It only searches for items in the main work area of the CRM application. The code must be adapted if the item is shown in the HTML document of a modal popup.

  • The context menu associated to the main control is opened by mouse click. Some controls may expect a right-click instead.

  • The code shown here assumes that the application can only display a single context menu, so it does not verify whether the item is associated with the main control.

Pattern for CRM Web Applications: SelectTransactionType

The SelectTransactionType pattern searches for and selects a transaction type in the popup window that appears when starting some CRM applications.

Some SAP CRM applications start by prompting the end user for a transaction type. This function performs this action by searching for the transaction type by its text, wherever it is in the list.

Note Note

This pattern only has the purpose to illustrate how to solve this problem and to explain to the Query API that CBTA can solve such issues. The equivalent component is CBTA_CRM_SelectTransactionType, which you can use without customizing the runtime library.

End of the note.

Example Example

The creation of a sales order is a typical example of business scenario that starts with the selection of the transaction type. The type is not always at the same position (depending on the number of transaction types in the database), so adapt the test script so that it does not search for the row number but for the transaction type using the text being displayed.

Note: By default, the line is selected by row number. This information is collected while recording the scenario, and is used in the generated test script.

The following graphic illustrates the automation of this step. The first column shows the transaction type, the second a short description. Both columns can identify the transaction type to be selected.

The bottom of the screen includes a “pager” control to navigate to the next pages if the transaction type is not on the current page.

End of the example.

Signature of SelectTransactionType Pattern

  • Input Parameters

    • TransactionType: text in the Transaction Type column

    • Description: (optional) text in the Description column

    • Operator: (optional) the operator to use when defining the filter (default is =)

      It compares the TransactionType and Description parameter values with the actual values of the respective columns. Supported operators are those documented in the Query API.

    • MaxPage: (optional) the number of pages to search for the transaction type

      Default is 10. The implementation navigates to the next page when the transaction type is not in the current one.

    • Options: several options influencing the behavior are available

      • /t = for trimming. Ignores leading and trailing spaces when comparing the TransactionType and Description parameter values with the actual values of the respective columns.

      • /u = upper-case. For a case-insensitive comparison.

  • Output Parameters

    • Output: report status, OK or FAILED.

SelectTransactionType has 5 parameters to comply with the default component CBTA_CRM_A_INVOKE_FUNCTION for calling custom functions.

Pattern for SAP GUI: ME21N_ExpandAllSections

Restores the initial state of the transaction ME21N/ME51N main screen.

The screen consists of collapsible panels. Each panel can be expanded or collapsed, depending on how the transaction ended during the previous session.

Like most of the patterns, the implementation consists of two functions. The first one is a façade to the implementation, which includes statements for handling execution errors. The second method performs the job.

Pattern for SAP GUI: WaitForCondition

Checks for a condition, and thus stops the execution flow temporarily.

Some SAP GUI applications start a background job to compute business data. The test script may need to pause and wait for the background job to complete, before continuing.

The PATTERN_NAME fragment is automatically replaced by the final custom function name when using the Code Assistant feature of the runtime library manager:

Syntax Syntax

  1. Function PATTERN_NAME ( TransactionType, Description, Operator, MaxPage, Options )
  2.   On Error Resume Next ' Important - Exception Handling - Do not change it!
  3.   EventComponentBegin()
  4.   If ConditionsManager().CheckConditions() Then
  5.     PATTERN_NAME = PATTERN_NAME_Impl ( TransactionType, Description, Operator, MaxPage, Options)
  6.   End If
  7.   EventComponentEnd()
  8. End Function
  9. Function PATTERN_NAME_Impl ( TransactionType, Description, Operator, MaxPage, Options ) 'internal
  10.   ImportLibrary "CRM_WebController.vbs"
  11.   ImportLibrary "CRM_WebControls.vbs"
  12.   PATTERN_NAME_Impl = "NOT DONE"
  13.   ...
  14. End Function
End of the code.

Initialization Phase

The first statements of the implementation initialize local variables and validate the input parameters:

Syntax Syntax

  1. Dim query, filter, subFilter, selectorInPopup, maxPageAsInt, i, uriNextPage, nextPageControl
  2. maxPageAsInt = ToInt(MaxPage)
  3. If IsNull(maxPageAsInt) Or maxPageAsInt = 0 Then
  4.   maxPageAsInt = 10
  5. End If
  6. If IsNull(Operator) Then
  7.   Operator = "="
  8. End If
  9. If IsNull(Options) Then
  10.   Options = ""
  11. End If
End of the code.

ReportDebugLog writes information to the traces for troubleshooting:

Syntax Syntax

  1. ReportDebugLog  "CUSTOM Function - PATTERN_NAME" & _
  2.                 " - Parameters: TransactionType " & TransactionType & " - Description: " & Description
  3. ReportDebugLog  "CUSTOM Function - PATTERN_NAME" & _
  4.                 " - Operator: " & Operator & " - MaxPage: " & maxPageAsInt & " - Options: " & Options
End of the code.

Implementation

The implementation consists of a loop (using the FOR/NEXT statements) to search each page for the transaction type.

Within this loop, the Query API defines the row match criteria. The query object is created by the CRM controller. The Query API handles situations that are specific to the underlying UI technology. CRM applications are built on top of the WebCUIF framework. The query created in the example below leverages the meta-information that this framework inserts in the HTML content, so that the test engineer can handle common use cases like this one. For information, see Query API for Testing of Dynamic Scenarios.

Syntax Syntax

  1. For i=1 To maxPageAsInt
  2.   '  Preparation of the CRM Query - Identifying the parent Table container (in the Popup)
  3.   Set query = CrmController().CreateQuery()
  4.   query.ParentControlUri = "popupId=1; crm.id=A_btfollowup:V_ProcType:T_cellerator:C_proctype:I_"
  5.   ' Specifying the element type to search for - ROW_SELECTOR
  6.   Set filter = query.SetFilter()
  7.   filter.AddCondition "crm.type", "=", "ROW_SELECTOR"
  8.   filter.AddCondition "crm.context", "=", "proctype"
  9.   If Not IsNull(TransactionType) Then
  10.     ' filtering on the Transaction Type
  11.     filter.AddCondition "crm.column:proctype.process_type", Operator, TransactionType, Options
  12.   End If
  13.   If Not IsNull(Description) Then
  14.     ' filtering on the Transaction Type Description
  15.     filter.AddCondition "crm.column:proctype.proc_type_descr_20", Operator, Description, Options
  16.   End If
  17.   ...
  18. Next
End of the code.

The ParentControlUri property restricts the scope of the query. In this example, the URI of the table (shown in the popup window) is specified.

A filter is defined to specify what to search for: The first condition checks the crm.type attributes. It guarantees that only ROW_SELECTOR matches the criteria. The second condition checks for the context C_ fragmentof the ID that the WebCUIF framework generates.

Two additional conditions are defined, depending on the input parameters: When the TransactionType parameter is set, an additional condition is created to check for the content of the column with the technical name proctype.process_type. When the Description parameter is set, another condition is created to check the content of the column with the technical name proctype.proc_type_descr_20.

Note Note

The query is created within the loop because the query object has a restricted life, which is bound to the HTML document being displayed. When navigating to the next page, the current HTML document is discarded and a new one is displayed, so a new query is necessary.

End of the note.

Query Resolution

Once defined, the query can be resolved to get the controls that match the criteria. In this use case, we only expect a single control (a single row), so we use the SelectSingle method here. The selectorInPopup variable receives the query result:

Syntax Syntax

  1. ' Selecting the first element matching the criteria
  2. ReportDebugLog " CUSTOM Function - PATTERN_NAME - now resolving query - Current Page: #" & i
  3. Set selectorInPopup = query.SelectSingle()
End of the code.

If the transaction type is found, this variable is not NULL, and we check it to determine whether to navigate to the next page.

Syntax Syntax

  1. If selectorInPopup Is Nothing Then
  2.  uriNextPage = "label=Navigation to Page #" & (i+1) & "; " & _
  3.                 "popupId=1; tag=SPAN; crm.tag=TD; " & _
  4.                 "crm.id=A_btfollowup:V_ProcType:T_PAGER:C_proctype:I_:K_pag_pg-" & (i+1)
  5.   Set nextPageControl =  CrmController().GetCrmControlByUri(uriNextPage)
  6.   If nextPageControl Is Nothing Then
  7.     ReportLog "FAILED", "PATTERN_NAME", "Operation Failed - Last page has been reached"
  8.     Exit For
  9.   Else
  10.     ' Control not found - Let's navigate to the next page (if any)
  11.     CRM_WebControl_Click uriNextPage
  12.     If ReportStatus <>"OK" Then
  13.       Exit For
  14.     End If
  15.   End If
  16. Else
  17.  ...
  18. End If
End of the code.

This code builds the URI of the next page and simulates a mouse click to navigate to it.

When the last page is reached, the loop is interrupted and the test script can fail because no transaction type was selected.

Row Selection

When the row selector UI element is found, the selectorInPopup variable is set. The implementation uses the GetControlUri method to determine the URI of the row selector and calls the CRM_Table_SelectRow function to perform the selection.

Syntax Syntax

  1. ' Control found - let's click on the ROW_SELECTOR
  2. CRM_Table_SelectRow selectorInPopup.GetControlUri()
  3. If ReportStatus = "FAILED" Then
  4.   ReportDebugLog " CUSTOM Function - PATTERN_NAME - Operation Failed"
  5. Else
  6.   ReportDebugLog " CUSTOM Function - PATTERN_NAME - Operation Succeeded"
  7. End If
  8. PATTERN_NAME_Impl = ReportStatus
  9. Exit For
End of the code.

The PATTERN_NAME_Impl variable provides feedback about the status of the operation. It is the value received by the output parameter of the CBTA_CRM_A_INVOKE_FUNCTION component. Result: The transaction type is selected. The Exit For statement interrupts the loop to avoid searching the next pages.

Pattern for SAP GUI: ME21N_ExpandAllSections

The ME21N_ExpandAllSections pattern checks for the state of the header sections and expands them automatically. It restores a recognized initial state if a transaction starts in a different state, depending, for example, on user preferences, to let the test script continue in the expected context.

Example Example

This problem typically occurs with transaction ME21N, where the main screen consists of several collapsible panels. The initial state of the panels is unknown at startup. Each panel can be expanded or collapsed, depending on how the transaction ended during the previous session. The test script needs to expand this panel before it continues. The following graphics shows the Overview panel, once in collapsed and once in expanded state.

End of the example.

The custom code of this pattern verifies the state of each panel and expands it, if necessary.

Note Note

This situation can normally be resolved using default components such as CBTA_A_SETCONDITION, but not with transaction ME21N, which has a very specific handling of its panels. It uses several subscreens to display the content of each panel, so a custom function is necessary.

End of the note.

Signature of SelectTransactionType Pattern

  • Input Parameters: none

  • Output Parameters: none

We assume that the custom function has been created previously, using the Code Assistant feature of the runtime library manager.

Test script definition: This custom function has no input parameters, so it can be called by the CBTA_GUI_A_EXECUTESTATEMENT default component:

Input parameters: The component for calling the custom function expects at least the Library parameter (name of the VB script file) and the Statement parameter (statement to execute). If the custom function does not expect input parameters, the statement is simple.

Execution report: The actions performed by the custom function are displayed in the execution report.

The implementation consists of sub-procedures. The first one is a façade of the implementation. The second method performs the job.

The PATTERN_NAME fragment is automatically replaced by the final custom code name when using the Code Assistant feature of the runtime library manager.

Syntax Syntax

  1.  Sub PATTERN_NAME ()
  2.   On Error Resume Next ' Important - Exception Handling for SAPGUI - Do not change it!
  3.   EventComponentBegin()
  4.   If ConditionsManager().CheckConditions() Then
  5.     If ConditionsManager().CheckConditions() Then
  6.   End If
  7.   EventComponentEnd()
  8. End Sub
  9. Sub PATTERN_NAME_Impl () 'internal
  10.   ReportDebugLog "CUSTOM Function - PATTERN_NAME"
  11.   ...
  12. End Sub
End of the code.

The subprocedure calls the Expand_Impl function for each collapsible section in the ME21N transaction.

Syntax Syntax

  1. Uri = "label=Expand Header; type=GuiButton;
  2.   id=wnd[0]/usr/subSUB0:SAPLMEGUI:0016/subSUB1:SAPLMEVIEWS:1100/
  3.  subSUB1:SAPLMEVIEWS:4000/btnDYN_4000-BUTTON"
  4. Expand_Impl Uri
  5. Uri = "label=Expand Item Overview; type=GuiButton;
  6.   id=wnd[0]/usr/subSUB0:SAPLMEGUI:0016/subSUB2:SAPLMEVIEWS:1100/
  7.   subSUB1:SAPLMEVIEWS:4001/btnDYN_4000-BUTTON"
  8. Expand_Impl Uri
  9. Uri = "label=Expand Item Detail; type=GuiButton;
  10.   id=wnd[0]/usr/subSUB0:SAPLMEGUI:0016/subSUB3:SAPLMEVIEWS:1100/
  11.   subSUB1:SAPLMEVIEWS:4002/btnDYN_4000-  BUTTON"
  12. Expand_Impl Uri
End of the code.

The Expand_Impl procedure is also delivered with the pattern code. It searches for the collapsible button by URI, calling the FindGuiControlByUri method. This call returns a reference to a GuiScripting object (a GuiButton in this case). The code then determines whether the panel is expanded or collapsed, using the IconName property.

Note Note

The logic is specific to the ME21N transaction. Checking the IconName is not the regular way of determining the collapsible state, but it is the only information available in the ME21N transaction.

End of the note.

Syntax Syntax

  1. Sub Expand_Impl ( Uri ) 'internal
  2.   Set GS_guiControl = Nothing
  3.   On Error Resume Next                  ' Switching ON a local error handling
  4.   Set GS_guiControl = GuiScripting().FindGuiControlByUri(Uri)
  5.   On Error Goto 0                       ' Switching OFF the local error handling
  6.   If GS_guiControl Is Nothing Then      ' Control not found
  7.     ReportLog "INFO", "Expand", "Operation skipped - the button does not exists"
  8.   Else
  9.     If GS_guiControl.IconName = "DAARSO" Then
  10.       ReportLog "INFO", "Expand", "Operation skipped - the section is already expanded"
  11.     Else
  12.       GS_guiControl.Press           ' Control has been found - let's click on it
  13.       ReportLog "INFO", "Expand", "Operation has been performed" _
  14.                  & vbCrlf & "Target: " & GetMeaningfulName(GS_guiControl)
  15.     End If
  16.   End If
  17. End Sub
End of the code.
Pattern for SAP GUI: ME51N_ExpandAllSections

ME51N_ExpandAllSections is analog to ME21N_ExpandAllSections. The only difference is that it expands ME51N collapsible panels. For more information, see the previous section, Pattern for SAP GUI: ME21N_ExpandAllSections.

Pattern for SAP GUI: WaitForCondition

The WaitForCondition pattern makes a test script wait for the background process to complete before continuing. With SAP GUI, some transactions can start asynchronous background processes on the server, so the UI cannot display the operation result automatically. The end user must perform actions (like pressing ENTER) to update the UI with the server status.

The pattern performs an action several times until a text is displayed in the SAP GUI UI.

Signature of WaitForCondition Pattern

  • Input Parameters:

    • Uri: URI identifying the SAP GUI control displaying the operation result

      It displays the text for which the wait condition checks. If empty, the URI of the status bar is used by default. Default value: label=Main Window; type=GuiMainWindow; id=/app/con[0]/ses[0]/wnd[0]

    • TextToCheck: text or part of the text that the control displays when the background process is still running

      Default value: Scheduled

    • WaitTime: time in milliseconds to wait between attempts

      Default: 1000 (one second)

    • MaxAttempts: maximum number of attempts

      When the maximum numbe is reached, the implementation stops checking and exits with NOT_DONE as output parameter. Default : 30.

    • Options: not used

  • Output Parameters:

    • Output: status, NOT_DONE or DONE

The pattern has 5 parameters, so it can be called by the CBTA_GUI_A_INVOKE_FUNCTION default component.

Like most of the patterns, the implementation consists of two functions. The first one is a façade of the implementation, which includes execution error handling statements. The second method performs the job.

Initialization Phase

The first statements validate the input parameters and set their default values, if necessary.

Syntax Syntax

  1. If IsNull(Uri) Then
  2.   Uri = "label=Status Bar; type=GuiStatusbar; id=/app/con[0]/ses[0]/wnd[0]/sbar"
  3. End If
  4. If IsNull(TextToCheck) Then
  5.   TextToCheck = "Scheduled"
  6. End If
  7. If IsNull(WaitTime) Then
  8.   WaitTime = "1000" '1 second
  9. End If
  10. If IsNull(MaxAttempts) Then
  11.   MaxAttempts = "30" '30 * 1000 ==> 30 seconds max!
  12. End If
End of the code.

he code writes information to the traces, for troubleshooting, and initializes the result to NOT DONE.

Syntax Syntax

  1. ReportDebugLog  "CUSTOM Function - PATTERN_NAME" & _
  2.                 vbCrLf & " - Uri: " & Uri & _
  3.                 vbCrLf & " - TextToCheck: " & TextToCheck & _
  4.                 vbCrLf & " - WaitTime " & WaitTime & _
  5.                 vbCrLf & " - MaxAttempts: " & MaxAttempts
  6. PATTERN_NAME_Impl = "NOT DONE"
End of the code.

Implementation

A loop, using the For/Next keywords, checks several times for the text being displayed, until the limit is reached, which is defined by the maxAttempts input parameter.

The GetPropertyValue method retrieves the text that is displayed by the control to which the URI refers. It then checks if this text contains the value in the TextToCheck input parameter: If so, it waits for the defined time and executes ENTER to refresh the screen. If not, it assumes the background process is over and breaks the iteration.

Syntax Syntax

  1. Dim i, statusBarUri, mainWindowUri, statusBarText, max
  2. mainWindowUri = "label=Main Window; type=GuiMainWindow; id=/app/con[0]/ses[0]/wnd[0]"
  3. max = ToInt(MaxAttempts)
  4. For i=1 To max
  5.   ReportDebugLog "PATTERN_NAME - Now getting the text of the Control"
  6.   statusBarText = GetPropertyValue ( Uri, "Text", Null )
  7.   ReportDebugLog "PATTERN_NAME - Control Text: " & statusBarText
  8.   If InStr(statusBarText, TextToCheck) Then
  9.       ' Let's wait
  10.       ReportLog "INFO", "PATTERN_NAME", "Waiting for background job to complete - attempt #" & i
  11.       GS_Wait WaitTime, Null
  12.       'Let's Press Enter to refresh the UI
  13.       GS_PressKey mainWindowUri, "Enter", Null
  14.   Else
  15.       ' Text not visible anymore
  16.       ReportLog "DONE", "PATTERN_NAME", "Background job has completed"
  17.       PATTERN_NAME_Impl = "DONE"
  18.       'Let's stop the loop
  19.       Exit For
  20.       End If
  21. Next
End of the code.
Patterns Location

The patterns that are predefined by SAP are stored under MIME Repository (SE80) of the SAP Solution Manager system, under Start of the navigation path SAP Next navigation step PUBLIC Next navigation step CBTA Next navigation step PATTERNS End of the navigation path. Patterns are stored in sub-folders, depending on their nature.

Runtime Library Manager

The runtime library manager customizes the runtime library. It has the following capabilities:

  • Opening the runtime library for editing

  • Writing custom code manually

  • Writing custom code by using the patterns with the code assistant

  • Testing the custom code before submitting it

  • Submitting changes to make them available to all testers

Code Assistant

When you use the code assistant, a guided procedure helps you to select a pattern and generate the custom code.

Selecting a Pattern

Select a pattern before you create a custom function. If you use the assistant instead of doing it manually, the generated code will be ready for use. Select a pattern according to your needs or the problem that you are facing. The UI technology of the application that is tested is the main criterion for the pattern selection.

Generating a Custom Function

The code assistant finishes with the generation of the custom code, using the function name that the test engineer specified.

The VB script containing the custom code is stored locally on the file system, at the location specified by the test engineer. Adapt the VB script to your needs, and test it, before submitting the changes.

For more information, see Enhancing CBTA With Custom Code.

More Information

...