Show TOC

Example documentationExamples for Using the Query API

 

Example: Contact Creation

Three views are used to enter the contact information:

  • bp_cont/ContactDetails

  • bp_cont/SalesEmployee

  • bp_addr/StandardAddress

The query API can retrieve all the input fields in the SalesEmployee view.

Searching for Web Controls

The following script shows how to create and execute a query:

The VB Script accesses the HTML document by calling the CrmController method, and creates a query using theCreateQuery method. The query is empty. Specify the criteria to identify the controls we are looking for, using filters and conditions. In our example, a single filter with two conditions is specified. The filter is created using the SetFilter method, and the two conditions are added using the AddCondition method.

Once the criteria are set, the query can be executed with the following methods:

  • Select: returns a collection of CRM Web controls which match the criteria.

  • SelectSingle: returns the first CRM Web control which matches the criteria, not a collection

The next exemplary sections describe how to use the results of the Select and SelectSingle methods.

Setting the Input Field Value

Our first example explains how to create and execute a query. Our second example will show how to use the result, and manipulate the retrieved CRM Web control object.

Syntax Syntax

  1. Dim controller, query, filter, crmControl, controlUri
  2. Set controller = CrmController()
  3. Set query = controller.CreateQuery()
  4. Set filter = query.SetFilter()
  5. filter.AddCondition "crm.view", "=", "SalesEmployee"
  6. filter.AddCondition "crm.type", "=", "inputField"
  7. Set crmControl = query.SelectSingle()
  8. If Not crmControl Is Nothing Then
  9.   controlUri = crmControl.GetControlUri()
  10.   controller.SetElementValue controlUri, "1234"
  11. End If
End of the code.

This script invokes the SelectSingle method to retrieve a single CRM Web control (so there is no need to iterate through a collection). It checks whether the crmControl variable is set, and asks for the URI identifying the CRM Web control, by calling the GetControlUri method. This call returns a URI which complies with the ones that the runtime library expects when you use default components.

In this example, this is the URI that identifies the CRM Web control:

crm.area=WorkArea; tag=INPUT;

crm.id=A_bp_cont:V_SalesEmployee:T_inputField:C_salesemployee:I_struct.salesemployee

With this URI, the script can invoke one of the methods exposed by the CRM Web controller API to perform actions that are normally performed with default components. In our example, the script sets the value of the input field to 1234, by calling the SetElementValue method.

Example: Appointment Creation

The scenarios that we have seen so far are not dynamic, so the query API is not necessary, because the default components are normally sufficient to automate them. The next example explains how to select CRM Web controls by filtering on the values of the INPUT HTML element that the browser displays.

Searching for Web Controls in a Table

We must automate a dynamic scenario in which the script selects the first row in which the partner function is Sales employee and Partner ID is 244.

The difficulty is that the conditions are to be checked against the CELL contents in the same row but a different column, not against the CRM Web control that is being searched. This kind of query can be very complex when it searches the internal hierarchy of HTML elements. To make it simple, the filters and the conditions have been specified to hide the complexity and handle common use cases like this one.

This is what the VB Script coding for row selection looks like:

Syntax Syntax

  1. Dim controller, query, filter, selector, controlUri
  2. Set controller = CrmController()
  3. Set query = controller.CreateQuery()
  4. Set filter = query.SetFilter()
  5. filter.AddCondition "crm.application", "=", "btpartner"
  6. filter.AddCondition "crm.view", "=", "Partner"
  7. filter.AddCondition "crm.context", "=", "btpartner"
  8. filter.AddCondition "crm.type", "=", "ROW_SELECTOR"
  9. filter.AddCondition "crm.column:btpartner.partner_no", "=", "244"
  10. filter.AddCondition "crm.column~Partner Function", "=", "Sales employee"
  11. Set selector = query.SelectSingle()
  12. If Not selector Is Nothing Then
  13.   If Not selector Is Nothing Then
  14.   If Not selector Is Nothing Then
  15. End If
End of the code.

This script shows the types of conditions that the query supports. The conditions here check the attributes of the CRM Web controls. The API lets you check the regular HTML attributes and properties, and some CRM-specific attributes to check the fragments of the CRM IDs.

The object spy (or the developer tool from MS Internet Explorer) shows the CRM ID of the first row selector:

