Forum Discussion

marinb's avatar
marinb
Contributor
9 years ago

Object property does not exist right after it passes an exist check?

Given the following piece of code in our script:

 

Sys.Refresh();
if (aqObject.IsSupported(Sys.Desktop.ActiveWindow(), "MappedName")) { if (Sys.Desktop.ActiveWindow().MappedName != null) //FAILS HERE { <...snip...>

How could it ever be possible that it occasionally fails on the marked //FAILES HERE line with this error:

You are trying to call the "MappedName" method or property of an object that does not exist.

 

It does a full system refresh, then it checks if MappedName property exist, then if it does so, it goes to the next line and suddenly it doesn't exist anymore?

 

 

  • Well the only place I can think the issue would be is when calling the ActiveWindow() method. You aren't technically checking the same object since you are grabbing a new object with each call to the ActiveWindow() method. That method returns either a Window object or an empty stub object if no top-level window is found. In your code it must return a Window object in the first check then during the second check for whatever reason something changed and TestComplete doesn't think there's any top-level windows so it returns an empty stub object which doesn't have the MappedName property.

     

    I couldn't reproduce the issue myself, but my suggestion is that you return the results for the ActiveWindow() method into a variable, then reference that same variable. So I'd change your code to this:

     

    Sys.Refresh();
    activeWindow = Sys.Desktop.ActiveWindow()
    if (aqObject.IsSupported(activeWindow, "MappedName"))
    {
        if (activeWindow.MappedName != '')  //FAILS HERE
        {
           <...snip...> 

    Which BTW, the MappedName property is never null. If you don't have a MappedName for an object it returns an empty string which is different than null.

     

  • Well the only place I can think the issue would be is when calling the ActiveWindow() method. You aren't technically checking the same object since you are grabbing a new object with each call to the ActiveWindow() method. That method returns either a Window object or an empty stub object if no top-level window is found. In your code it must return a Window object in the first check then during the second check for whatever reason something changed and TestComplete doesn't think there's any top-level windows so it returns an empty stub object which doesn't have the MappedName property.

     

    I couldn't reproduce the issue myself, but my suggestion is that you return the results for the ActiveWindow() method into a variable, then reference that same variable. So I'd change your code to this:

     

    Sys.Refresh();
    activeWindow = Sys.Desktop.ActiveWindow()
    if (aqObject.IsSupported(activeWindow, "MappedName"))
    {
        if (activeWindow.MappedName != '')  //FAILS HERE
        {
           <...snip...> 

    Which BTW, the MappedName property is never null. If you don't have a MappedName for an object it returns an empty string which is different than null.

     

    • marinb's avatar
      marinb
      Contributor

      Thanks for the response! I will try this out!

       

      PS: I adjusted the code a bit for this topic. The real code checks on empty stringvalue as well, since I made a little IsEmpty function checking on all 'empty' values like null or "" for readability: if (IsEmpty(activewindow))

  • Manfred_F's avatar
    Manfred_F
    Regular Contributor

    It can always occur that a given, valid reference to an application object (control..) is invalidated at the next line of test Automation script code.

     

    Our scripting works asynchronously.

    You iterating an object's children? Well. How do You know that during Iteration their number has not changed? Are You sure that at least the object still exists afterwards?

     

    Some of our Automation script code serves for synchronization. Especially therein, be prepared to react on any Kind of Errors.

    • marinb's avatar
      marinb
      Contributor

      True, our application can also be quite unresponsive. I try to make it as robust as possible, but you still get dirty loops like this in order to prevent hiccups... if x.exists, then if  x really exists, then if y exists, but really, x should exist! etc etc ;-)

       

           for (var i = 0; i < iMaxWait; i++)
           {
              if (oMapping.Exists)
              {
                  if (aqObject.IsSupported(oMapping, "VisibleOnScreen"))
                  {
                      if (oMapping.Exists)
                      {
                          if (oMapping.VisibleOnScreen)
                          {
                              if (oMapping.Enabled || bDoNotCheckOnEnabled)
                              {
                                  bFound = true;
                                  break;
                              }
                          }
                      }
                  }
              }
              <snip>

       

      If I remove the second exists check, it fails occasionally. With that extra check, it does not.

      If I remove the VisibleOnScreen supported action, it fails occasionally, even while every object always should have it.

       

      • Manfred_F's avatar
        Manfred_F
        Regular Contributor

        Yes, You Need all kinds of caution.

         

        I use the following pattern, see attachment:

         

        • disable error handling
        • try several times
          • execute the steps
          • on success leave Loop,
          • on error
            • reset error
            • wait a Moment
            • stay in Loop
        • enable error handling

         

        This allows me to use rather straight-Forward code..