Forum Discussion

nish_b's avatar
nish_b
Contributor
4 years ago
Solved

setInterval is not defined: Suggestion for best wait method during page loads

Hi,

 

ISSUE:  ReferenceError: setInterval is not defined

 

DESCRIPTION: I am trying to write a pure JavaScript function for the webpage to fully load before proceeding with my test script. I am using setInterval() to poll until the DOM Load event is fired

 

BACKGROUND: I have already used page.Wait(); for waiting during page load. But still the webelements are not found after the wait. I also have tried a polling function to check whether the element exists.

 

CODE SNIPPETS:

1) Pure JavaScript function for DOM:

      let webpage = Sys.Browser().Page(this.openBrowserWindowURL()).contentDocument; //Get current webpage document

waitForDOMToLoadFullyLoad(webpage){
//The basic check 
if(webpage.readyState === 'complete') {
  // Polling further until load event fires - which means all icons are fully loaded
  let pageisloaded=0;
  let interval = setInterval(function() {
     window.addEventListener('load', (event) => {
     pageisloaded=1;
    })
   if(pageisloaded) {
      Log.Message("DOM Load event is completed!");
      clearInterval(interval);
    }
  }, 100);
}

    }

 

2) POLLING FUNCTION:

isElementPresent(webElement,timeout,pollingTime,frequency) {
let flag=false;
aqUtils.Delay(timeout);
for(let i=0;i<frequency;i++){
  if(webElement.Exists){
    Log.Message("Element exists");
    flag=true;
    break;
  }
 else {
    Log.Message("Waiting for element at iteration: "+i);
    webElement.WaitItem(index,pollingTime);
    }
  }
 return flag;

}


QUESTIONS: 

1. Please suggest which is better option? Code Snippet 1 or 2? Code Snippet 2 is not giving satisfying results. It works sometimes, sometimes it doesn't work.

2. Why am I getting error: setInterval is not defined. Is it not supported in TestComplete?

  • Hi,

     

    function for the webpage to fully load

    Definition of the fully loaded page depends on how the given tested page is implemented.

    The generic process is like this:

    -- Browser sends request for the page to the server and waits for the response;

    -- When the response is fully received, browser starts to render it. This is the moment that page.Wait waits for;

    -- Page may contain script functions that modify DOM structure. These might be jQuery, Angular, regular script function or something else. jQuery and Angular provide internal ways to determine if they finished their current activities or not. This can be used to delay test execution until jQuery and/or Angular finish their current activities. Regular script functions are not predictable. They can provide some heavy processing that takes a lot of time without any indication whether or not the processing has completed;

    -- Finally, page may contain some Ajax calls that are executed asynchronously. Depending on their nature, these calls may get data and change page DOM structure in a way that you are interested in. In this case your code must postpone until the required web element appears on the page. Otherwise, such calls may be ignored and test code may proceed.

     

    So, your approach to wait for the page load may depend on the page design and implementation.

     

    As for the setInterval() / clearInterval() functions - what these functions are provided by? They are not built-in TestComplete functions. If JavaScript provides these functions, then they should be accessible from JavaScript-based test project. If this is something provided by DOM/jQuery/etc. then these functions must be called from within page context. Check https://support.smartbear.com/articles/testcomplete/embedding-scripts-into-web-pages/ and "Run JavaScript on Web Pages" TestComplete's help topic for more details on how to call script function from the page context.

     

    Your polling function provided in code snippet #2:

    It will not work as you probably expect it to function. The reason is that this function checks if the object provided as a parameter exists. If the object does not exist, then the code waits in a loop until object's .Exists property becomes True. This will never happen. If the object did not exist when it was obtained, then this means that TestComplete's stub object was returned. And even if/when the sought for object appears, this will in no way be reflected on the stub object. The approach in this case must be not to wait for .Exists to become true, but search in a loop for the object (via .FindXXX() ) and check its .Exists property.

     

  • Hi Alex,

     

    I tried your suggestion for 2. i modified the function to loop and keep searching for webelement and then check Exists property. But at 2nd iteration (when i =1)  , when it tries to find the webelement again, it is throwing "Unspecified Error". Could you help here?

     

    Below is the rewritten function:

     

    isElementPresent(webpage,xpath,timeout,pollingTime,frequency) {
    let flag=false;
    let webObj;
    Log.Message("Timeout starting");
    aqUtils.Delay(timeout);
    Log.Message("Timeout stopped");
    for(let i=0;i<frequency;i++){
    webObj=webpage.FindChildByXPath(xpath);
    Log.Message("webobj is: "+webObj);
    if(webObj!==null){
    Log.Message("webObj is not null, checking its existence");
    if(webObj.Exists===true){
    Log.Message("Element exists at iteration: "+i);
    flag=true;
    break;
    }
    else
    {
    Log.Message("Waiting for element at iteration: "+i);
    aqUtils.Delay(pollingTime);
    }
    }
    else {
    Log.Message("WebObj is null/Undefined. Waiting for element at iteration: "+i);
    aqUtils.Delay(pollingTime);
    }
    }
    return flag;
    }

  • Hi,

     

    .FindChildByXPath() should work. I expect the problem is within the getOpenBrowserPage() method. Can you provide it?

    What happens between two subsequent calls to getOpenBrowserPage()? If the page or its content changes somehow then test code must wait at least until the page is reloaded (via <page>.Wait() method) and only then proceed.

     