A_btpartner:V_Partner:T_ROW_SELECTOR:C_btpartner:I_:R_1

The fragments provide meta-information about the CRM Web control:

  • A_: application

  • V_: view name

  • T_: type

  • C_: context node

  • I_: interface; for input fields, the technical name

  • R_: row number

The condition can check the value of these fragments using CRM attributes like the following:

  • crm.application: checks the application

  • crm.application: checks the view name

  • crm.application: checks for the UI element type

  • ...

The following filtering guarantees that the query will only return the row selectors:

Syntax Syntax

  1. filter.AddCondition "crm.application", "=", "btpartner"
  2. filter.AddCondition "crm.view", "=", "Partner"
  3. filter.AddCondition "crm.context", "=", "btpartner"
  4. filter.AddCondition "crm.context", "=", "btpartner"
End of the code.

We now need to select the second one only (the second visible line). If our scenario was not dynamic, we could select the second row directly, using a default component (for example SelectRow) and specifying the URI:

A_btpartner:V_Partner:T_ROW_SELECTOR:C_btpartner:I_:R_2

Because our scenario is dynamic, the row we want to select may not always be in the second position. So we need to search for it by checking the value of the other columns. Two syntaxes are possible when you filter for column values, depending on whether you pass the column title or the column technical name.

The syntax can be crm.colum:<context>.<interface> or crm.colum~<Column Title>, so the following two ways of filtering are equivalent:

Syntax Syntax

  1. filter.AddCondition "crm.column:btpartner.partner_no", "=", "244"
  2. filter.AddCondition "crm.column:btpartner.partner_fct ", "=", "Sales employee"
End of the code.

...

Syntax Syntax

  1. filter.AddCondition "crm.column~Partner ID", "=", "244"
  2. filter.AddCondition "crm.column~Partner Function", "=", "Sales employee"
End of the code.

In our example, both syntaxes are used:

Syntax Syntax

  1. filter.AddCondition "crm.column:btpartner.partner_no", "=", "244"
  2. filter.AddCondition "crm.column~Partner Function", "=", "Sales employee"
End of the code.
Tips and Tricks

Iterating Through a Set of Web Controls

The following code shows how to iterate though the set of CRM Web controls that are retrieved by the query. The collection implements the Web Control Collection Interface described in Technical Information for the Query API.

Syntax Syntax

  1. Dim collection
  2. Set collection = query.Select()
  3. If collection Is Nothing Then
  4.   MsgBox "Nothing has been found"
  5. Else
  6.   MsgBox "Element Found: " & collection.Count
  7.   Dim childControl
  8.   for i=0 To collection.Count-1
  9.     Set childControl = collection.ControlAt(i)
  10.     MsgBox "Uri: " & childControl.GetControlUri()
  11.   Next
  12. End If
End of the code.

Note Note

The VB Script For Each statement is not supported.

End of the note.

Making Information Available to Subsequent Components

Usually, only a part of the tested scenario is dynamic and requires custom coding and queries. Then it can be useful to make the URI of the retrieved CRM Web controls available to subsequent components, and continue the scenario using default components. This is typically done with the SetToken method, as shown in the following example:

Syntax Syntax

  1. Dim crmControl, crmControlUri
  2. Set crmControl = query.SelectSingle()
  3. If crmControl Is Nothing Then
  4.   CBTA.Log "Unexpected Situation - Control not found"
  5. Else
  6.   crmControlUri = crmControl.GetControlUri()
  7.   CBTA.Log "Uri: " & crmControlUri
  8.   ExecutionContext.SetToken "rowSelector", crmControlUri
  9. End If
End of the code.

Subsequent components can reuse the value that is stored in the execution context, using the %token% syntax. In this example, the subsequent components can use %rowSelector% to perform operations on the ROW_SELECTORthat was selected by the query.

Writing Information to the Execution Report

The CBTA object provides the following methods:

  • CBTA.Log: troubleshoots complex scenarios

    Public Sub Log(message)

  • CBTA.Report: provides feedback to the tester by the Execution Report

    Public Sub Report(Severity, Topic, Message, Options)

Reducing the Scope of a Query

By default, the CRM queries automatically search for CRM Web controls in the FRAME work area of the main browser window. The query analyzes the content of the body of the HTML document, and checks the filters and conditions for all CRM Web controls that were found.

