Squish records tests using the scripting language that was specified for the test suite, rather than using a proprietary language. Once a test has been recorded we can run the test and Squish will faithfully repeat all the actions that we performed when recording the test, but without all the pauses that humans are prone to but which computers don't need. It is also possible—and very common—to edit recorded tests, or to copy parts of recorded tests into manually created tests, as we will see later on in the tutorial.
Recordings are always made into existing tests, so we must begin by
creating a new "empty" test. There are two ways we can do this. One way
is to click |. This will pop up the New Squish Test Case wizard (Section 16.3.6)—simply enter the name
for the test case and then click . Another
way is to click the New Test Case toolbar button (to the right of the
"Test Cases" label in the Test Suites view); this will create a new test
case with a default name (which you can easily change). Use one of these
methods and give the new test case the name “tst_general”.
Squish automatically creates a sub-folder inside the test suite's
folder with this name and also a test file, in this case
test.py. (If we had chosen JavaScript as our
scripting language the file would be called
test.js, and correspondingly for Perl or Tcl.)

To make the test script file (e.g., test.py) appear
in an Editor view (Section 16.2.6), click—or double-click
depending on the
||| setting—the test case.
(Incidentally, the checkboxes are used to control which test cases are
run when the Run Test Suite toolbar button is clicked; we can always run
a single test case by clicking its Run Test button.) Initially, the
script is empty. If we were to create a test manually (as we will do
later on in the tutorial), we must create a
main function. The name "main" is special to
Squish—tests may contain as many functions and other code as we
like (providing it is legal for the scripting language), but when the
test is executed (i.e., run), Squish always executes the
main function. This is actually very convenient since it
means we are free to create other functions, import libraries, and so
on, without problems. It is also possible to share commonly used code
between test scripts—this is covered in the User Guide (Chapter 13). (In fact, two other function names are special
to Squish, cleanup and init; see Tester-Created Special Functions (Section 14.1) for details.)
Once the new empty test case has been created we are now free to write test code manually, or to record a test. If we choose to record we can either replace all the test's code with the recorded code, or insert recorded code into the middle of some existing test code. We will only concern ourselves with recording and replacing in the tutorial.
![]() | For command-line users |
|---|---|
Creating a new test case from the command line is an easy two-step process: first, create a test case directory; and second, create an empty test case script.
|
Before we dive into recording let's briefly review our very simple (and far from thorough) test plan:
Open the MyAddresses.adr address file.
Navigate to the second address and then add a new name and address.
Navigate to the fourth address (that was the third address) and change the surname field.
Navigate to the first address and remove it.
Verify that the first address is now the new one that was added.
We are now ready to record our first test. Click the toolbar button (
) that's to the right of the
tst_general test case shown in the Test Suites view (Section 16.2.16)'s Test Cases list. This will cause
Squish to run the AUT so that we can interact with it. Once the AUT is
running perform the following actions—and don't worry about how
long it takes since Squish doesn't record idle time:
Click
|,
and once the file dialog appears, click the
MyAddresses.adr filename, then click the
button.
Click the second row, then click |, then in the Add dialog's first line edit type in "Jane". Now click (or tab to) the second line edit and type in "Doe". Continue similarly, to set an email address of "jane.doe@nowhere.com" and a phone number of "555 123 4567". Don't worry about typing mistakes—just backspace delete as normal and fix them. Finally, click the button. There should now be a new second address with the details you typed in.
Click the fourth row's second (surname) column, delete its text and replace it with "Doe". (You can do this simply by overtyping.) Then press Enter to confirm your edit.
Now click the first row, then click |, and then click the button in the message box. The first row should be gone, so your "Jane Doe" entry should now be the first one.
Click the toolbar button in the Squish Control Bar (the second
button from the left).
This will make the Squish IDE appear. In the Application
Objects view expand the Window_0 object, then the
Table_0 object. Click the TableRow_4 object,
and then the TableCell_0 object
to make its properties appear in the
Properties view (Section 16.2.11), and then check the
text property's checkbox. Now click the
TableCell_1 object and check its
text property. Finally, click the
button (at the top-right of the Verification Point Creator view (Section 16.2.19)) to have the forename and
surname verifications for the first row inserted into the recorded test
script. (See the screenshot below.) Once the verification points are
inserted the Squish IDE's window will be hidden again and the Control Bar
window and the AUT will be back in view.
We've now completed the test plan, so in the AUT click |, then click in the message box, since we don't want to save any changes.

Once we quit the AUT, the recorded test will appear in Squish's IDE as the screenshot illustrates. (Note that the exact code that is recorded will vary depending on how you interact. For example, you might invoke menu options by clicking them or by using key sequences—it doesn't matter which you use, but since they are different, Squish will record them differently.)

