Overriding Squish functions

Overriding Squish functions

Motivation

There may be cases where one wants to change the behavior of the functions provided by Squish.

For example, even though the default timeout of waitForObject() is 20 seconds (which usually is enough for a GUI control to be “visible and enabled”), in some rare cases one may find that this is still not enough time.

One would usually handle such cases individually by adding a second parameter to the respective waitForObject() call, which stands for the desired timeout in milliseconds:

// Let's wait for up to 40 seconds for ":x":
waitForObject(":x", 40000);

But, what if there are many more places where such a change would needed?

Then we would have to go through our script, adding the timeout parameter to all the other desired waitForObject() calls, which can be a very tedious and error prone task.

Also, we may not even know in advance where these longer timeouts are required.

Here is an (abbreviated) example test script where the default timeout of waitForObject() is sometimes too short (and we assume that there are many other places in the source code where the default timeout is too short, too):

function main()
{
    startApplication("addressbook");

    // Sometimes it takes up to 30 seconds for the
    // main window to appear, so this sometimes
    // leads to an Object Not Found error at script
    // runtime:
    waitForObject("{type='MainWindow'}");

    // ...
}

In such a case it can be suitable to override the waitForObject() function itself, which allows us to alter its behavior, for example using a different default timeout value.

Solution

We will now override the waitForObject() function to have a larger default timeout (40.000 milliseconds). We will also add messages to the log to know whether the default timeout or a custom timeout has been used:

function main()
{
    startApplication("addressbook");

    // Generally override Squish functions after
    // switching application contexts to avoid
    // that the overrides are being reset:
    overrideWaitForObject();

    // Sometimes it takes up to 30 seconds for the
    // main window to appear, but with our overridden
    // waitForObject() function the default is 40
    // seconds, so the Object Not found error that
    // we sometimes got here should be properly
    // avoided now:
    waitForObject("{type='MainWindow'}");

    // ...
}

function myWaitForObject(objectOrName, optionalTimeout)
{
    if (optionalTimeout == null) {
        test.log("Using new default timeout: 40000");
        return myWaitForObject.waitForObjectOriginal(
                objectOrName, 40000);
    }

    test.log("Using custom timeout: " + optionalTimeout);
    return myWaitForObject.waitForObjectOriginal(
            objectOrName, optionalTimeout);
    }
}
 
function overrideWaitForObject()
{
    // Store a reference to the original function
    // on our custom function, so that we can still
    // access it in our custom function:
    myWaitForObject.waitForObjectOriginal = waitForObject;

    // Override waitForObject with our own function:
    waitForObject = myWaitForObject;
}

After executing this the Test Results view shows this:

This looks like what we wanted: The new default timeout of 40.000 milliseconds has been used.

But there is one problem here: When double clicking on the log message “Using new default timeout: 40000” the script editor shows and selects the script line where the test.log() function is being called:

In most of the cases though, this is not the desired behavior, especially in case of errors. Instead we want that the script line where waitForObject() is being called to be shown and selected.

Fortunately Squish allows to achieve this as well, by using test.fixateResultContext() and test.restoreResultContext(), as shown in the next section.

Improved Solution

Here is our myWaitForObject() function again, but we have added calls to test.fixateResultContext() and test.restoreResultContext() (the latter in a try/finally block to ensure that it will always be called):

// ...

function myWaitForObject(objectOrName, optionalTimeout)
{
    // Enable that log and test result messages as well
    // as errors are being reported on the calling
    // source code line so that a double click on the
    // respective message opens that source code line
    // in the editor, which typically is the wanted
    // behavior:
    test.fixateResultContext();

    // Use try/finally to ensure that even in case of
    // errors test.restoreResultContext() is being
    // executed:
    try {
        if (optionalTimeout == null) {
            test.log("Using new default timeout: 40000");
            return myWaitForObject.waitForObjectOriginal(
                    objectOrName, 40000);
        } else {
            test.log("Using custom timeout: " + optionalTimeout);
            return myWaitForObject.waitForObjectOriginal(
                    objectOrName, optionalTimeout);
        }
    } finally {
        // Change message reporting back to the
        // default:
        test.restoreResultContext();
    }
}

// ...

After executing this the Test Results view still shows the same as before:

This time when double clicking on the log message “Using new default timeout: 40000” the script editor shows and selects the script line where waitForObject() has been called:

0 Comments

Leave a reply

Your email address will not be published. Required fields are marked *

*