For performance reasons, you can reduce the scope of the query and specify where to start searching. For instance, when searching for CRM Web controls of type ROW_SELECTOR, first specify the parent container HTML table element, using the ParentControlUri property of the query. For example:

Syntax Syntax

  1. '--------------------------------------------
  2. ' Query Example with Restricted Scope
  3. '--------------------------------------------
  4. Dim query, filter, subFilter
  5. Set query = CrmController().CreateQuery()
  6. query.ParentControlUri = "tag=DIV; crm.id=A_btpartner:V_Partner:T_cellerator:C_btpartner:I_"
End of the code.

Note Note

The URI should be determined by the object spy, but the HTML element table cannot always be selected, depending on the style.

The alternative to the object spy is to search for the CRM ID of the cellerator UI element with the developer tool in MS Internet Explorer.

End of the note.

Searching for Web Controls in a Popup Window

The queries search for CRM Web controls in the FRAME work area of the main browser window, by default. You can change this default behavior with the ParentControlUri property.

Example VB Script to search for a control in a modal popup window:

Syntax Syntax

  1. Dim controller, query, filter
  2. Set controller = CrmController()
  3. Set query = controller.CreateQuery()
  4. query.ParentControlUri = "popupId=1; crm.area=WorkArea; tag=body"
  5. Set filter = query.SetFilter()
  6. filter.AddCondition "crm.type", "=", "ROW_SELECTOR"
  7. filter.AddCondition "crm.context", "=", "proctype"
  8. filter.AddCondition "crm.context", "=", "proctype"
  9. filter.AddCondition "crm.column:proctype.proc_type_descr_20", "=", "Meeting"
  10. Dim selectorInPopup, selectorUri
  11. Set selectorInPopup = query.SelectSingle()
  12. selectorInPopup.HighLight "red"
  13. selectorUri = selectorInPopup.GetControlUri()
  14. controller.SearchResult_SelectRow selectorUri
End of the code.

This example contains nothing new regarding the selection of the ROW_SELECTOR. The script uses some conditions to select the transaction with type 1001 and type description Meeting. The difference is that it now specifies searching in the FRAME work area of the popup by setting the ParentControlUri property:

query.ParentControlUri = "popupId=1; crm.area=WorkArea; tag=body"

In this example, it would have been possible to restrict the scope of the query even more, by specifying the URI of the TABLE HTML element like this:

query.ParentControlUri = "popupId=1; crm.id=A_btfollowup:V_ProcType:T_cellerator:C_proctype:I_"

Combining Filters for Complex Queries

All examples so far use only one filter with several conditions. Conditions are evaluated one by one, and the CRM Web UI elements are excluded as soon as a condition is not met. The conditions are connected by a logical ANDoperator.

Our previous example selected the first row with the following conditions: Partner Function equals "Sales employee" AND Partner ID equals "244".

Instead of searching for the ROW_SELECTOR, we could retrieve controls that are either checkboxes or input fields that are associated with an F4 help, by combining several filters, as in the following example:

Syntax Syntax

  1. Dim query, filter, subFilter, collection, childControl
  2. Set query = CrmController().CreateQuery()
  3. query.ParentControlUri = "tag=DIV; crm.id=A_btpartner:V_Partner:T_cellerator:C_btpartner:I_"
  4. Set filter = query.SetFilter()
  5. filter.AddCondition "crm.application", "=", "btpartner"
  6. filter.AddCondition "crm.view", "=", "Partner"
  7. filter.AddCondition "crm.context", "=", "btpartner"
  8. filter.AddCondition "crm.column:btpartner.partner_no", "=", "244"
  9. filter.AddCondition "crm.column~Partner Function", "=", "Sales employee"
  10. Set subFilter = filter.SetFilter()
  11. subfilter.AddCondition "crm.tagType", "=", "valueHelp"
  12. Set subFilter = filter.AddFilter()
  13. subfilter.AddCondition "crm.tagType", "=", "checkbox"
  14. Set collection = query.Select()
  15. If collection Is Nothing Then
  16.   CBTA.Report CBTA.FAILED, "Demo Query", "No controls have been found", ""
  17. Else
  18.   CBTA.Report CBTA.INFO, "Demo Query", "Nb. Controls: " & collection.Count, ""
  19.   for i=0 To collection.Count-1
  20.     Set childControl = collection.ControlAt(i)
  21.     CBTA.Report CBTA.INFO, "Demo Query", "Uri: " & childControl.GetControlUri(), ""
  22.   Next
  23. End If
