Forum Discussion

pramod_tr_rao's avatar
pramod_tr_rao
Occasional Contributor
11 years ago
Solved

Test Complete does not wait until the entire Page/Frame is loaded even though we wait for the ready state to be complete

Hi,

   We have an issue where Test Complete performs operation on an object even before the entire Page/Frame is loaded. We have put in a function that checks and waits until the readystate of the page/frame is complete. After this step we click on the object, but most of the times testcomplete does not end up clicking on the item as the page/frame is not completely loaded.

 

Due to this all our scripts are failing due to Sync issues. We do not want to add in a Hard Coded Wait, so please let me know if you have any suggestions on how we can implement a solution to this issue.We also have a while loop that waits for the object until it exists or a max delay timeout is reached. so we are waiting for the object to be VisibleOnScreen as well,but still we are facing this sync issue. PLEASE HELP..KINDA URGENT...

Thanks,

Pramod

 

Please find the code for the WaitTimeOut function below.

 

Function bWaitTimeOut()

 

  On Error Resume Next

 

  Dim intStopTime

  Dim arrFrames,objFrame

  Dim intCounter, bWaitStatus

 

  bWaitTimeOut = True

  bWaitStatus = False

 

  intStopTime = GetTickCount() + gdblMaxDelayTime

  Do While GetTickCount() < intStopTime

 

      arrFrames = uobjPage.FindAllChildren("ObjectType", "Frame", 5, True)

      If UBound(arrFrames) >= 0 Then

       bWaitStatus = False

        For intCounter = 0 To UBound(arrFrames)

          Set objFrame = arrFrames(intCounter)

          If objFrame.Exists And objFrame.contentDocument.readyState <> "complete"  Then

            bWaitStatus = True

            Exit For

          End If

        Next

        aqUtils.Delay(100)

      Else

         bWaitStatus = False

         If uobjPage.Exists And uobjPage.readyState <> "complete" Then

         'If Sys.Process(gstrBrowserType).readyState <> "complete" Then

           bWaitStatus = True

         End If

         aqUtils.Delay(100)

      End If

      If Not bWaitStatus Then

        Exit Do

      End If

  Loop

 

  'Wait for the page to be completely loaded

  uobjPage.Wait

 

  If Err.Number <> 0 Then bWaitTimeOut = False

 

End Function

 

  • Hi Pramod,



    Does your tested web page contain script(s) code that modify the content of the page?

    The case is that browsers set the page ready flag (that TestComplete looks for) when the page is obtained from the server. Then, the browser executes scripts on the page. But this happens with the ready flag already set. Depending on the scripts, browser and local system load, scripts execution can take significant time.

    According to my experience, the best way is to wait until the page is loaded (page.Wait). Then, it is really good if you can find some object that, if found on the page, indicates that the browser completed scripts processing and the page is ready to interact with the end-user. Wait for this object to exists.

    Then you may proceed with the test using your current approach: not to try to perform some action against some object on the page, but first check if this object exists and wait (using timeout) until the object appears if it was not found. And only after the object was found, proceed with the actions against it.



    The described approach works pretty well for me for several highly scripted web applications.



    Hope this will help.

