How to get QML element by id or objectName using either findObject() or waitForObject() without object map? Is it even possible?
Consider:
Item {
    id: page
    objectName: "pageObject"
    Text {
        id: foobar
        objectName: "lorem"
        text: "ipsum"
    }
}
I would like to access foobar's text in test script like:
obj = findObject("foobar")
if obj.text == "ipsum":
    test.passes("all good")
else:
    test.fail("uh oh")
I have also tried:
obj = findObject("lorem")
obj = findObject("{name='lorem'}")
obj = findObject("{name='lorem' type='Text'}")
obj = findObject("{objectName='lorem'}")
obj = findObject("{objectName='lorem' type='Text'}")
                Ultimately I solved the issue by only having the root level object in object map. All other objects are iterated in code using functions below.
import sys
import time
# Definitions
ROOT_SYMBOLIC_OBJECT = ":_KMainView"
# Object finding functions
def findSymbolic(symbolicName):
    # Note: give Squish symbolic name like ":Foobar"
    try:
        obj = findObject(symbolicName)
    except LookupError:
        sys.exc_clear()
        test.log("FAIL: Root object not found: " + symbolicName)
        sys.exit()
    return obj
def findRoot():
    return findSymbolic(ROOT_SYMBOLIC_OBJECT)
def findFlat(fromElement, findId, occurence, stopOnFail, verbose):
    start = time.time()
    result = None
    found = 0
    if fromElement and hasattr(fromElement, 'children'):
        children = object.children(fromElement)
        for child in children:
            if hasattr(child, 'id') and child.id == findId:
                found += 1
                if found == occurence:
                    result = child
                    break
    if result == None and stopOnFail:
        test.log("FAIL: findFlat: " + findId + " not found")
        sys.exit()
    if verbose:
        printElapsed("findFlat", findId, start)
    return result
def findRecursive(fromElement, findId, occurence):
    return findRecursiveWithOptions(fromElement, findId, occurence, True, False, True)
def findRecursiveWithOptions(fromElement, findId, occurence, stopOnFail, verbose, skipUnnamed):
    start = time.time()
    found = 0
    depth = -1
    obj, found, depth = objIter(fromElement, findId, occurence, verbose, skipUnnamed, found, depth)
    if found == occurence:
        printElapsed("findRecursive ok", findId, start)
        return obj
    printElapsed("findRecursive not found", findId, start)
    if stopOnFail:
        test.log("FAIL: findRecursive:" + findId + " not found.")
        sys.exit()
    return None 
def objIter(fromElement, findId, occurence, verbose, skipUnnamed, found, depth):
    depth += 1
    if verbose:
        printObjIter(fromElement, depth)
    children = object.children(fromElement)
    for child in children:
        if hasattr(child, 'id'):
            if child.id == findId:
                found += 1
                if found == occurence:
                    return child, found, depth
        elif skipUnnamed:
            continue
        obj, found, depth = objIter(child, findId, occurence, verbose, skipUnnamed, found, depth)
        depth = depth - 1
        if found == occurence: 
            return obj, found, depth
    return None, found, depth
def findRecursiveList(fromElement, findId):
    return findRecursiveListWithOptions(fromElement, findId, True, False, True)
def findRecursiveListWithOptions(fromElement, findId, stopOnFail, verbose, skipUnnamed):
    start = time.time()
    objList = []
    depth = -1
    objList, depth = objListIter(fromElement, findId, verbose, skipUnnamed, objList, depth)
    printElapsed("findRecursiveList", findId, start)
    return objList 
def objListIter(fromElement, findId, verbose, skipUnnamed, objList, depth):
    depth += 1
    if verbose:
        printObjIter(fromElement, depth)
    children = object.children(fromElement)
    for child in children:
        if hasattr(child, 'id'):
            if child.id == findId:
                objList.append(child)
        elif skipUnnamed:
            continue
        objList, depth = objListIter(child, findId, verbose, skipUnnamed, objList, depth)
        depth = depth - 1
    return objList, depth
# Utilities
def printElapsed(functionName, objectId, start):
    elapsed = time.time() - start
    test.log(functionName + " - " + objectId + " in " + str(elapsed) + "s.")
def printObjIter(element, depth):
    dashes = "-" * depth
    if hasattr(element, 'id'):
        test.log(dashes + " " + str(element.id))
    else:
        test.log(dashes + " [unnamed]")
Example test script for the question's QML:
startApplication("exampleapp") # Launch application binary 'exampleapp'
snooze(10) # Let it start
root = findRoot()
page = findFlat(root, "page", 1, True, False)
foobar = findFlat(page, "foobar", 1, True, False)
# Also just: foobar = findRecursive(root, "foobar", 1)
if foobar.text == "ipsum":
    test.passes("text is ok")
else:
    test.fail("Incorrect foobar text: " + foobar.text)
                        You can replace the symbolic name ":_KMainView" stored in ROOT_SYMBOLIC_OBJECT with its real name just as well, because symbolic name are just place holders for real names:
Article - How Squish looks up Real Names from Symbolic Names
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With