End of the code.

In this example, the main filter no longer checks for the ROW_SELECTOR type, so all cells in the row match its criteria. The difference is that we have now defined two sub-filters that specify the type of the UI elements for which we are looking.

The first sub-filter checks for elements that are associated with an F4 help, which use the valueHelp tagType.

Syntax Syntax

  1. Set subFilter = filter.SetFilter()
  2. subfilter.AddCondition "crm.tagType", "=", "valueHelp"
End of the code.

The second sub-filter checks for checkbox UI elements:

Syntax Syntax

  1. Set subFilter = filter.AddFilter()
  2. subfilter.AddCondition "crm.tagType", "=", "checkbox"
End of the code.

There are two sub-filters here. Both have a single condition which checks for the crm.tagType attribute.

  • The first sub-filter is created by calling the SetFilter method on the main filter object.

  • The second sub-filter is added by the AddFilter method-

By defining several filters we specify that we are looking for cells which match both CRM tag types. This is possible because, unlike conditions, the filters are connected by the logical OR operator.

Reusing Default Component Implementations

The controller interfaces also expose methods to interact with the application UI. There is at least one method per default component that CBTA delivers.

The two examples below are equivalent:

Syntax Syntax

  1. CRM_Table_SelectRow crmControl.GetControlUri()
  2. If ReportStatus = "FAILED" The
  3.   ' Nothing to do
  4. End If
End of the code.

...

Syntax Syntax

  1. Set operationResult = CrmController().Table_SelectRow crmControl.GetControlUri()
  2. If operationResult.Status = "FAILED" Then
  3.   CBTA.Report CBTA.FAILED, "Demo Query", "Row selection failed", ""
  4. Else
  5.   CBTA.Report CBTA.INFO, "Demo Query", "Row has been selected", ""
  6. End If
End of the code.

The first example invokes the component implementation, while the second one invokes the corresponding method by the controller interface. The advantage of the first approach is that it benefits from default exception handling (writing information in the execution report when an error occurs). In the second example, the script is responsible for checking whether the operation succeeds.

Note Note

In general, the public methods of the controller interfaces return an Operation Result Object that implement the Operation Result Interface (see Technical Information for the Query API). The information that is available there can provide human-readable feedback in the execution report.

See Writing Information to the Execution Report, earlier in this document.

End of the note.

Mapping Between Public Methods and Component Implementations

The following list shows examples of methods, which are exposed by the controller interfaces, and their component implementations:

Controller

Method Name

Component Implementation (VB Script Function)

CrmController()

CaptureScreen

CRM_CaptureScreen

WebControl_Click

CRM_WebControl_Click

SetElementValue

N/A

Table_SelectRow

CRM_Table_SelectRow

SearchResult_SelectRow

CRM_SearchResult_SelectRow

WebController()

CaptureScreen

WEB_CaptureScreen

WebControl_SetValue

WEB_WebControl_SetValue

WebControl_CheckProperty

WEB_WebControl_CheckPropert

Example: Finding a Row by Content

CBTA contains default components that search tables for a row, by the content of one of the cells. As of CBTA 3.0 SP02, the following components are available:

  • CBTA_LS_T_FindRow: searches a Light Speed table for a row, by checking the value of a single cell.

    Input parameters:

    • URI: specifies the URI of the table container

    • ColumnTitle: title of the column (the visible text)

    • Operator: boolean operator used to compare the actual value with the expected one

    • Content: expected value of the cell

    • Options: Some options can be used to convert the values before comparing them.

    Output parameters: The number of the row matching the criteria.

  • CBTA_CRM_T_FindRow: similar to CBTA_LS_T_FindRow but for SAP CRM Web applications

Both components were implemented using the query API, so a test engineer can copy and paste the source code of the component implementation, and adapt it to his needs.

Note Note

The code of the CBTA_LS_T_FindRow is in the runtime library, it is visible in theLS_Functions.vbs file.

Use the runtime library manager to customize the runtime library and write custom functions. When you open the runtime library for editing, the LS_Functions.vbs file is made available, locally in the file system, at the location that has been specified by the test engineer.

End of the note.

VB Script Function – LsTable_FindRowByContent

