14.8. How to Use Event Handlers

14.8.1. Global Event Handlers
14.8.2. Event Handlers for All Objects of a Specified Type
14.8.3. Event Handlers for Specific Objects

In Squish test scripts it is possible to react to events that occur inside the AUT. This can be useful, for example, to provide a test script response for when a dialog appears unexpectedly, such as an error message box. This can be done by registering an event handler function for a particular event and that should be called when that event occurs on a specified object, or on an object of a specified type, or for any object.

Event handler functions are registered by calling an installEventHandler function. For a handler that should apply to all the AUT's objects—that is, a global event handler—just the event type and the handler function are passed as arguments. For a handler that should apply to a particular object or to all objects of a particular type, the object or type is passed as the first argument, followed by the event type and the handler function. In addition to standard toolkit events (such as Qt's QKeyEvent), some Squish- and toolkit-specific generic events are supported such as MessageBoxOpened and Crash.

[Note]Squish for Web-specific

For Squish for Web, event handler functions are always called with no argument, rather than passed an object (typically the object the event happened to). It is still possible to access objects inside Squish for Web event handlers, but we must obtain references to the objects ourselves, for example, using the waitForObject function.

In the following subsections we will look at example event handlers for all three cases.

14.8.1. Global Event Handlers

When a message box pops up the MessageBoxOpened event occurs. (In fact, the MessageBoxOpened event only applies to the Squish for Java™, Squish for Qt, and Squish for Windows editions; however, there are similar events for the other toolkits.) Like all such events the test script will ignore the event, but we can register an event handler function to be called whenever such events occur. It doesn't really make sense to associate a global event like this with a particular object or type, so it is usually handled by a global event handler.

Here we will look at an example of creating and installing a handler for message boxes.

Python
def handleMessageBox(messageBox):
    test.log("MessageBox opened: '%s' - '%s'" % (
        messageBox.windowText, messageBox.text))
    messageBox.close()

def main():
    startApplication("myapp")
    installEventHandler("MessageBoxOpened", "handleMessageBox")
    ...
JavaScript
function handleMessageBox(messageBox)
{
    test.log("MessageBox opened: '" + messageBox.windowText +
        "' - '" + messageBox.text + "'");
    messageBox.close();
}

function main()
{
    startApplication("myapp");
    installEventHandler("MessageBoxOpened", "handleMessageBox");
    // ...
}
Perl
sub handleMessageBox
{
    my $messageBox = shift @_;
    test::log("MessageBox opened: '" . $messageBox->windowText .
        "' - '" . $messageBox->text + "'");
    $messageBox->close();
}

sub main
{
    startApplication("myapp");
    installEventHandler("MessageBoxOpened", "handleMessageBox");
    # ...
}
Ruby
# encoding: UTF-8
require 'squish'
include Squish

def handleMessageBox(messageBox)
    Test.log("MessageBox opened: '%s' - '%s'" % [
        messageBox.windowText, messageBox.text])
    messageBox.close
end

def main
    startApplication("myapp")
    installEventHandler("MessageBoxOpened", "handleMessageBox")
    ...
end
Tcl
proc handleMessageBox {messageBox} {
    test log [concat "MessageBox opened: '" \
        [property get $messageBox windowText] "' - '" \
        [property get $messageBox text]  "'"]
    invoke $messageBox close
}

proc main {} {
    invoke startApplication "myapp"
    installEventHandler "MessageBoxOpened" "handleMessageBox"
    # ...
}

Note that if we were using a similar Squish for Web event (e.g., ModalDialogOpened), the dialog would not be passed as an argument, because Squish for Web event handlers receive no arguments.

Another special event is Crash. This is useful when we want to install an event handler to be called when the AUT crashes—for example, to do cleanups or to restart the AUT. (The Crash event is supported by all Squish versions, except for Squish for Web.) Here's an example:

Python
def crashHandler():
    test.log("Deleting lock files after AUT crash")
    deleteLockFiles()

def main():
    startApplication("myapp")
    installEventHandler("Crash", "crashHandler")
    ...
JavaScript
function crashHandler()
{
    test.log("Deleting lock files after AUT crash");
    deleteLockFiles();
}

function main()
{
    startApplication("myapp");
    installEventHandler("Crash", "crashHandler");
    // ...
}
Perl
sub crashHandler
{
    test::log("Deleting lock files after AUT crash");
    deleteLockFiles();
}

sub main
{
    startApplication("myapp");
    installEventHandler("Crash", "crashHandler");
    # ...
}
Ruby
# encoding: UTF-8
require 'squish'
include Squish

def crashHandler
    Test.log("Deleting lock files after AUT crash")
    deleteLockFiles
end

def main
    startApplication("myapp")
    installEventHandler("Crash", "crashHandler")
    ...
end
Tcl
proc crashHandler {} {
    test log "Deleting lock files after AUT crash"
    deleteLockFiles
}

proc main {} {
    invoke startApplication "myapp"
    installEventHandler "Crash" "crashHandler"
    # ...
}