5 Replies

  • AlexKaras's avatar
    AlexKaras
    Champion Level 3
    Hi Pramod,



    Does your tested web page contain script(s) code that modify the content of the page?

    The case is that browsers set the page ready flag (that TestComplete looks for) when the page is obtained from the server. Then, the browser executes scripts on the page. But this happens with the ready flag already set. Depending on the scripts, browser and local system load, scripts execution can take significant time.

    According to my experience, the best way is to wait until the page is loaded (page.Wait). Then, it is really good if you can find some object that, if found on the page, indicates that the browser completed scripts processing and the page is ready to interact with the end-user. Wait for this object to exists.

    Then you may proceed with the test using your current approach: not to try to perform some action against some object on the page, but first check if this object exists and wait (using timeout) until the object appears if it was not found. And only after the object was found, proceed with the actions against it.



    The described approach works pretty well for me for several highly scripted web applications.



    Hope this will help.
  • pramod_tr_rao's avatar
    pramod_tr_rao
    Occasional Contributor


    Hi Alex,

            Thanks a lot for the reply, I have tried using the page.wait method as well, but in vain.

    The application uses AJAX,and at most times opens up modal windows, so actually you are still on the same page.



    Also, We call this function bWaitTimeOut as in the post, whenever we a navigating across pages, and after that we create the object using the NativeWebObject.Find method, in which we check whether the object exists, enabled, VisibleOnScreen, and then perform the operation on the object.



    Basically, we are trying to avoid Hard Coded wait, but instead use dynamic wait and wait only until required.



    Are there any other alternatives to this? Basically, what you have mentioned in your reply should work, but it is not working as we have tried it earlier :(, so any other ideas/suggestion on how we can acheive this dynamic wait for objects are welcome. :)



    Thanks,

    Pramod


  • AlexKaras's avatar
    AlexKaras
    Champion Level 3
    Hi Pramod,



    I did not hear about any other alternative than waiting for the target object until it appears within the reasonable period of time.

    I never used NativeWebObject.Find(), but prefer .Find()/.FindChild()/.FindChildByXPath().

    I am also not happy with this approach, but this is the price that you are required to pay if you use dynamic 'self-modifying' web pages. As opposed to the old good desktop applications that have all resources available when started, 'self-modifying' web pages constantly download something from the web and you never know when this or that IU element is available. So waiting for the object is the only approach I can imagine so far.

    Again, it is very good to have an object (either 'global' one, of page/window-specific) that, with a high probability, is created last. Wait until this object is created, then look for the target object you need and only then work with this target object. The reason for this suggestion is that it is possible that your target tested object may already exist on the page and even be visible, but the browser might still be busy with script execution to create other objects and/or populate your tested object and other objects with data. This may result in that if you don't wait until the browser is ready to interact with the end-user, your actions against the tested object (clicks, etc.) might be 'lost' or cleared by the browser or object's code and this will lead to the test failure.

    (Again, consider the fact that TestComplete usually imitates end-user actions. And this is exactly corresponds to how human acts: wait for the page to be rendered on the screen, than wait for the UI element he/she needs, then try to use this UI element. Wait until the browser seems to be ready to interact with you if it doesn't respond and repeat the attempt to use the UI element.)

  • AlexKaras's avatar
    AlexKaras
    Champion Level 3
    BTW, one comment about your bWaitTimeOut() function: excuse me for being impolite, but I consider usage of the On Error Resume Next statement at the beginning of the function to be a very bad programming practice.

    The case is that Err.Number is set/reset after execution of *every* line of code. This means (considering your case) that you are checking if the uobjPage.Wait statement was executed without runtime error. You can say absolutely nothing about whether or not run-time errors occured for *all* previous lines. Instead, they all are *assumed* to succeed, while this may not correspond to reality. As a result, it is possible that there will be an error in your code, but this error will be suppressed and you will think that your code succeeded. But when you try to use the results of your code outside of the On Error Resume Next scope, this another code will fail, making you think that the problem is there, while actually the root of the problem was within the code where the error was suppressed.

    While I think that I understand why you are using On Error Resume Next statement, note that it does not correspond to the On Error GoTo <label> stetement from VB or try/catch blocks from other languages. Actually, VBScript does not have a means to handle runtime errors and thus is the worst choice for the test projects where runtime errors are highly probable or even expected (for example - for the Web Services test projects).

    In case of VBScript, if you expect that some line of code might fail, then you must put the On Error Resume Next statement *right before* this line and *immediately after* the line save the value of Err.Number. Then you may either proceed or analyse the saved value. Obviously, this clutters the code and makes it difficult to read, but this is the only correct approach to handle possible runtime errors in VBScript.
  • Hi - not sure if this might help - it feels similar to issues I have seen - maybe a call to Aliases.RefreshMappingInfo() is required before checking for the existence or visibility of some of the objects?