Forum Discussion

SarahEdwards's avatar
SarahEdwards
Contributor
8 years ago

Dynamically verify object property in script via Keyword test

For better or worse, I'm meshing scripts with keyword tests. I'm trying to pass into a function the on-screen object and then the property of said object, like "Exists" or "Enabled".

 

function waitToRunExists(selector, prop, attempts) 
{
var theElement;

//Prime the attempts variable
if( typeof attempts == "undefined" || attempts == null ) 
{
attempts = 1;
}
var theElement = selector;

// Wait for theElement/on-screen object to be true, or bail after X attempts
do{

attempts++;
if (attempts > 500)
{
Log.Error("Too many attempts. attempts = " + attempts + ".");
} 
} 
while ( theElement.prop == false || attempts > 500); //attempts was 200 // || attempts > 200

}

In the keyword test, I'm using the "Run Script Routine". For the prop variable, I've tried string, variant, code expression, etc. It seems like a type issue, but I can't find the correct type. Any suggestions?

 

 

  • Question:  Is the test simply a test of the properties of "Exists", "Enabled", "Visible"?  If so, you don't need a new script routine for it, you can simply use the If-Object operation in Keyword tests (https://support.smartbear.com/testcomplete/docs/keyword-testing/reference/test-actions/if-object.html).  This covers these basic items with out needing custom code.

     

    Now, as for your code: The problem with your code as it is written is, if you pass in the object itself and you're checking for "Exists" and the object doesn't ACTUALLY exist, you're going to get an error in your check of that property, no matter how you implement it.  You can't evaluate the ANY property of an object that does not exist... that object has to exist first before you can evaluate the property.  What I would do is, instead of the object itself, pass in the PARENT of the object. You can then do a "WaitChild" method of sorts to get the object you're wanting to test and, if it comes back empty, you'll know it doesn't exist.  If it comes back with Exists being "true", then you can do whatever other tests you want.

     

    So... if I were to rewrite your code to be able to check for a property value given any particular property string, this is how I would do it.

     

     

    function waitToRunExists(parent, selector, prop, propValue, attempts) {
        var theElement;
        var existCounter = 0;
        var attemptCounter = 0;
        //Prime the attempts variable
        if( typeof attempts == "undefined" || attempts == null ) {
            attempts = 1;
            }
        //wait for Element to exist
        theElement = parent.WaitAliasChild(selector, 500 );
        while (existsCounter < 120) {
            if (theElement.Exists) break;
            existsCounter++;
            theElement = parent.WaitAliasChild(selector, 500 );
        } 
        //if the element doesn't exist after 2 minutes, log an error and skip the rest of the function
        if ((existsCounter == 120) && (!theElement.Exists)) {
            Log.Error('The object ' + selector + ' does not exist');
        } else {
        // if the Object does exist, loop until either the # of loops exceeds the desired # of attempts
        // or the desired property of theElement is true
            do {
                attemptCounter++;
                if (attemptCounter > attempts) {
                    Log.Error("Too many attempts. attempts = " + attempts + ".");
                
                } 
            } while ((aqObject.GetPropertyValue(theElement, prop) != propValue) || (attemptCounter > attempts)); //attempts was 200 // || attempts > 200
        }
    }
    Now, that SAID... this is still redundant code if you're looking to wait for a property to come back with a certain value. In your keyword test, after checking to see if the object exists (see my while loop in the above code), you can add an OnScreen Action for the object and, as the action, use WaitProperty method (https://support.smartbear.com/testcomplete/docs/reference/test-objects/members/common-for-all/waitproperty-method.html). Basically, you can tell the test case to wait until an object's property has a particular value OR the wait method times out. To see if it worked, just use the "Last Result" value in an if then statement to check to see if it returns true... if it's true, the property is the desired value. If false, the timeout happened.
  • tristaanogre's avatar
    tristaanogre
    Esteemed Contributor

    Question:  Is the test simply a test of the properties of "Exists", "Enabled", "Visible"?  If so, you don't need a new script routine for it, you can simply use the If-Object operation in Keyword tests (https://support.smartbear.com/testcomplete/docs/keyword-testing/reference/test-actions/if-object.html).  This covers these basic items with out needing custom code.

     

    Now, as for your code: The problem with your code as it is written is, if you pass in the object itself and you're checking for "Exists" and the object doesn't ACTUALLY exist, you're going to get an error in your check of that property, no matter how you implement it.  You can't evaluate the ANY property of an object that does not exist... that object has to exist first before you can evaluate the property.  What I would do is, instead of the object itself, pass in the PARENT of the object. You can then do a "WaitChild" method of sorts to get the object you're wanting to test and, if it comes back empty, you'll know it doesn't exist.  If it comes back with Exists being "true", then you can do whatever other tests you want.

     

    So... if I were to rewrite your code to be able to check for a property value given any particular property string, this is how I would do it.

     

     

    function waitToRunExists(parent, selector, prop, propValue, attempts) {
        var theElement;
        var existCounter = 0;
        var attemptCounter = 0;
        //Prime the attempts variable
        if( typeof attempts == "undefined" || attempts == null ) {
            attempts = 1;
            }
        //wait for Element to exist
        theElement = parent.WaitAliasChild(selector, 500 );
        while (existsCounter < 120) {
            if (theElement.Exists) break;
            existsCounter++;
            theElement = parent.WaitAliasChild(selector, 500 );
        } 
        //if the element doesn't exist after 2 minutes, log an error and skip the rest of the function
        if ((existsCounter == 120) && (!theElement.Exists)) {
            Log.Error('The object ' + selector + ' does not exist');
        } else {
        // if the Object does exist, loop until either the # of loops exceeds the desired # of attempts
        // or the desired property of theElement is true
            do {
                attemptCounter++;
                if (attemptCounter > attempts) {
                    Log.Error("Too many attempts. attempts = " + attempts + ".");
                
                } 
            } while ((aqObject.GetPropertyValue(theElement, prop) != propValue) || (attemptCounter > attempts)); //attempts was 200 // || attempts > 200
        }
    }
    Now, that SAID... this is still redundant code if you're looking to wait for a property to come back with a certain value. In your keyword test, after checking to see if the object exists (see my while loop in the above code), you can add an OnScreen Action for the object and, as the action, use WaitProperty method (https://support.smartbear.com/testcomplete/docs/reference/test-objects/members/common-for-all/waitproperty-method.html). Basically, you can tell the test case to wait until an object's property has a particular value OR the wait method times out. To see if it worked, just use the "Last Result" value in an if then statement to check to see if it returns true... if it's true, the property is the desired value. If false, the timeout happened.
    • SarahEdwards's avatar
      SarahEdwards
      Contributor

      Thank you! That makes much more sense. Here's what I wound up with:

      function waitToRunExists(parent, childObj, attempts)
      {
      var theElement;
      //Prime the attempts variable
      if( typeof attempts == "undefined" || attempts == null )
      {
      attempts = 1;
      }
      childObj = aqConvert.VarToStr(childObj);
      var theElement = parent.WaitNamedChild(childObj, 1 );
      // Wait for the child object to exist or bail after 500 attempts/loops
      do{
      theElement = parent.WaitNamedChild(childObj, 1 );
      attempts++;
      if (attempts > 500)
      {
      Log.Error("Too many attempts. attempts = " + attempts + ".");
      }
      }
      while ( !theElement.Exists || attempts > 500);

      }

       

      This runs much quicker than the keyword test's equivalent method. It should also eliminate the need for arbitrary delays in our tests.