Synchronization functions like waitForObject() or action functions like mouseClick() error out with a script error like this:
Here, <name> is the argument passed to the function. The error may seem to occur randomly or it might always occur in a particular script statement.
- Object synchronization functions such as waitFor(), waitForObject(), waitForObjectItem(), findObject(), and object.exists() must be used to ensure that Squish doesn't try to execute tests faster than the GUI (designed for "slow" human users) can keep up.
- The waitForObject() and waitForObjectItem() functions default to waiting 20000 milliseconds (20 seconds) for the object they are given to be visible and ready to use. They raise a catch-able exception if they time out.
- The object.exists() and findObject() functions look for the specified object immediately, regardless of whether it is visible or ready. If the object isn't found object.exists() returns false and findObject() raises a catch-able exception.
- General commands like mouseClick(), clickButton(), etc., use findObject() internally. So if the object cannot be found when these commands execute this results in an immediate error.
- Object synchronization must allow for varying delays (e.g., due to network latency, I/O load, CPU speed and activity). This means that Squish must wait longer than one would typically expect.
- By enabling screenshot generation in case of errors and failures (testSettings.logScreenshotOnError, testSettings.logScreenshotOnFail) one can roughly verify whether, say, an object's caption is what it is expected to be (although using one of Squish's test functions on the object's actual text is much more reliable). However, where screenshots can prove very helpful is to show us if a window or dialog that we expected to appear really did or not.
Keep in mind that when you use object synchronization with wait functions such as waitForObject() and waitForObjectItem(), these functions have built-in a default timeout of 20000 milliseconds (20 seconds). But if your test machines are under heavy (and more or less random) load that is sufficient to slow down your application, it may be that this default timeout becomes insufficient for some operations.
So, if you know that after pressing a button the next object that should be automated will take 15 seconds to appear (maybe because the application must do a computationally expensive calculation), then setting a timeout larger than even the default 20 seconds is a good idea.
Before interacting with a GUI object Squish must first find the object. This typically involves Squish looking up the object's symbolic name in the Object Map to find the properties by which the object can be identified, and then Squish will search the AUT's objects to find one that matches the properties. Then Squish will check to see if the object is ready for interaction, i.e., that the object is both visible and enabled. If Squish can't find the object (i.e., if it cannot find any object whose properties match those it is looking for), or if it finds the object but the object isn't visible or isn't enabled, a catch-able exception will be thrown.
The underlying causes typically fall into two categories:
- Timing Problems. GUI controls are often not available instantly. For example, applications can take a while to load in the first place, during which some or all of their widgets may be unavailable. Furthermore, if an expensive computation is initiated, during the computation some widgets may become inaccessible (because the application becomes unresponsive). Modern applications often use animation effects and these too can cause a timing dependency: for instance, rather than a button suddenly appearing it may be animated into visibility and might not be clickable until the animation completes. How long an application takes to perform any particular action can also vary depending on how much load the system is under. And for applications that use networking, network latency can impact how long things take.
- Application State Differences. An application's user interface can have different states between when a test was recorded and when the same test is played back. There might even be state differences between two executions of the same test. One possible reason for this is that some applications have a "Save and Restore" feature (like the Squish IDE), that remembers the application's state when it was last terminated (e.g., window and toolbar sizes and positions, open files, etc.), and restores this state when the application restarts. Another cause can be that the application shows data that varies from run to run such as the current date and time shown in a label or status bar. And, of course, even if the application accesses the same file each time, if the content of the file is changed between test runs this may affect the application's state.
Other differences (which are not addressed here) are changes to the application's source code or configuration such as changed label texts, changed window titles, or changed version number (e.g., as shown in the About box).
First, determine whether the error is caused by a timing issue or not. Is the error thrown by a call to a function like waitForObject() or waitForObjectItem() that times out after 20 seconds? If you are sure that it is legitimate to wait longer (for example, waiting for your application's splash screen to go away so that the main window is revealed), you can specify a longer timeout. For example:
Is the error thrown by an interaction function like mouseClick()? If the function is given an object name or reference directly, there are various options to try. If the object is the subject of a waitForObject() or similar call on the preceding line, you could add an explicit timeout to make the wait longer. And if there is no such call, you could try adding one, either before the interaction function, or within it, e.g., change from something like mouseClick(":_OK_Button") to something like mouseClick(waitForObject(":_OK_Button")).
A quick and dirty way to detect (and work around) timing issues is to force Squish to wait for a specific hard-coded amount of time. For example, here is a statement that will make the script execution wait for 5 seconds:
In some cases, this alone will be sufficient to resolve any problems. However, in general it is best to to use a wait function wherever possible.
How to cope with state differences depends on what causes the differences.
If the problem is with a "Save and Restore" feature it might be possible to switch it off. Alternatively, make sure that just before the end of every test recording, you close files and generally set the application to how you want it to be at the start of each test and then close the application and finish the test recording. A more drastic approach is to delete the application's settings before each test run so it always starts up cleanly.
If the test involves modifying a file that will then be read by the application on a subsequent test, make sure that the original file is preserved and used for each test run.
A counter-measure to prevent changing text properties (i.e., labels that show the current date and time or random IDs) from causing test runs to fail, is to use inexact property matching for the affected objects using Squish's wildcard and regular expression matching facilities. (See Improving Object Identification and Matching Objects with Changeable Texts
When Squish cannot find any object of the type specified in the real name (also see Article - How Squish looks up Real Names from Symbolic Names), it will give an error message similar to this, which mentions the "type":
When Squish finds one or more objects of the type specified in the real name (also see Article - How Squish looks up Real Names from Symbolic Names), but one or more of the property value specified in the real name does not match any of the found objects, it will give an error message similar to this, which mentions each unmatched property: