5.11. How to Create and Use Synchronization Points

When recording a script in Squish, the event recorder must ensure that the AUT and the test script are synchronized. One way of achieving this is for the recorder to automatically insert snooze statements into the script. These statements force the script to wait for a specified number of seconds (which might be a fractional amount such as 2.5). This is necessary to ensure that a script is replayed at the same speed as it was recorded. For example, if the user waited for a window to pop up, the script will wait for the same amount of time. This is important to prevent Squish from running the AUT too fast for the AUT's toolkit to keep up.

Using snooze statements is the simplest way to synchronize the AUT and a test script. But in many cases, simply waiting for a certain amount of time isn't sufficient. For example, if a script is recorded on a fast machine and later replayed on a slow machine the time waited by snooze might not be long enough.

Another way of synchronizing is to use waitForObject statements instead of snooze statements. If the waitForObject function is used, before every action that is recorded, a waitForObject statement will be recorded so that the object can be accessed. So on replay, instead of waiting for a specific amount of time, Squish will wait for the given object to exist and be accessible (i.e., visible). Since using the waitForObject function has proved much more reliable than using the snooze, it is the default method used when recording test cases.

A third alternative is to use the waitFor function. This function waits until a given condition becomes true, or optionally, until a specified time out expires. The condition can be anything from a property to a complex script statement. Here is an example that waits for a particular dialog to pop up, and logs a fatal error if the dialog doesn't appear within 5 seconds:

Python
ok = waitFor("object.exists(':Address Book - Save As_QFileDialog')",
    5000)
if not ok:
    test.fatal("AddressBook Save As dialog didn't appear")
JavaScript
var ok = waitFor("object.exists(':Address Book - Save As_QFileDialog')",
    5000);
if (!ok)
    test.fatal("AddressBook Save As dialog didn't appear");
Perl
my $ok = waitFor("object::exists(':Address Book - Save As_QFileDialog')",
    5000);
if (!$ok) {
    test::fatal("AddressBook Save As dialog didn't appear");
}
Ruby
ok = waitFor("Squish::Object.exists(':Address Book - Save As_QFileDialog')",
    5000)
if !ok
    Test.fatal("AddressBook Save As dialog didn't appear")
end
Tcl
set ok [waitFor {object exists ":Address Book - Save As_QFileDialog"} \
    5000]
if {!$ok} {
    test fatal "AddressBook Save As dialog didn't appear"
}

Here is another example, this time one that will wait “forever” since no timeout is specified. So if the expected file doesn't exist and isn't created, the test script will be stuck:

Python
waitFor("QFile.exists('addresses.tsv')")
JavaScript
waitFor("QFile.exists('addresses.tsv')");
Perl
waitFor("QFile::exists('addresses.tsv')");
Ruby
waitFor("QFile.exists('addresses.tsv')")
Tcl
waitFor {invoke QFile exists "addresses.tsv"}

This next example waits up to 2 seconds for an OK button to become enabled. The waitFor function repeatedly evaluates the code it has been given as its first argument and returns true as soon as the code evaluates to true; or returns false if the code doesn't evaluate to true within the number of milliseconds specified by its second argument.

Python
button = findObject(":Address Book - Add.OK_QPushButton")
enabled = waitFor("button.enabled", 2000)
if not enabled:
    test.fatal("OK button has not been enabled")
JavaScript
var button = findObject(":Address Book - Add.OK_QPushButton");
var enabled = waitFor("button.enabled", 2000);
if (!enabled)
    test.fatal("OK button has not been enabled");
Perl
my $button = findObject(":Address Book - Add.OK_QPushButton");
my $enabled = waitFor("$button->enabled", 2000);
if (!$enabled) {
    test::fatal("OK button has not been enabled");
}
Ruby
button = findObject(":Address Book - Add.OK_QPushButton")
enabled = waitFor("button.enabled", 2000)
if !enabled
    Test.fatal("OK button has not been enabled")
end
Tcl
set button [findObject ":Address Book - Add.OK_QPushButton"]
set enabled [waitFor {property get $button enabled} 2000]
if {!$enabled} {
    test fatal "OK button has not been enabled"
}

These examples show different variations of synchronization points. As the condition which is passed to the waitFor function can be any script code which can be evaluated, including function calls, there are no limits to creating synchronization points.

More on synchronization for Web applications and advanced AJAX synchronization can be found at How to Synchronize Web Page Loading for Testing (Section 5.3.8).