A third kind of special event is the Timeout event. These events are triggered whenever the AUT fails to respond to some Squish command within five minutes. This can happen if the application got stuck in an endless loop, or if there is some other reason that keeps it from being able to respond. You can install an event handler for this event so that your tests can handle such situations gracefully. The timeout time can be changed by using the squishrunner's or squishserver's setResponseTimeout option (see Configuring squishrunner (Section 16.4.1.7) or Configuring squishserver (Section 16.4.2.3)), or using the Squish IDE (see Squish pane's child panes (Section 17.3.11.7.1).)

14.8.2. Event Handlers for All Objects of a Specified Type

It is possible to set up an event handler that will respond to particular types of events for all objects of a specified type. For example, using Squish for Qt, we can install an event handler which is always called when a QMouseEvent occurs on a QCheckBox. This means that every time the event occurs, that is, whenever any of the AUT's checkboxes is clicked, the event handler is called. Here's an example:

Python
def handleCheckBox(obj):
    test.log("QCheckBox '%s' clicked" % objectName(obj))

def main():
    startApplication("myapp")
    installEventHandler("QCheckBox", "QMouseEvent", "handleCheckBox")
    ...
JavaScript
function handleCheckBox(obj) {
    test.log("QCheckBox '" + objectName(obj) + "' clicked");
}

function main() {
    startApplication("myapp");
    installEventHandler("QCheckBox", "QMouseEvent", "handleCheckBox");
    // ...
}
Perl
sub handleCheckBox
{
    my $obj = shift @_;
    test::log("QCheckBox '" . objectName($obj) . "' clicked");
}

sub main
{
    startApplication("myapp");
    installEventHandler("QCheckBox", "QMouseEvent", "handleCheckBox");
    # ...
}
Ruby
# encoding: UTF-8
require 'squish'
include Squish

def handleCheckBox(obj)
    Test.log("QCheckBox '%s' clicked" % [objectName(obj)])
end

def main
    startApplication("myapp")
    installEventHandler("QCheckBox", "QMouseEvent", "handleCheckBox")
    ...
end
Tcl
proc handleCheckBox {obj} {
    test log [concat "QCheckBox '" [objectName $obj] "' clicked"]
}

proc main {} {
    invoke startApplication "myapp"
    installEventHandler "QCheckBox" "QMouseEvent" "handleCheckBox"
    # ...
}

Similar event handlers for similar events can be created using the other toolkits that Squish supports, but recall that for Squish for Web, no argument is passed to the event handler, so if we want to interact with an object we must first obtain a reference to it (e.g., using the waitForObject function.)

14.8.3. Event Handlers for Specific Objects

The third kind of event handling that Squish supports is for events that occur to particular objects. For example, again using the Qt toolkit, we could install an event handler that was called every time a line editor received a QKeyEvent, so the event handler would be called every time the test typed some text into the line editor. Here's an example:

Python
def handleDescriptionLineEdit(obj):
    lineEdit = cast(obj, QLineEdit)
    test.log("QLineEdit '%s' text changed: %s" % (
        objectName(obj), lineEdit.text))

def main():
    startApplication("myapp")
    lineEdit = waitForObject(":Description:_QLineEdit")
    installEventHandler(lineEdit, "QKeyEvent",
        "handleDescriptionLineEdit")
    ...
JavaScript
function handleDescriptionLineEdit(obj)
{
    var lineEdit = cast(obj, QLineEdit);
    test.log("QLineEdit '" + objectName(obj) +
        "' text changed: " + lineEdit.text)
}

function main()
{
    startApplication("myapp");
    var lineEdit = waitForObject(":Description:_QLineEdit");
    installEventHandler(lineEdit, "QKeyEvent",
        "handleDescriptionLineEdit");
    // ...
}
Perl
sub handleDescriptionLineEdit
{
    my $obj = shift @_;
    my $lineEdit = cast($obj, QLineEdit);
    test::log("QLineEdit '" . objectName($obj) .
        "' text changed: " . $lineEdit->text);
}

sub main
{
    startApplication("myapp");
    my $lineEdit = waitForObject(":Description:_QLineEdit");
    installEventHandler($lineEdit, "QKeyEvent",
        "handleDescriptionLineEdit");
    # ...
}
Ruby
# encoding: UTF-8
require 'squish'
include Squish

def handleDescriptionLineEdit(obj)
    lineEdit = cast(obj, QLineEdit)
    Test.log("QLineEdit '%s' text changed: %s" % [
        objectName(obj), lineEdit.text])
end

def main
    startApplication("myapp")
    lineEdit = waitForObject(":Description:_QLineEdit")
    installEventHandler(lineEdit, "QKeyEvent",
        "handleDescriptionLineEdit")
    ...
end
Tcl
proc handleDescriptionLineEdit {obj} {
    set lineEdit [cast $obj QLineEdit]
    test log [concat "QLineEdit '" [objectName $obj] \
        "' text changed: " [toString [property get $lineEdit text]]]
}

proc main {} {
    invoke startApplication "myapp"
    set lineEdit [waitForObject ":Description:_QLineEdit"]
    installEventHandler $lineEdit "QKeyEvent" "handleDescriptionLineEdit"
    # ...
}

The object passed as obj is just a generic Squish object; we must cast it to an object of the correct type using the cast function, to be able to access the object's methods and properties.