Implementing Recording Support

Applies to TestComplete 14.91, last modified on July 20, 2021

TestComplete includes a powerful recorder which allows testers record new tests instead of creating them from scratch. When creating a custom keyword test operation that wraps actions a tester can perform during test recording (such as a custom checkpoint), you may consider adding recording support for this operation. This way, you can enable TestComplete to record your custom operation instead of the corresponding standard operation(s).

This topic explains how to implement custom keyword test operations with recording support. The end of the topic contains the source code of a script extension that provides a sample operation that can be recorded.

About Keyword Recording Process

Before we go into detail on creating recordable operations, we would like to explain how keyword test recording takes place in TestComplete.

TestComplete records all tests, both scripts and keyword tests, in a script form. At that, keyword tests are generated based on the recorded script code by analyzing it and replacing individual statements by the corresponding keyword test operations. Script extensions can also be involved in analysis of the recorded code and thus can make TestComplete use custom operations where appropriate.

When analyzing the recorded script, TestComplete divides it into individual statements and searches for the keyword test operation(s) matching each of the statements. This search is performed as follows:

  1. TestComplete raises the IsSupported event on all keyword test operations and passes the script statement as a parameter.

  2. TestComplete checks the return value of event handlers to determine which operations correspond to the statement. (Appropriate operations return True in this case.)

    If there is only one appropriate, TestComplete adds it to the resulting keyword test. At that, it raises the OnGenerate event on the operation to initialize parameter and field values of the given operation instance.

    If several operations reported that they correspond to the specified code snippet, TestComplete opts for the operation that has higher priority. The order of priority is as follows:

    1. Standard operations of the Checkpoints category (highest priority).
    2. Custom operations created with script extensions (high priority).
    3. Other standard operations (normal priority).

    If candidate operations have the same priority, TestComplete decides between them at random. There is no way to determine or control this choice. This also means that TestComplete can choose different operations at different times.

  3. If the statement being analyzed contains nested statements (this applies to conditional, loop and other statements), TestComplete repeats steps 1-2 for each of them.

About Creating Keyword Test Operations that can be Recorded

As it is mentioned in the previous section, TestComplete raises the IsSupported and OnGenerate events on custom keyword test operations when constructing a keyword test based on the recorded data. So, to create a recordable operation, you need to subscribe to these events and handle them in the operation code.

The IsSupported event occurs when TestComplete is analyzing the recorded code and checks if a certain code snippet corresponds to your custom operation. The event has one parameter -- a string holding the script statement. This statement can be a method call, a property assignment, a conditional or any other statement supported by the scripting language of the user’s project. Note, that a statement can be multi-lined and include other statements (an example of such statement is if … then).

The event handler should parse the specified code and return True if it corresponds to the operation and False otherwise. If it returns True, the operation will be considered as a candidate for adding to the keyword test in place of that code.

The OnGenerate event occurs if the operation’s IsSupported event handler returned True. In this case, TestComplete creates a new instance of the operation and fires this event to initialize the operation parameters and fields according to the recorded code.

The event has three parameters - a string holding the script code and objects that provide access to the operation fields and parameters. (See the event description for details.)

The event handler should parse the code, retrieve values for the operation parameters and fields and initialize the latter with captured values.

Creating the IsSupported and OnGenerate event handlers is a nontrivial task, because it requires parsing the script code. TestComplete provides no built-in means for this purpose, so you need to analyze the code yourself. In most cases, you can do this using regular expressions. Note, however, that different scripting languages supported by TestComplete have different syntax, so you need to define code patterns for each of the supported languages. Also note that many object methods, whose calls can be present in the recorded script, use a variable number of parameters of variable parameter types, so it can be difficult to extract the parameter values from the script code.

Be careful when implementing the OnGenerate event handler: incorrectly returned positive results can break the recorded keyword test.

Example

This example contains the code of a sample script extension that provides the following items:

  • The Copy File keyword test operation, which is a wrapper over the aqFileSystem.CopyFile method. The operation has two parameters that specify the source and destination file names.

  • The Copy File record-time action. When selected during keyword test recording, it records the Copy File operation that copies the TestComplete help file to the Desktop. During script recording, the action records the corresponding aqFileSystem.CopyFile method call.

Below is the script code of the operation and the contents of the description.xml file:

description.xml

<?xml version="1.0" encoding="UTF-8"?>
<ScriptExtensionGroup>
    <Category Name="Keyword Test Operations">
        <ScriptExtension Name="Copy File Operation" Author="SmartBear Software" Version="1.0">
            <Script Name=""> <!- - Specify the script file name (script.vbs or script.js) in the Name attribute - ->

                <KDTOperation Name="Copy File">
                    <Parameters>
                        <Parameter Name="Source" DefaultValue=""/>
                        <Parameter Name="Destination" DefaultValue=""/>
                    </Parameters>
                    <Columns>
                        <Column Name="Item" Value="Copy File" />
                        <Column Name="Value" Editable="True" EditorType="Parameters" />
                    </Columns>
                    <Events>
                        <Event Name="OnExecute" Routine="CopyFile_OnExecute" />
                        <Event Name="IsSupported" Routine="CopyFile_IsSupported" />
                        <Event Name="OnGenerate" Routine="CopyFile_OnGenerate" />
                    </Events>
                </KDTOperation>

            </Script>
        </ScriptExtension>
    </Category>
