Oh man - yeah, those are a pain. Currently, we ended up having our developers write a little function to do the dirty work for us (see code below), and then we call the function from our TC scripts as needed. I'm not a big fan of this method, and I did write a script that could handle it at one point, but it didn't work for every situation. I don't think this does either, but it's a bit easier to call. If you choose to use this, then you'd have to have your developer put it in their code (obviously, not ideal), and then call it from a debug version of the app your testing. Regarding your error, seems like there's a possible problem there, but a general idea here is to use the Object Browser, instead of Object Spy, because it'll give you a lot more detail about all the components, not just the one you highlighted. I almost exclusively use the Browser now when trying to lookup an object.
Delphi Code:
// Data can look like any of 'Value' or '[Value]' or '[Value][SubValue]' as many levels deep as needed.
// The result they want back is |[n1]|[n2], etc.
// where n1 is the node index of Value,
// n2 is the child node index of SubValue, etc.
// note the pipe. |[x] for each value returned.
function TVirtualStringTree.GetNodeIndex(Data: String; VisibleColumnIndex: Integer): String; // for QA
var
Path: String;
Column: Integer;
function FindChild(aNode: PVirtualNode; aData: String): PVirtualNode;
var
Node: PVirtualNode;
Idx: Integer;
begin
Result := nil;
idx := -1;
if aNode = nil then
Node := GetFirst
else
Node := aNode.FirstChild;
While Node <> nil do
begin
idx := idx + 1;
if Text[Node, Column] = aData then
begin
Path := Path + '|[' + IntToStr(idx) + ']';
Result := Node;
break;
end;
Node := Node.NextSibling;
end;
end;
var
lData: String;
Node: PVirtualNode;
aTS: TStringList;
ColumnsArray: TColumnsArray;
begin
if Data <> '' then
begin
aTS := TStringList.Create;
try
ColumnsArray := Header.Columns.GetVisibleColumns;
Column := ColumnsArray[VisibleColumnIndex].Position;
Path := '';
lData := Data;
if lData[1] = '[' then
lData := Copy(lData, 2, MAXINT);
if lData[Length(lData)] = ']' then
lData := Copy(lData, 1, Length(lData) - 1);
aTS.Text := Trim(StringReplace(lData, '][', #13#10, [rfReplaceAll]));
Node := FindChild(nil, aTS[0]);
aTS.Delete(0);
while (aTS.Count > 0) and
(Node <> nil) do
begin
Node := FindChild(Node, aTS[0]);
aTS.Delete(0);
end;
if Node <> nil then
Result := Path
else
Result := '';
finally
aTS.Free;
end;
end;
end;
Not sure what language your scripts are in, but ours is in Python, and below is how it's called...
#-----------------------------------------------------------------------------
# Process TVirutalStringTree
#-----------------------------------------------------------------------------
def Process_TVirtualStringTree(ItemObjStr, ItemValue):
try:
ColIndex = '0'
# if '>' is found, split
if ItemValue.find('>') != -1:
ColName, ItemValue = ItemValue.split('>')
# get list of column headers
ColumnList = ItemObjStr + ".ContentToText(3,',')"
ColumnList = eval(ColumnList)
ColumnList = ColumnList.split(',')
# loop through header list until value is found, then set index
index = 0
index2 = 0
ColIndex = -1
for item in ColumnList:
index = index + 1
item = item.strip()
if item == ColName:
ColIndex = str(index2)
break
index2 = index2 + 1
# if ColIndex is never updated, then the column was never found - log error
if ColIndex == -1:
Log.Error('Column not found')
# pass column value and column index to John's routine
NodeIndex = ItemObjStr + '.GetNodeIndex(' + '\'' + ItemValue + '\'' + ',' + ColIndex + ')'
NodeIndex = eval(NodeIndex)
# if john's routine returnes -1 then we log an error
if NodeIndex == '':
Log.Error(ItemValue + ' not found')
ItemValue = NodeIndex
return ItemValue
except Exception as Error:
TerminateDueToError('Process_TVirtualStringTree', str(Error))
Hope this helps.