Syntax Syntax

  1. Public Function LsTable_FindRowByContent ( Uri, ColumnTitle, Operator, Content, Options )
  2.   On Error Resume Next
  3.   EventWebComponentBegin()
  4.   LsTable_FindRowByContent = LsTable_FindRowByContent_Impl( Uri, ColumnTitle, Operator, Content, Options )
  5.   EventWebComponentEnd()
  6. End Function
  7. Public Function LsTable_FindRowByContent_Impl ( Uri, ColumnTitle, Operator, Content, Options )
  8.   LsTable_FindRowByContent_Impl = ""
  9.   If IsNull(Uri) Or IsNull(ColumnTitle) Or IsNull(Content) Then
  10.     Exit Function
  11.   End If
  12.   If IsNull(Operator) Then
  13.     Operator = "="
  14.   End If
  15. If IsNull(Options) Then
  16.     Options = ""
  17.   End I
  18.   ReportDebugLog "LsTable_FindRowByContent" & _
  19.                     vbCrLf & "Uri: " & Uri & _
  20.                     vbCrLf & "ColumnTitle: " & ColumnTitle & _
  21.                     vbCrLf & "Operator: " & Operator & _
  22.                     vbCrLf & "Content: " & Content & _
  23.                     vbCrLf & "Options: " & Option
  24.   Dim controller, query, filter
  25.   Set controller = LsController()
  26.   Set query = controller.CreateLsQuery()
  27.   query.ParentControlUri = uri
  28.   Set filter = query.SetFilter()
  29.   filter.AddCondition "tag", "=", "TD"
  30.   filter.AddCondition "ls.subtype", "=", "SC"
  31.   filter.AddCondition "ls.column~" & ColumnTitle, Operator, Content, Options
  32.   Set control = query.SelectSingle()
  33.   If control Is Nothing Then
  34.     ReportLog "FAILED", "LsTable_FindRowByContent", "Operation Failed - Row could not be found"
  35.   Else
  36.     LsTable_FindRowByContent_Impl = control.GetRelevantControl().GetLsRow()
  37.     If InStr(Options, "/Select" ) Then
  38.       ReportLog "INFO", "LsTable_FindRowByContent", _
  39.         "Operation succeeded - Row has been selected" & vbCRLf & _
  40.         "Row is: " & LsTable_FindRowByContent
  41.       ReportDebugLog "LsTable_FindRowByContent - Row Selector Uri: " & control.GetControlUri()
  42.       WEB_WebControl_Table_SelectRow control.GetControlUri()
  43.     Else
  44.       ReportLog "INFO", "LsTable_FindRowByContent", _
  45.                 "Operation succeeded - Row is: " & LsTable_FindRowByContent
  46.     End If
  47.   End If
  48. End Function
End of the code.
Component LsTable_FindRowByContent

The following sections explain in detail how this component has been implemented.

Exception handling: The implementation consists of two functions. The first function is required only because the VB Script syntax is not good for exception handling and the On Error Resume Next keyword used here is the only available option.

All default components are built according to the same concept; the first surrounds the invocation of the actual implementation to intercept any errors.

Syntax Syntax

  1. Public Function LsTable_FindRowByContent ( Uri, ColumnTitle, Operator, Content, Options )
  2.   On Error Resume Next
  3.   EventWebComponentBegin()
  4.   LsTable_FindRowByContent = LsTable_FindRowByContent_Impl( Uri, ColumnTitle, Operator, Content, Options )
  5.   EventWebComponentEnd()
  6. End Function
End of the code.

Validating input parameters: The first statements of the implementation validate the input parameters, to avoid common issues.

Syntax Syntax

  1. Public Function LsTable_FindRowByContent_Impl ( Uri, ColumnTitle, Operator, Content, Options )
  2.   LsTable_FindRowByContent_Impl = "
  3.   If IsNull(Uri) Or IsNull(ColumnTitle) Or IsNull(Content) Then
  4.     Exit Function
  5.   End If
  6.   If IsNull(Operator) Then
  7.     Operator = "="
  8.   End If
  9.   If IsNull(Options) Then
  10.     Options = ""
  11.   End If
  12. ...
  13. End If
End of the code.

In this example, the URI and some parameters are mandatory, some have a default value. The script checks them all and reacts accordingly.

Writing information to the execution report: The following code just provides feedback to the test engineer. The value of each input parameter is written to the execution report.

