Forum Discussion

MrDysprosium's avatar
MrDysprosium
Contributor
8 years ago

How to wait for an object to exist without an arbitrary delay?

From what I've read on the forums, it seems that the TC solution to "My project fails when I use object.Exists on an object that wasn't there yet" is to just put in a delay for an arbitrarily long amount of time before you do the "Exists" check on an object.

What I want to do is something like this:

while !(object.exists):
    aqUtils.Delay(1000, "Waiting for object to exist)

//do other stuff now that the object exists.

Buuuuutttttt, this doesn't work. The project will fail immediately because the object doesn't exist.

So how do you guys get around this? Are there any smart ways of handling this without killing the test and starting over? 

3 Replies

  • tristaanogre's avatar
    tristaanogre
    Esteemed Contributor

    Change your code to this:

     

    var myObject = Aliases.MyApp.MyForm.WaitAliasChild('myObject', 20000);
    
    if (!myObject.Exists){
        Log.Error('My object does not exist after 20 seconds');
    }

    There are ways of adapting this to different ways of executing this but the key is the special method of "WaitAliasChild".  There are similar methods (what you may see around the forums as "WaitNNN" methods) that you can read about at https://support.smartbear.com/testcomplete/docs/app-testing/mobile/android/open/checking-object-state/waiting-for-objects.html?q=WaitNNN#using-waitnnn-methods. Each of these operates on the same general principle.

     

    For myself, I create a library function that allows me to, given any parent object, child object name, and designated wait time, I can wait for any given period.  Now, I use NameMapping so this assumes aliases and such are designated.

     

    function waitForObject(parentObject, childName, milliseconds = 60000){
        var childObject;
        if ((parentObject === undefined)||(parentObject === null)) {
            throw Error('Parent object is undefined or null');
        }
        if ((childName === undefined)||(childName === null)) {
            throw Error('Child name is missing');
        }
        childObject = parentObject.WaitAliasChild(childName, milliseconds);
        if (!childObject.Exists) {
            throw Error('Could not find the object ' + childName + ' in the disgnated ' + milliseconds + 'ms');
        }
    
    }

    Now, if you're not using mapping or the object you are waiting for is not mapped, then you want to use FindChild (https://support.smartbear.com/testcomplete/docs/reference/test-objects/members/common-for-all/findchild-method.html) which, again, you can wrap that in a function like so

     

    function waitForObject(propertiesArray, valuesArray, parentObject, depth, milliseconds = 60000){
        var childObject;
        var counter = 0;
        //I'm leaving out the code to check for proper parameters but I'd recommend bullet proofing your code
        childObject = parentObject.FindChild(propertiesArray, valuesArray, depth);
        while ((!childObject.Exists) && (counter < milliseconds / 500)) {
            aqUtils.Delay(500);
            counter++
        }
        if (counter = milliseconds/500){
             return null;
        }
        return childObject;
    }

    This function will wait the indicated amount of time.  If the object returns within that time, the function returns the object.  If not, it returns null.

     

    Again... these are just two ways of doing it... but the key is that you use some built in method (either WaitNNN or FindChild) to look for the object before you check for "exists".  

  • tristaanogre's avatar
    tristaanogre
    Esteemed Contributor

    BTW, any article you read that just says "Use an arbitrary delay" is either a) wrong or b) misread. Arbitrary delays won't work 100% of the time.  What if your application under test decided to have a bad day and wait longer than that fixed number?  You'll still fail.

     

    Note that, in my second example I am using the aqUtils.Delay method, but it's not the same... I'm not waiting for a fixed 500 milliseconds...I'm basically building a method similar to the WaitNNN methods but for situations where I can't use one of those and have to use the FindChild. FindChild doesn't have a delay property so I use the aqUtils.Delay method to simulate that.  At minimum, using that function, it will return almost immediately... but if it doesn't you'll only have to wait increments of half a second.

    • AlexKaras's avatar
      AlexKaras
      Icon for Champion Level 1 rankChampion Level 1

      > FindChild doesn't have a delay property

      There is a great complimentary FindChildEx() one. Pretty useful in a lot of cases...