Forum Discussion

mkiewicz's avatar
mkiewicz
Occasional Contributor
8 years ago

More Efficient Searches

Again, I'm new to TestComplete, so apologies in advance if this question is redundant.


We are developing in Angular 2.0 with a lot of dynamic content. We are trying to search across a set of results returned from a search that may encompass many pages of results (think ~50 pages of results with 7 results per page). Currently every time we have to search a new page of results we have load another page object and this takes about 3-4s per page load. We'd like to make this a little more efficient. I'm inclined to think this is because we're using a page object to get the result set displayed as follows and every time we are getting an object, the complete DOM is being polled:

evalObject = page.Page.FindChildByXPath(xpathToEval);

With evalObject being the one item in the result set displayed and xpathToEval being the xpath to that object

What I'd like to do is maybe take the container holding all of the result set item and iterate through them as follows (pseudo code follows)

containerObject = page.Page.FindChildByXPath(xpathToContainer)

evalObjects = Collection Of results (xpathToCommonAttribute) from container Object

{
    for(i = 0; i < evalObject.length; i++)

    {

        //do comparison on expected text and text of evalObject[i]

    }

    if (item not found)

   {

       //click the next page and reload the container

   }

}

(end pseudo code)

I don't see where this is possible because it isn't possible to evaluate the children of anything other than a page object. Is there a better way to do this and, in this case, evaluatre the results from the container object?

Thanks!!

8 Replies

  • tristaanogre's avatar
    tristaanogre
    Esteemed Contributor

    What about breaking it into two functions?  Something like the following pseudocode?  Untested, but this is what's in my head

     

     

     

    function searchForText(page, textToSearch) {
        var evalObject = page.Page.FindChildByXPath(xpathToContainer)
        var success = false;
        for (var i = 0; i < evalObject.length; i++) {
            if (found comparison) success = true;
        }
        return success;
    }
    
    function checkAllPages() {
        //load page
        while (!searchForText(page, textToFind)) {
             //Click on new page
        }
    
    }

     

    • mkiewicz's avatar
      mkiewicz
      Occasional Contributor

      I thought about that but it doesn't lessen the number of times a page gets loaded. I came from a Selenium shop and typically using Selenium you would grab the object you wanted to search across (e.g. a table) and just use that....


      do
      {
          IWebElement schTable = driver.FindElement(By.Id("tableId"));

       

          ReadOnlyCollection<IWebElement > searchedItemsschTable.FindElements(By.Id("searchItem_Id"));

       

          for each (IWebElement  item in searchedItems)
          {

                 //search for what you are looking for and return result if found

          }

       

          if (item found) 

          {

             //set item fund and leave loop

          }

          else

          {

              //click next page of results

          }
      while(item not found || EOF last page of results)

       

      This way I'm working off of one grab of the table and traversing the table. The way I have it set up in TestComplete is as follows

      resultCount = page.Page.EvaluateXPath(<M'Results Item Tag Identifier'>).length

      //scroll through this page of resu;lts
      for (i=0; i < resultCount; i++)
      {
          idx = i + 1;
          xpathToEval = FunctionalClasses.getOffsetXPath(schTextColumn, i + 1);
          evalObject = page.Page.FindChildByXPath(xpathToEval);
          thsText = evalObject.contentText;

          //search for what you are looking for and return result if found. If not go to next page get new object and continue

      }

      This is requiring the whole page DOM to be queried by the xpath expression every time through the loop because EvaluateXPath and FindChildByXpath can only be used against page objects. It's taking 3 - 5 seconds to traverse seven results / page. when there are a lot of pages of result to scroll through this can become tedious

      It could also be that I'm not doing this right. If there's a better way, I'd love to hear about it

      Thanks!!!

      • tristaanogre's avatar
        tristaanogre
        Esteemed Contributor

        OK, I guess I'm not understanding... are there multiple pages?  Or are you on a single page and looking for information within a table?  

        If there are multiple pages, I'm not sure I understand how Selenium can find information on a page that is not currently being rendered by the browser.  You still need to navigate to the next page in order to check what's on screen, right?  Of course, I'm not well versed in Selenium so there could be things that it's doing that I don't know about.

         

        TestComplete does it's testing by interacting with objects that are present within the application at the time of interaction.  So, if you have a page on screen with particular content, TestComplete can interact with anything on that page at any time so long as the page itself is not changing.  Even if components within the page change, TestComplete sees it as the same page because it is the same URL.  Now, does the page reload after I click on something?  Potentially, it does, depending upon how the page is coded.  But that isn't always the case. In any case, if there is a table on a page with content and I'm checking for that content, I don't need to refresh the page each time, all I need to do is traverse the table.

        Now... it SEEMS that your problem is finding the table... You're using XPath which, OK, works... but is it strictly necessary?

        You can map the table on the page using NameMapping and Aliases.  Say I have a table on a page.  It has a property of RowCount. I want to search the table for something and, if I can't find it, go to the next page.  Here's what I'd do.  Pseudocode, mind you.


        function findMyText(textToFind) {
           var page, table, tableContent;
           page = Sys.Browser().Page('*'); //returns whatever page you happen to be on
           while (!textFound) {
               table = page.FindChild(['ObjectType','idStr'],['Table', 'myTableIdentifier'], 30); // This is a bit rough but the general idea is that you want to find the specific table on the current page based upon a set of known properties and values
               tableContent = table.FindChild('contentText', textToFind, 3);
               if (tableContent.Exists) {
                  textFound = true;
                  return tableContent;
                  }
           }   
        return null;
        }

        You're not traversing the whole DOM this way, you're simply finding the table in the hierarchy of the object tree and using it. You'd call this function from someplace else then where, if the result returns null, go to the next page.  If it returns something not null, you have your object.