</ScriptExtensionGroup>

JScript

// This routine is executed by the operation during the test run
function CopyFile_OnExecute (Data, Source, Destination)
{
  if (aqFileSystem.CopyFile(Source, Destination))
    Log.Message("The file \"" + Source + "\" has been copied successfully.")
  else
    Log.Error("Failed to copy the \"" + Source + "\" file.")
}

// Holds parsed script code
var match;

// This routine checks if the operation is equivalent to the specified code snippet
function CopyFile_IsSupported(Code)
{
  // Construct a regular expression that matches the aqFileSystem.CopyFile method call
  var re;
  switch (Syntax.CurrentLanguage)
  {
    case "JavaScript" : case "JScript" : case "Python":
      re = /aqFileSystem\.CopyFile\(\"(.*)\", \"(.*)\"\)/; break;
    case "VBScript" :
      re = /Call aqFileSystem\.CopyFile\(\"(.*)\", \"(.*)\"\)/; break;
    case "DelphiScript":
      re = /aqFileSystem\.CopyFile\('(.*)', '(.*)'\)/; break;
    case "C#Script" : case "C++Script":
      re = /aqFileSystem\[\"CopyFile\"\]\(\"(.*)\", \"(.*)\"\)/; break;
  }

  // Test the Code against the regular expression
  match = re.exec(Code);
  return (match != null);
}

// This routine initializes the operation instance corresponding to the specified code
function CopyFile_OnGenerate(Code, Data, Parameters)
{
  /*
    The Code has already been parsed in the IsSupported event handler.
    So, we only need to initialize the operation parameters with
    values retrieved from the Code.
  */

  // Replace double backslashes in file names with single ones
  Parameters.Source = aqString.Replace(match[1], "\\\\", "\\");
  Parameters.Destination = aqString.Replace(match[2], "\\\\", "\\");
}

VBScript

' This routine is executed by the operation during the test run
Sub CopyFile_OnExecute (Data, Source, Destination)
  If aqFileSystem.CopyFile(Source, Destination) Then
    Log.Message "The file """ & Source & """ has been copied successfully."
  Else
    Log.Error "Failed to copy the """ & Source & """ file."
  End If
End Sub

' Holds parsed script code
Dim Matches

' This routine checks if the operation is equivalent to the specified code snippet
Function CopyFile_IsSupported(Code)
  ' Construct a regular expression that matches the aqFileSystem.CopyFile method call
  Dim re
  Set re = New RegExp
  Select Case Syntax.CurrentLanguage
    Case "JavaScript", "JScript", "Python"
      re.Pattern = "aqFileSystem\.CopyFile\(""(.*)"", ""(.*)""\)"
    Case "VBScript"
      re.Pattern = "Call aqFileSystem\.CopyFile\(""(.*)"", ""(.*)""\)"
    Case "DelphiScript"
      re.Pattern = "aqFileSystem\.CopyFile\('(.*)', '(.*)'\)"
    Case "C#Script", "C++Script"
      re.Pattern = "aqFileSystem\[""CopyFile""\]\(""(.*)"", ""(.*)""\)"
  End Select

  ' Test the Code against the regular expression
  Set Matches = re.Execute(Code)
  CopyFile_IsSupported = (Matches.Count > 0)
End Function

' This routine initializes the operation instance corresponding to the specified code
Sub CopyFile_OnGenerate(Code, Data, Parameters)
  ' The Code has already been parsed in the IsSupported event handler.
  ' So, we only need to initialize the operation parameters with
  ' values retrieved from the Code.

  With Matches(0)
    ' Replace double backslashes in file names with single ones
    Parameters.Source = aqString.Replace(.SubMatches(0), "\\", "\")
    Parameters.Destination = aqString.Replace(.SubMatches(1), "\\", "\")
  End With
End Sub

You can test this example in the following way:

  1. Copy the folder containing the script file and the description.xml file to the <TestComplete>\Bin\Extensions\ScriptExtensions folder.

  2. Launch TestComplete and create a new project.

  3. Start recording a keyword test and specify the test name.

  4. In the list of custom actions on the Recording toolbar, select Copy File.

  5. Stop recording.

The recorded keyword test will contain the Copy File operation. The operation parameters will specify the <TestComplete>\Help\TestComplete14.chm file as a source and <Users>\<User_Name>\Desktop\TestComplete14.chm (on Windows Vista, Windows 7, Windows Server 2008 and later operating systems) or <Documents and Settings>\<User_Name>\Desktop\TestComplete14.chm (on other operating systems) as the destination file.

See Also

Creating Keyword Test Operations
Creating Keyword Test Operations - Basic Concepts

Highlight search results