How to Use Event Handlers

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(eventName, handlerFunctionName) 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: 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 Object waitForObject(objectOrName) function.

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

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.

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

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

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

sub main
{
    startApplication("myapp");
    installEventHandler("MessageBoxOpened", "handleMessageBox");
    # ...
}
# 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
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:

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

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

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

sub main
{
    startApplication("myapp");
    installEventHandler("Crash", "crashHandler");
    # ...
}
# 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
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 or Configuring squishserver), or using the Squish IDE (see Squish Preferences Child Panes.)

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. Only the Qt version installEventHandler(eventName, handlerFunctionName) supports this kind of usage currently. For example, 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:

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

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

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

sub main
{
    startApplication("myapp");
    installEventHandler("QCheckBox", "QMouseEvent", "handleCheckBox");
    # ...
}
# 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
proc handleCheckBox {obj} {
    test log [concat "QCheckBox '" [objectName $obj] "' clicked"]
}

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

Event Handlers for Specific Objects

The third kind of event handling that Squish supports is for events that occur to particular objects. The only toolkit that supports this currently is the Qt toolkit. We can install an event handler that is called every time a line editor receives a QKeyEvent, so the event handler would be called every time some text is typed into the line editor. Here's an example:

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")
    ...
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");
    // ...
}
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");
    # ...
}
# 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
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 Object cast(object, type) function, to be able to access the object's methods and properties.

© 2023 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners.
The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation.
Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.