Hi all, In Test Complete project, which was written in 2013 (not by me), I see that one of the flex objects can be successfully found: function ActionToolbar()
{
var oParent = MVVO_PageCo...
function DocumentViewer()
{
var oParent = Page();
var aProps = ["ObjectType", "ObjectLabel"];
var aVals = ["DocumentView", "documentView"];
return CFInternetBrowser.FindObjectByProperties(aProps, aVals, oParent, "DocumentViewer", 100);
}
CFInternetBrowser.FindObjectByProperties is more complicated function, it searches the specified parent object for an object who's that matches the specified property values.
function FindObjectByProperties(aPropertyNames, aPropertyValues, oParentObject, strDescription, nDepth, bTryWaitForBrowser)
{
var strModuleID = c_strModule + GetFunctionName(arguments.callee);
var strStatus = "(Object NOT found)";
var oReturn = null;
var oObject = null;
var oPage;
try
{
CFLog.DebugMessageBegin(strModuleID + " Values: " + aPropertyValues.toString());
// Assign default parameter values.
nDepth = CFGeneralUtilities.GetValueOrDefault(nDepth, 50);
bTryWaitForBrowser = CFGeneralUtilities.GetValueOrDefault(bTryWaitForBrowser, true);
if (CFObject.ObjectExists(oParentObject))
{
// Refresh the parent object
oParentObject.Refresh();
}
else
{
// The ParentObject does not exist, so there is not point in continuing to attempt to find the child element
throw new kfxException(strModuleID, "The provided oParentObject does not exist. #1", null, strDescription);
}
// Try to find the object the first time
oObject = CFObject.FindObjectByProperties(aPropertyNames, aPropertyValues, oParentObject, strDescription, nDepth);
// If the object was not found, try one last time.
if ((CFException.IsException(oObject)) && (bTryWaitForBrowser))
{
// Find the page object in the hierarchy
oPage = GetPageFromDescendent(oParentObject);
CheckResult(oPage);
// Make sure the page is loaded and rendered before trying again.
CheckResult(WaitForBrowser(oPage));
if (CFObject.ObjectExists(oParentObject))
{
// Refresh the parent again
oParentObject.Refresh();
}
else
{
// The ParentObject does not exist, so there is not point in continuing to attempt to find the child element
throw new kfxException(strModuleID, "The provided oParentObject does not exist. #2", null, strDescription);
}
// Try one more time to see if we can find the object.
oObject = CFObject.FindObjectByProperties(aPropertyNames, aPropertyValues, oParentObject, strDescription, nDepth);
}
// Finally if the object was not found, throw an exception.
CheckResult(oObject, "Could not find object: " + strDescription);
// Set the return value
oReturn = oObject;
}
catch(oException)
{
oReturn = CFException.ProcessException(strModuleID, oException);
CFLog.DebugException(oReturn);
}
CFLog.DebugMessageEnd(strModuleID);
// Object was found
if (! CFException.IsException(oObject))
strStatus = "(Object found)";
WriteToLog(strModuleID, strStatus + ": Names='" + aPropertyNames.toString() + "', Values='" + aPropertyValues.toString() + "', Depth=" + nDepth);
return oReturn;
}
CFObject.FindObjectByProperties:
function FindObjectByProperties(aPropertyNames, aPropertyValues, oParentObject, strDescription, nDepth)
{
var strModuleID = c_strModule + CFGeneralUtilities.GetFunctionName(arguments.callee);
var oObject = null;
try
{
CFLog.DebugMessageBegin(strModuleID + " Values: " + aPropertyValues.toString());
// Assign default parameter values.
nDepth = CFGeneralUtilities.GetValueOrDefault(nDepth, 100);
// See if provided parent object is an exception object
if (CFException.IsException(oParentObject))
throw new kfxException(strModuleID, "The provided oParentObject was already an exception object.", oParentObject, strDescription);
// Make sure we were given a valid parent object.
if (oParentObject == null)
throw new kfxException(strModuleID, "You must supply a valid parent object. The parent object specified is null.");
// We need to convert the arrays for use with the TestComplete API.
var aConvertedPropertyNames = CFGeneralUtilities.ConvertArrayToDictionary(aPropertyNames);
var aConvertedPropertyValues = CFGeneralUtilities.ConvertArrayToDictionary(aPropertyValues);
// Attempt to locate an object that matches the set of properties we were given.
oObject = oParentObject.Find(aConvertedPropertyNames, aConvertedPropertyValues, nDepth);
// Finally if the object was not found, throw an exception.
if (! ObjectExists(oObject))
throw new kfxException(strModuleID, "Could not find object: " + strDescription, null, "", arguments);
}
catch(oException)
{
oObject = CFException.ProcessException(strModuleID, oException);
CFLog.DebugException(oObject);
}
CFLog.DebugMessageEnd(strModuleID);
return oObject;
}
And this object uses parent ActionToolbar (successfully):
function Approve()
{
var oParent = ActionToolbar();
var aProps = ["Caption", "ObjectType"];
var aVals = ['Approve', 'ToolButton'];
return CFInternetBrowser.FindObjectByProperties(aProps, aVals, oParent, "Approve");
All objects in my application which were used in code I could see object tree, except of ActionToolbar.
In debug mode I also see ActionToolbar object:
So as I see this is real object.. So why I can`t see it in project tree?)) I don`t understand.
DocumentViewer is searching for a child object of the page that could be anywhere within 100 layers of the page that is of ObjectType DocumentViewer with ObjectLabel documentViewer. So... that's where you need to start. Yes, you're seeing buttons in your viewer... but I don't see in your initial screenshot where that Document Viewer object is... it could be ANYWHERE in your tree within 100 layers deep.
Keep in mind that ObjectType and ObjectLabel don't always display in the object tree. You need to inspect the details of the objects in your tree to find the specific object.
So... once it finds the DocumentViewer, it then finds another object with ObjectType ActionToolbar with label actionToolBar. Again... it might not show up exactly like that in the tree, you need to inspect the object details.
Again... it all comes down to, as I suspected, a LOT of code being wrapped around the native "Find" method. To understand the custom code, you need to understand that method.
As you can see actions Approve and Request Comment are in "More Actions" menu. The problem is to find their objects.
All logic of autotest looks good: we look for action, if we cannot find it we look for "More actions" button (little arrow on the pic), click it, and then try to find action button again. In both cases (in "More actions" and not in "More actions") we use the same function to find the action button, you can see it in my message above.
But if the action button is in "More actions" menu (i.e. Approve on the screenshot) TestComplete can`t find it.
I marked action buttons in object tree on screen below:
It seems that it worked when this test was created, but I`m not sure, nobody knows...
My guess is that, for the More Actions, you need to select, potentially, either a different parent object or a different set of criteria. Again, the object tree only shows the tree relationship. Click on the buttons you want to access and look at their properties. Use those to work with your find methods to find the specific buttons.