11 Replies

  • AlexKaras's avatar
    AlexKaras
    Champion Level 3

    Hi,

     

    function for the webpage to fully load

    Definition of the fully loaded page depends on how the given tested page is implemented.

    The generic process is like this:

    -- Browser sends request for the page to the server and waits for the response;

    -- When the response is fully received, browser starts to render it. This is the moment that page.Wait waits for;

    -- Page may contain script functions that modify DOM structure. These might be jQuery, Angular, regular script function or something else. jQuery and Angular provide internal ways to determine if they finished their current activities or not. This can be used to delay test execution until jQuery and/or Angular finish their current activities. Regular script functions are not predictable. They can provide some heavy processing that takes a lot of time without any indication whether or not the processing has completed;

    -- Finally, page may contain some Ajax calls that are executed asynchronously. Depending on their nature, these calls may get data and change page DOM structure in a way that you are interested in. In this case your code must postpone until the required web element appears on the page. Otherwise, such calls may be ignored and test code may proceed.

     

    So, your approach to wait for the page load may depend on the page design and implementation.

     

    As for the setInterval() / clearInterval() functions - what these functions are provided by? They are not built-in TestComplete functions. If JavaScript provides these functions, then they should be accessible from JavaScript-based test project. If this is something provided by DOM/jQuery/etc. then these functions must be called from within page context. Check https://support.smartbear.com/articles/testcomplete/embedding-scripts-into-web-pages/ and "Run JavaScript on Web Pages" TestComplete's help topic for more details on how to call script function from the page context.

     

    Your polling function provided in code snippet #2:

    It will not work as you probably expect it to function. The reason is that this function checks if the object provided as a parameter exists. If the object does not exist, then the code waits in a loop until object's .Exists property becomes True. This will never happen. If the object did not exist when it was obtained, then this means that TestComplete's stub object was returned. And even if/when the sought for object appears, this will in no way be reflected on the stub object. The approach in this case must be not to wait for .Exists to become true, but search in a loop for the object (via .FindXXX() ) and check its .Exists property.

     

    • nish_b's avatar
      nish_b
      Contributor

      Hi Alex,

       

      Thank you for your response! I will work on the suggestions provided and let you know the update! 🙂 

      • nish_b's avatar
        nish_b
        Contributor

        Hi Alex,

         

        I tried your suggestion for 2. i modified the function to loop and keep searching for webelement and then check Exists property. But at 2nd iteration (when i =1)  , when it tries to find the webelement again, it is throwing "Unspecified Error". Could you help here?

         

        Below is the rewritten function:

         

        isElementPresent(webpage,xpath,timeout,pollingTime,frequency) {
        let flag=false;
        let webObj;
        Log.Message("Timeout starting");
        aqUtils.Delay(timeout);
        Log.Message("Timeout stopped");
        for(let i=0;i<frequency;i++){
        webObj=webpage.FindChildByXPath(xpath);
        Log.Message("webobj is: "+webObj);
        if(webObj!==null){
        Log.Message("webObj is not null, checking its existence");
        if(webObj.Exists===true){
        Log.Message("Element exists at iteration: "+i);
        flag=true;
        break;
        }
        else
        {
        Log.Message("Waiting for element at iteration: "+i);
        aqUtils.Delay(pollingTime);
        }
        }
        else {
        Log.Message("WebObj is null/Undefined. Waiting for element at iteration: "+i);
        aqUtils.Delay(pollingTime);
        }
        }
        return flag;
        }