Syntax Syntax

  1. ReportDebugLog "LsTable_FindRowByContent" & _
  2.                     vbCrLf & "Uri: " & Uri & _
  3.                     vbCrLf & "ColumnTitle: " & ColumnTitle & _
  4.                     vbCrLf & "Operator: " & Operator & _
  5.                     vbCrLf & "Content: " & Content &
  6.                     vbCrLf & "Options: " & Option
End of the code.

Creation of the Query Restricted to a Table Container

If the input parameters are consistent, a query is created using the Light Speed Controller, and it’s scope is restricted to the table by setting the ParentControlUri property:

Syntax Syntax

  1. Dim controller, query, filter
  2. Set controller = LsController()
  3. Set query = controller.CreateLsQuery()
  4. query.ParentControlUri = uri
End of the code.

Definition of the Criteria

To find a row by checking the content of one of the cells, we use a single filter with 3 conditions:

Syntax Syntax

  1. Set filter = query.SetFilter()
  2. filter.AddCondition "tag", "=", "TD"
  3. filter.AddCondition "ls.subtype", "=", "SC"
  4. filter.AddCondition "ls.column~" & ColumnTitle, Operator, Content, Options
End of the code.

The first condition specifies the tag used by the Light Speed Framework to generate a cell. The regular <TD> HTML tag is used.

Note Note

This condition is not mandatory, but filtering out the other tags has a significant impact on performance, since the number of UI elements matching this condition might be small.

End of the note.

The second condition relies on Light Speed data to determine the sub-type of control. The Light Speed Framework marks all cells with the SC sub-type, regardless of the actual type (such as input field or checkbox). For more information on data specific to the Light Speed Framework, see Technical Information for the Query API.

The third condition is the most important one; it uses the ColumnTitle parameter specified to search for the cell displayed in the column we are interested in. This condition also uses the Operator, Content, and Options parameters to specify the value we expect in the cells. For more information on boolean operators and options for conditions, see Technical Information for the Query API.

Resolving the Query

The criteria have been defined; the query is now ready to be executed. The following code triggers the query resolution:

Syntax Syntax

  1. Set control = query.SelectSingle()
  2. If control Is Nothing Then
  3.   ReportLog "FAILED", "LsTable_FindRowByContent", "Operation Failed - Row could not be found"
  4. Else
  5.   LsTable_FindRowByContent_Impl = control.GetRelevantControl().GetLsRow()
  6.   ...
  7. End If
End of the code.

By calling the SelectSingle method, the CBTA_LS_T_FindRow component only searches for a single row, that is, the first row that matches the criteria. It is also possible to retrieve a set of cells that match the criteria, by calling the Select method instead.

Returning the Row Number

The following code gets the row number by using Light Speed Data that is made available by interfaces that are specific to the underlying UI technology.

For more details on Light Speed-relevant control interfaces, see Technical Information for the Query API.

Syntax Syntax

  1. LsTable_FindRowByContent_Impl = control.GetRelevantControl().GetLsRow()
  2. ...
End of the code.

Note Note

The CBTA_LS_T_FindRow component returns the row number in its output parameter. The internal method used to set the output parameter is not in scope of this document.

End of the note.

Selecting the Row

The CBTA_LS_T_FindRow component can select the row as well as search for it. The script has to ask for the URI of the cell that matches the criteria, and then trigger the row selection.

The URI is retrieved by calling the following GetControlUri method, and the selection is made by calling the WEB_WebControl_Table_SelectRow function, which corresponds to theCBTA_WEB_SelectRow default component. In the following example, the selection is only made when the Options parameter contains /Select:

Syntax Syntax

  1. If InStr(Options, "/Select" ) Then
  2.   ReportLog "INFO", "LsTable_FindRowByContent", _
  3.     "Operation succeeded - Row has been selected" & vbCRLf & _
  4.     "Row is: " & LsTable_FindRowByContent
  5.   ReportDebugLog "LsTable_FindRowByContent - Row Selector Uri: " & control.GetControlUri()
  6.   WEB_WebControl_Table_SelectRow control.GetControlUri()
  7. Else
  8.   ReportLog "INFO", "LsTable_FindRowByContent",
  9.             "Operation succeeded - Row is: " & LsTable_FindRowByContent
  10. End If
End of the code.