If the recorded test doesn't appear, click (or double-click depending on
your platform and settings) the tst_general test
case; this will make Squish show the test's
test.py file in an editor window as shown in the
screenshot.
Now that we've recorded the test we are able to play it back, i.e., run it. This in itself is useful in that if the play back failed it might mean that the application has been broken. Furthermore, the two verifications we put in will be checked on play back as the screenshot shows.
Inserting verification points during test recording is very convenient. Here we inserted two in one go, but we can insert as many as we like as often as we like during the test recording process. However, sometimes we might forget to insert a verification, or later on we might want to insert a new verification. We can easily insert additional verifications into a recorded test script as we will see in the next section, Inserting Additional Verification Points (Section 4.4).
Before going further we will look at how to record a test from the command line. Then we will see how to run a test, and we will also look at some of the code that Squish generated to record the test and discuss some of its features.
![]() | For command-line users |
|---|---|
First and foremost, the squishserver must always be running when recording or running a test. This is handled automatically by the Squish IDE, but for command line users the squishserver must be started manually. (See squishserver (Section 15.4.2) for further details.) To record a test from the command line we execute the squishrunner program and specify the test suite we want to record inside and the name we want to give to the test case. For example (assuming we are in the directory that contains the test suite's directory): squishrunner --testsuite suite_py --record tst_general --useWaitFor
It is always best to record using the |
To run a test case in the IDE just click the toolbar button (the green right-pointing triangle that appears when the test case is selected in the Test Suites view (Section 16.2.16)). This will cause Squish to run the AUT and replay every action (omitting human idle time, but allowing just enough time for the GUI toolkit to keep up). It is worth trying out since it has quite an impressive effect, especially if you haven't seen it in action before.
When we have two or more test cases we can run them individually by clicking the test case we want to run to select it and then clicking the button, or we can run them all (one after the other) by clicking the toolbar button (which is above and slightly to the left of the button. (Actually, only those test cases that are checked are run by clicking the toolbar button, so we can easily run a particular group of tests.)
![]() | For command-line users |
|---|---|
As noted earlier, the squishserver must always be running when recording or running a test. (See squishserver (Section 15.4.2) for further details.) To play back a recorded test from the command line we execute the squishrunner program and specify the test suite our recorded script is in and the test case we want to play. For example (assuming we are in the directory that contains the test suite's directory): squishrunner --testsuite suite_py --testcase tst_general |
If you look at the code in the screenshot (or the code snippet shown
below) you will see that it consists of lots of waitForObject and waitForObjectItem calls as parameters to various
other calls such as mouseClick,
clickButton, and type. The waitForObject function waits until a GUI object
is ready to be interacted with (i.e., becomes visible and enabled), and
is then followed by some function that interacts with the object. The
typical interactions are click a menu, click a menu option
or a button, or type in some text. (For a complete overview of
Squish's script commands see the User Guide (Chapter 13), the
API Reference Manual (Chapter 14), and the Tools Reference Manual (Chapter 15). Objects are
identified by names that Squish generates. (See How to Identify and Access Objects (Section 13.1) for full details.)
The generated code is less than 35 lines. Here's an extract that just shows how Squish records clicking the Edit menu's Add option, typing in Jane Doe's details into the Add dialog, and clicking OK at the end to close the dialog and update the table.
![]() | Scripting Language Support |
|---|---|
Although the screenshots only show the Python test suite in action, for the code snippets quoted here and throughout the tutorial, we show the code for all the scripting languages that Squish supports. In practice you would normally only use one of them of course, so feel free to just look at the snippets in the language you are interested in and skip the others. (In the HTML version of this manual you can use the combobox at the top of the page to select the language you use—this will hide the code snippets in other languages.) |
mouseClick(waitForObjectItem(":Address Book - MyAddresses.adr_Menubar",
"Edit"))
mouseClick(waitForObjectItem(":Edit_MenuItem", "Add..."))
type(waitForObject(":Address Book - Add.Forename:_Edit"), "Jane")
type(waitForObject(":Address Book - Add.Forename:_Edit"), "<Tab>")
type(waitForObject(":Address Book - Add.Surname:_Edit"), "Doe")
type(waitForObject(":Address Book - Add.Surname:_Edit"), "<Tab>")
type(waitForObject(":Address Book - Add.Email:_Edit"),
"jane.doe@nowhere.com")
type(waitForObject(":Address Book - Add.Email:_Edit"), "<Tab>")
type(waitForObject(":Address Book - Add.Phone:_Edit"), "555 123 4567")
clickButton(waitForObject(":Address Book - Add.OK_Button"))
mouseClick(waitForObjectItem(":Address Book - MyAddresses.adr_Menubar",
"Edit"));
mouseClick(waitForObjectItem(":Edit_MenuItem", "Add..."));
type(waitForObject(":Address Book - Add.Forename:_Edit"), "Jane");
type(waitForObject(":Address Book - Add.Forename:_Edit"), "<Tab>");
type(waitForObject(":Address Book - Add.Surname:_Edit"), "Doe");
type(waitForObject(":Address Book - Add.Surname:_Edit"), "<Tab>");
type(waitForObject(":Address Book - Add.Email:_Edit"),
"jane.doe@nowhere.com");
type(waitForObject(":Address Book - Add.Email:_Edit"), "<Tab>");
type(waitForObject(":Address Book - Add.Phone:_Edit"), "555 123 4567");
clickButton(waitForObject(":Address Book - Add.OK_Button"));
mouseClick(waitForObjectItem(":Address Book - MyAddresses.adr_Menubar",
"Edit"));
mouseClick(waitForObjectItem(":Edit_MenuItem", "Add..."));
type(waitForObject(":Address Book - Add.Forename:_Edit"), "Jane");
type(waitForObject(":Address Book - Add.Forename:_Edit"), "<Tab>");
type(waitForObject(":Address Book - Add.Surname:_Edit"), "Doe");
type(waitForObject(":Address Book - Add.Surname:_Edit"), "<Tab>");
type(waitForObject(":Address Book - Add.Email:_Edit"),
"jane.doe\@nowhere.com");
type(waitForObject(":Address Book - Add.Email:_Edit"), "<Tab>");
type(waitForObject(":Address Book - Add.Phone:_Edit"), "555 123 4567");
clickButton(waitForObject(":Address Book - Add.OK_Button"));
mouseClick(waitForObjectItem(":Address Book - MyAddresses.adr_Menubar",
"Edit"))
mouseClick(waitForObjectItem(":Edit_MenuItem", "Add..."))
type(waitForObject(":Address Book - Add.Forename:_Edit"), "Jane")
type(waitForObject(":Address Book - Add.Forename:_Edit"), "<Tab>")
type(waitForObject(":Address Book - Add.Surname:_Edit"), "Doe")
type(waitForObject(":Address Book - Add.Surname:_Edit"), "<Tab>")
type(waitForObject(":Address Book - Add.Email:_Edit"),
"jane.doe@nowhere.com")
type(waitForObject(":Address Book - Add.Email:_Edit"), "<Tab>")
type(waitForObject(":Address Book - Add.Phone:_Edit"), "555 123 4567")
clickButton(waitForObject(":Address Book - Add.OK_Button"))
invoke mouseClick [waitForObjectItem \
":Address Book - MyAddresses.adr_Menubar" "Edit"]
invoke mouseClick [waitForObjectItem ":Edit_MenuItem" "Add..."]
invoke type [waitForObject ":Address Book - Add.Forename:_Edit"] "Jane"
invoke type [waitForObject ":Address Book - Add.Forename:_Edit"] "<Tab>"
invoke type [waitForObject ":Address Book - Add.Surname:_Edit"] "Doe"
invoke type [waitForObject ":Address Book - Add.Surname:_Edit"] "<Tab>"
invoke type [waitForObject ":Address Book - Add.Email:_Edit"] \
"jane.doe@nowhere.com"
invoke type [waitForObject ":Address Book - Add.Email:_Edit"] "<Tab>"
invoke type [waitForObject ":Address Book - Add.Phone:_Edit"] \
"555 123 4567"
invoke clickButton [waitForObject ":Address Book - Add.OK_Button"]
As you can see the tester used the keyboard to tab from one text field to another and clicked the OK button using the mouse rather than with a key press. If the tester had clicked the button any other way (for example, by pressing Alt+O, or by tabbing to the OK button and pressing the spacebar), the outcome would be the same, but of course Squish will have recorded the actual actions that were taken.
![]() | Lookup Efficiency |
|---|---|
In the code snippet it looks as though Squish is having to look up the
same objects by name time after time. In fact Squish cache's names, so
after a name has been looked up once, subsequent lookups are very fast.
Another thing to notice is that there are no explicit delays. (It is
possible to force a delay using Squish's Another point to notice is that all the object names begin with a colon. This identifies them as symbolic names. Squish supports several naming schemes, all of which can be used—and mixed—in scripts. The advantage of using symbolic names is that if the application changes in a way that results in different names being generated, we can simply update Squish's Object Map (which relates symbolic names to real names), and thereby avoid the need to change our test scripts. (See the Object Map (Section 15.10) and the Object Map view (Section 16.2.9) for more about the Object Map.) |
Now that we have seen how to record and play back a test and have seen the code that Squish generates, let's go a step further and make sure that at particular points in the test's execution certain conditions hold.