RIATest 2 Documentation Copyright © RIATest.com

Synchronization or how to make your script wait when needed

One of the most frequently arising issues when writing automated tests is synchronization. When a test script runs it emulates user actions on Application Under Test. However those actions cannot be performed at an arbitrary speed because it takes time for the application to execute and react to the actions. This naturally leads to the requirement for automation tool to wait when needed for the preceding actions to complete their execution before emulating the next action or checking for a verification condition. This is called synchronization.

RIATest is capable of synchronizing automatically in the following cases:

However there are times when the automatic synchronization capability of RIATest is not sufficient and you have to manually specify that the script execution must wait for a specific condition. This usually happens when emulated user action triggers an asynchronous operation in your application. For example clicking on a button starts an operation that connects to server, requests some data and when it is received populates it in a list or data grid. Network operations are all inherently asynchronous because they take time and their duration is not definite. RIATest does not know that an asynchronous operation is happening in your application and thus will immediately attempt to execute the following action or property verification operation. If this next operation is for example an attempt to select an item from the list (to be populated) it will most certainly fail since the network operation has not yet complete, data is not received, the list is not populated and the item to be selected does not yet exist.

So, how do you make your script wait in such cases? The general idea is the following. Try to imagine what does the user do when working with the application. The user clicks on the button then starts watching the list. When items appear in the list only then the user will attempt to select from the list. In other words the user is synchronizing on a visual clue. The clue here is the list itself. While it is empty, wait. When the items appear, go ahead and click. Your goal as script author is to try to emulate the behavior of the user. Let's see how would our script look if we record user's actions (click on the button and make selection from the list).

FlexButton("Load")=>click();
FlexList("MyList")=>select("The Item");

What we need is to make the script wait after first action for the list to be populated before proceeding to the second action. One of the ways to do it is to use numAutomationChildren property of the list. This property is the number of the visible items in the list. If the list is empty this is property equals 0. So what we could do is to wait until this property's value becomes greater than zero, e.g.:

FlexButton("Load")=>click();
waitfor(FlexList("MyList")=>numAutomationChildren > 0);
FlexList("MyList")=>select("The Item");

Here we are using waitfor operator which keeps querying expression in the parentheses until it becomes true (or until timeout - by default 30 seconds). So the line 2 above would wait until at least one item appears in the list. In trivial cases this would be sufficient. The data from server is received in one big portion and all items in the list are populated at once. So as soon as we make sure there is at least one item in the list we can be sure all them are there and we can make the selection. However for more complex cases this may not be enough.

Suppose that the loading process occurs in portions, i.e. multiple requests are made to server sequentially and each reply from the server returns a small portion of data which the application immediately shows in the list and then sends another request to the server and so on until all the data is received and populated in the list. If this was the case then waiting for at least one item to appear in the list does not guarantee that the particular item we want to select is also present and can be selected. The waitfor operation in the above code snippet would not sufficient in such case.

What we need to do is to wait until the particular list item appears in the list so that it can be selected. The following code does exactly that:

FlexButton("Load")=>click();
waitfor(FlexList("MyList")->FlexListLabel("The Item")=>visible);
FlexList("MyList")=>select("The Item");

The second line will wait until there is a visible item with text "The Item" in the "MyList". This does not guarantee that entire list is loaded but it does guarantee that the item that we want to select is available. Does this pose a problem? It depends on your application. If it is ok for the user to make selection when the list is partially loaded and is still loading then all will be fine. From the other side if it is not ok to make such selection then the application should prevent the user from making such selection in the first place. How would it do it? By providing another visual clue to the user. For example it would show a progress bar while the operation is in progress and most likely would disable the list control. But these visual clues can be successfully used for synchronization from the script. For example if your application disables the list while loading and enables it when the load is complete you could do the following:

FlexButton("Load")=>click();
waitfor(FlexList("MyList")=>enabled);
FlexList("MyList")=>select("The Item");

Line 2 in above code will wait until entire list is loaded and the list is enabled before proceeding to the select action.

We have presented a few alternate ways to perform synchronization in this article. What they have in common is the idea to understand what visual clues are presented by the application to the user and use these visual clues for synchronization. In most cases this approach can be successfully used to perform the synchronization that is neccessary.