getting "FindAll is not a function" error

Originally posted by pkudrys on July 04, 2025

Hi folks,

Any idea why I’m getting error “FindAll is not a function”? Below code successfully returns parentElement object, But when I try to call FindAll with the obtained object, it fails with the above error.

The interesting point is, that if I call FindAll directly on inputElement object, it works OK. There seems to be a problem only with the parentElement-based object. Do I need to somehow convert the localParentbefore calling FindAll?

...
else if (inputElement.className.includes('mat-mdc-chip-input'))
{
  var localParent = inputElement.parentElement;
  var getAllChips = localParent.FindAll("tagName","mat-chip-row",10);
  for (let j = 0; j<=getAllChips.length - 1; j++)
  {
    getAllChips[j].FindElement("//mat-chip-row//*[contains(@class,'mat-mdc-chip-remove')]/parent::span").Click();
   }
}
...

Originally posted by rraghvani on July 04, 2025

You have defined localParent to be an object of inputElement.parentElement. You can access the property values of localParent (as shown in the watch list) e.g.

localParent.clientHeight
localParent.defaultChecked
localParent.disabled
localParent.innerHTML

but you have not inherited any of the methods. Therefore, FindAll will not work because it’s a JavaScript DOM and not TestComplete’s Test Object Model

What does inputElement and parentElement reference to in the Object Browser? And how have you defined them?

Originally posted by pkudrys on July 07, 2025

Hi, thank you for the reply. inputElement is filled with the alias object and parentElement is a property of the inputElement.

I’ve created a simple test project showing the issue: FindAll.zip

As shown on the previous image, localParent appears to be the same object (the structure of the object), like inputElement, so I’m a bit surprised FindAll does not work with it. Any idea how to access the object properly?

Originally posted by rraghvani on July 07, 2025

FYI, I’m looking into this.

Originally posted by rraghvani on July 07, 2025

Here’s the issue - the same code, just commented out line 3

function GetAllButtonsFromAlias(aliasItem)
{
    //var parentElement = aliasItem.parentElement;
    var buttons = aliasItem.FindAll("ObjectType", "Button", 100);
    buttonsArray = buttons.toArray();
    Log.Message(`Number of buttons on page, using NameMapping ${buttonsArray.length}`);
}

function test1()
{
    //GetAllButtonsFromAlias(Aliases.browser.pageCssButtons.buttons.Parent);
    Log.Message(Aliases.browser.pageCssButtons.buttons.parentElement.nodeName);
}

When calling parentElement (line 12) it is retrieving the buttons’ parent element, which is

(highlighted in yellow)

Aliases.browser.pageCssButtons.buttons highlights “Default Button” for me

The element

does not appear in the Object Browser

As mentioned in the documentation,

Use FindAll to search for all objects that have the specified values of the specified properties. The search is performed in the object hierarchy displayed in the Object Browser panel starting from the testedObj object and continuing down the hierarchy to the specified depth.

Hence, FindAll does not work on

element.

If I uncomment line 11 and comment line 12, and use Parent (highlighted in yellow)instead of parentElement, then 61 buttons are returned (highlighted in green)

To make your function return the appropriate number of items, don’t use line 3, but do pass parameters like “Aliases.browser.pageCssButtons.buttons” or “Aliases.browser.pageCssButtons.buttons.Parent”.

Hopefully, this should also resolve your issue with your other post relating to “FindAll returns only one (first) element”

Originally posted by pkudrys on July 07, 2025

Thank you for your investigation! I really missed the part about Object Browser requirement. Unfortunately, the solution you are suggesting is not what I can use. The above sample is just a simplified example, not the real-world problem.

If you check my original code in the first post, I need to get the list of mat-chip-row tags, which are located on the same level as the inputElement (alias item). And because watch list shows directly what I want under the node parentElement property (of the obtained alias element), I hoped to use it in my code.

Is there another way to get the list of items according of my needs? Using alias element, pointing to the input, instead of direct parent element, is apparently not an option?

In other words, is there a way to get a direct HTML parent (not mapped parent) of an element, which is referenced by the Alias object?

Originally posted by rraghvani on July 07, 2025

I had to do some research, since you are trying to access non native objects, i.e. objects that don’t appear in the Object Browser.

I’ve written a small program, then spent ages trying to figure out why parentElement.children was only returning one object, which just had a property value of length!

As it’s a collection of child elements, I need to call the method item i.e. parentElement.children.item(i) which then returns each of the child elements. This prints out the following

Which matches the HTML code

Are you able to do something similar, so that it retrieves mat-chip-row’s? You might have to use a different property other than tagName

Originally posted by pkudrys on July 08, 2025

Thanks for the investigation! Yes, this approach kind of works. I can retrieve the mat-chip-rows this way. The problem is, I can’t do anything with them :slight_smile: They can’t be clicked or used as a reference for any of the Find functions (to find certain element in them). Getting the same “xxx is not a function” error.

In a meantime, I tried slightly different approach using FindElementByXPath using aliasItem as a reference. But to my great surprise, even this approach does not work. It simply does not find the aliasItem’s ancestor element, even though the same xpath works fine in chrome dev. mode.

var findParent = aliasItem.FindElementByXPath("./ancestor::div[contains(@class,'w3-row')]")

Originally posted by rraghvani on July 08, 2025

JavaScript in TestComplete is powered by V8 engine v5.8, and Chrome DevTools will be something like V8 v13.7.152.17.

Since you are working with non standard elements, you may have to implement your own “Find”, “Click” etc methods. But before doing that, read through Using Custom Attributes of Web Objects? Refer to this Support for Web Controls

Originally posted by rraghvani on July 08, 2025

The screenshot that your have provided,

What do the items look like in the Object Browser? What item does it reference in your web app? And what item(s) are you trying to find and click on, on the web app?

Also, what technology does you web application use? Is there a similar web app that I can use to test?

Originally posted by pkudrys on July 08, 2025

It’s an Angular-based app. I just found a public sample page, where this can be tested:
https://material.angular.dev/components/chips/overview#autocomplete

I’ve updated the test project with this particular page and elements.

FindAll_test.zip

Basically, I need to find all mat-chip-rows and click button for each row. Of course, I know there is an easy way to achieve this by using name mapping and simple loop. But I can’t use it that way. This project is just a simplified sample. In original project, I’m collecting all form inputs (using the complicated xpath) and do various things for each input. Basically collecting IDs/values, storing them in JSON, eventually loading IDs/values from JSON and filling individual form inputs. Therefore, I’m working on a generic method, which should work with various forms, containing variable number and types of elements.

Originally posted by rraghvani on July 08, 2025

Not sure if this is helpful, but here’s a few coding examples that highlights the button. Example 4 highlights and deletes. Name mappings are not used

function examples()
{
    // Using Chrome, navigate to https://material.angular.dev/components/chips/examples
    var page = Sys.Browser("chrome").Page("https://material.angular.dev/components/chips/examples");
                
    var panel = page.FindElement("//example-viewer[@id='chips-reactive-form']//chips-reactive-form-example/section/mat-form-field//mat-chip-grid[@role='grid']");

    // Example 1
    var items = panel.FindAll(["CustomObjectType", "contentText"], ["MatChipRow", "regexp:(how-to.*)"], 100);
    for (var i = 0; i < items.length; i++) {
        Sys.HighlightObject(items[i]);
    }
    
    // Example 2
    var items = panel.FindAll(["CustomObjectType", "contentText"], ["MatChipRow", "tutorial*"], 100);
    for (var i = 0; i < items.length; i++) {
        Sys.HighlightObject(items[i]);
    }
    
    // Example 3
    var items = panel.FindElements("//span[@aria-describedby='mat-mdc-chip-7-aria-description']|//span[@aria-describedby='mat-mdc-chip-4-aria-description']");
    for (var i = 0; i < items.length; i++) {
        Sys.HighlightObject(items[i]);
    }

    // Example 4
    var panel = page.FindElement("//app-component-viewer[contains(., 'overview')]")
    // Fina all objects in the page, where CustomObjectType = MatChipRow
    var items = panel.FindAll("CustomObjectType", "MatChipRow", 100);
    // Iterate through all found objects, highlight them and then click the X button to close them
    for (var i = 0; i < items.length; i++) {
        Sys.HighlightObject(items[i]);
        items[i].Button(0).Click();        
    }
}

I also have this snippet of code,

function pagesize()
{
    var page = Sys.Browser("chrome").Page("*");
    page.contentDocument.Script.eval("document.body.style.transform='scale(0.8, 0.8)'");
    aqUtils.Delay(2000);
}

which performs JavaScript injections - which performs the same as if using Chrome DevTools. However, this functionality was last working in TC v15.55 and has been broken since.

Originally posted by pkudrys on July 09, 2025

Hi, thank you for the suggestions! Yeah, I will most probably have to use one of these workarounds. To be quite honest, I don’t quite like them, because they add unnecessary complexity and hardcoded xpaths :wink: I would still prefer to use aliasElement as the reference and fnid its parent or certain ancestor.

Do you know what’s funny? As I mentioned before, FindElementByXPath failed to find the ancestor. You explained that TC uses an outdated JS, which may be the cause of this issue. However, I found out, that EvaluateXPath does exactly what’s expected to do! It finds the expected ancestor element, which FindElementByXPath fails to find. The problem is, that it returns an object, which is again not compatible with FindElement and other find-related functions :smiley:

As you can see here, the EvaluateXpath found proper element. But FindAll fails with “FindAll is not a function” error.

Originally posted by eykxas on July 09, 2025

Hello!

I’m also working on an Angular project. For this type of project, I exclusively use XPath to retrieve my objects.

In your example, here’s what I would do:

let ar = page.FindElements("//div[@role='presentation']//mat-chip-row"); //page is your parent object, this xpath returns an array of all the mat-chip-row inside your div.

Originally posted by rraghvani on July 09, 2025

There’s a subtle difference between FindElement and FindElements, an easy mistake to miss!

pkudrys​ just want to reiterate, FindAll method will only work on those objects that appear in the Object Browser.

Standard methodsExtended methods

Otherwise, you will have to implement your own “FindAll” method. Which means finding the parent node first, and then iterating through each child node, any node that matches your criteria, you then save and append that node to an array - this is real programming, and you’ll have total control of your search criteria!

Originally posted by eykxas on July 09, 2025

I don’t understand the issue here. He wants to get the list of all mat-chip-row and then doing something (click on the button).

With FindElements (and the proper xpath) he gets an already populated array, and just need to iterate through.

That’s what I’m doing in my projet, and it works fine. Without needing NameMapping.