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