Search code examples
javascriptdomqtphp-uftmicrofocus

Does Webelement.Object.<method> provide the original result, or a clone?


TDLR: The central question is:

Is it true that with IE, a Web test object´s .Object method and all "sub-methods" are directly providing access to the original DOM objects, while with Chrome and FireFox, UFT does not return the original DOM object instances, but clones, copies, or some other representative instances?

Details: Playback steps that work in conjunction with IE, and that should work with all supported browsers according to the documentation, fail in conjunction with Chrome and Firefox for no good reason.

An analysis shows that this is caused by an unexpected behavior or bug in UFT.

Therefore I describe the problem in a general way. (Sorry, don´t have a SSCE yet.)

In particular:

If I use T T.Object.parentNode on the UFT level of a test object to reference the parent element, and then call .childNodes there to determine the immediate children of the parent element, then the following applies:

Expected: The list provided by childNodes contains among other possible instances also the instance T.Object.

Actual: The list supplied by childNodes contains (among other possible children) the T.Object only if IE is the browser in which the DOM is located. If Chrome or Firefox is used, the list provided by T.Object.parentNode.childNodes contains an element that represents exactly the same DOM element as T.Object.parentNode, but it is not the same object instance, i.e. there is no object instance E in the list provided by childNodes for which the UFT VBScript expression "E is T.Object.parentNode" evaluates to true.

On JavaScript level it can be shown that the assumption "A.parentNode.childNodes returns a list containing the object instance A" is always fulfilled (where A is any element (except the root) with sub-elements). On the UFT level, however, it can be understood that the assumption only applies in connection with IE, but not in connection with Chrome or Firefox.

But the documentation of UFT claims to make the native DOM object directly accessible via .object, and from this we conclude that calls and return values of methods of such DOM objects have to be passed through directly.

Instead, for Chrome and Firefox UFT seems to have a mechanism so that, for example, lists (like the NodeList provided by childNodes) are not passed through unaltered as a function result, but the list elements are cloned, or something similar, so that it is not the native instances that are provided, but only copies/representatives/clones.

Is this true? Then I consider this a bug, either in the documentation, or in UFT's Chrome and Firefox support. Is there a workaround?

I am just now starting to address Chrome and Firefox as target browsers for various reasons, and due to above circumstances, central generic code that is used breaks, quite unexpectedly for me, and I don't know of any generic workaround, so I would have to develop a case-specific individual workaround for each affected use, of which I have literally hundreds.

Any suggestions?


Solution

  • It's true that in IE UFT exposes the actual COM object used by IE via the .Object property. It is also true that for all other browsers (Firefox, Chrome, Edge, Mobile) UFT creates a wrapper object which forwards invocations to the browser's native DOM element (since those browsers don't expose their DOM as COM objects).

    If I understand your question correctly you're depending on COM's object identity rules. In a previous (professional) life I worked on the COM wrappers for UFT and I don't recall our considering this as a use-case. You may open a defect for UFT, I'm not sure how feasible it is to fix this, more likely they will say it's a limitation and update the documentation.

    If you want to check if a .Object object refers to the same underlying DOM element I would suggest setting some property yourself, something like:

    counter = 0
    Function UniqueValue(obj)
        If TypeName(obj.unique_value) = "Empty" Then
            obj.unique_value = "unique_value_" & counter
            counter = counter + 1
        End If
    End Function
    
    ' After this The element will have "unique_value_0" and the link "unique_value_1"
    UniqueValue Browser("Example Domain").Page("Example Domain").WebElement("Example Domain").Object
    UniqueValue Browser("Example Domain").Page("Example Domain").WebElement("Example Domain").Object
    
    UniqueValue Browser("Example Domain").Page("Example Domain").Link("More information...").Object