Forum Discussion

madnut's avatar
madnut
Contributor
15 years ago

Unable to get element in Firefox using getElementsByTagName

Hi, I've got the issues with accessing element from the array returned by getElementsByTagName. The following sample code works fine in IE but it fails with exception in Firefox:


var arrayOfElements = anyElement.getElementsByTagName(tag);

for (var i = 0; i < arrayOfElements.length; i++)

{

Log.Message(arrayOfElements.getAttribute('id')); // or any other attribute

}


Could someone explain what's wrong with it?


And some additional questions:


1. How can I convert arrayOfElements object to TC object to be able use TC methods, like Exists, Click etc.?


2. Is it possible to get child objects for specified element on page? For example, I need to get all links in specified table, not on the whole page. I've tried to use FindXXX methods but they returns nothing if called as element's method.


7 Replies

  • Hi Oleksiy,




    The getElementsByTagName method returns a native enumerator of native objects which cannot be converted to TestComplete wrappers. In case of Firefox, the native objects do not contain the getAttribute method. 




    As for your additional questions, I recommend that you try using the FindAllChildren method (for additional information, see the "FindAllChildren Method" help topic). Note that the default value of the method's Depth parameter is 1, and this means that the method only examines children of the current object by default (that is why, the method returned nothing in your case, I suppose). If you need to examine 2 or more levels of the objects hierarchy, you need to specify the search depth explicitly. Here is an example script that clicks one of the links contained in the specified object:




    [JScript]




    function testFF() {


      var found = obj.FindAllChildren("tagName", "A", 100); <=== Pay attention to the method's third parameter

      found = VBArray(found).toArray();

      found[0].Click();

    }




    Let me know if you have any additional questions.

  • Thanks for reply, Alex!


    Using of FindXXX methods for dynamic pages (e.g. AJAX) actually doesn't really help in Firefox - sometimes it can't find anything even if page is already loaded. Please, look the code below for details:


    [JS]


    var curPage, tcObj, nativeObj;

    var oFound = false;

    while (!oFound) // simple condition just for example

    {

    curPage = Sys.Process("firefox").WaitPage("*", 1000);


       tcObj = curPage.FindChild("idStr", "txtUserName", 1000);          // this method sometimes return stub non existing object

    nativeObj = curPage.document.getElementById("txtUserName"); // this one is always return correct object


       if (tcObj.Exists)

    {

    oFound = true; // got it

    }

    else

    {

    aqUtils.Delay(500, "wait a bit for page loading");

    }

    }


    In some cases FindChild() can't recognize new controls appeared on page even if it is called in a loop as in example. It looks like TC caches page's content and doesn't refresh it if actual page is updated. Therefore I've tried to use native getElement* methods but, as you said before, there are no way to convert native object into TC wrapper. So, the issue is still open and I have no ideas how to resolve it. Are there any methods to force TC to refresh page object to be able to find newly added elements on page?


    And one more note, related to iterating through the elements array (my first post): I just found out that accessing to element in FF differ from that one in IE. Please, see below:



    var arrayOfElements = anyElement.getElementsByTagName(tag);

    for (var i = 0; i < arrayOfElements.length; i++)

    {

    Log.Message(arrayOfElements.getAttribute('id')); // IE variant

    Log.Message(arrayOfElements.item(i).getAttribute('id')); // FF variant

    }


    p.s. I'm using TC 7.51, IE 7 and FF 3.5.7


    upd: TC still can't find element even if I manually refresh page in FF


  • Hi Oleksiy,




    Try inserting a call to the Refresh method in your code before the call to the FindChild method. Also, try using "NativeWebObject.id" (for Internet Explorer) or "NativeFirefoxObject.id" (for Firefox) instead of "idStr" as the value of the first argument of the FindChild method. If this does not help, please provide us with a script that demonstrates the problem with a public site.




    As for your note, native Firefox objects contain the getAttribute method, but as the enumerator returned by the getElementsByTagName method has a different structure in Firefox and Internet Explorer, it is necessary to access the enumerator's elements using the different approaches you've mentioned.

  • Thank you David,


    I've tried Refresh(), but it helps only time to time. Then I decided to add one more Wait before Refresh and it looks like it helps. So, the final code now is the following:


    var curPage = Sys.Process("firefox").WaitPage("*", 5000);

    curPage.Wait();

    curPage.Refresh();



    obj = curPage.FindChild("NativeFirefoxObject.id", "txtUserName", 1000);


    So, it seems that issue is resolved for me, but I have one small question: Are there any differences between WaitPage() and page.Wait() methods behavior and implementation?


  • Hi Oleksiy,



    The difference is that the WaitPage method delays the test execution until a Page object with the specified address appears, while the Wait method delays the test execution until a page's contents are completely loaded.

  • Thanks Jared,


    but according to TC Help


    "The WaitPage method checks the readyState property of
    the loaded HTML document and returns when this property reports that the page
    loading is completed"


    So, if it's true than WaitPage() should be the same as page.Wait(), isn't it?

    I'm just wondering if I should separately check for readyState value to be sure that page is completely loaded.


  • Hi Oleksiy,


    The ways of these methods' functioning are different. The corresponding help topics contain wrong information; the WaitPage method does not check the readyState property. We are planning to modify the topics in the next version of TestComplete.


    Anyway, you don't have to check for the value of the readyState property individually, you need to use the Page.Wait method which returns when the property reports that the target page has been loaded completely.