I recently faced a problem with determining browsers' support for certain DOM features. One of them was Element.children feature, which is still causing me headache. I have the following line in my code:
var NATIVE_CHILDREN = Element.prototype.hasOwnProperty('children');
It is supposed to check if the browser supports Element.children -feature [https://developer.mozilla.org/en/DOM/Element.children].
According to MDN and quick testing, all the major browsers support this feature.
On Firebug on Firefox, value of NATIVE_CHILDREN is expectedly true. Surprisingly, on Chrome, Safari and Opera the value is false (unfortunately I don't have accees to machine with Windows to check what IE thinks about it).
According to DOM4 - Free Editor's Draft 5 April 2012 [http://dom.spec.whatwg.org/#element], children should be part of Element object's prototype. Apperantly Chrome's, Safari's and Opera's Element object doesn't contain such a method!
I have tried checking the prototypes of HTMLCollection and Node (I also tested HTMLParagraphElement and HTMLBodyElement), but none of them seem to contain method called 'children' (except on Firefox). How can I make my test to work cross-browser? I don't want to use any external libraries for this, because this is for my own little library.
I think the reason why this test might return false on Chrome is that you're checking on the prototype. This is not the best way, for several reasons:
Different browsers can (and do) use different implementations of the prototype, some prototypes are not accessible in IE for instance. In this case, I'd say your issue is the result of chrome relying on the (non standard) __proto__ property rather then prototype. I can't remember when, but I had a similar issue with chrome, and this was the source if the problem.
AFAIK all browsers have a children property for their elements, though they behave differently in some cases, so I have some doubt as to the use of checking the existence of such a property.
If you still want to check this, why not use document.body.hasOwnProperty('children')? Returns true on FF, Chrome, Safari and IE.
That's because some engines only slap on the children attribute on element creation. A quick test in the Chrome console shows that:
Element.prototype.hasOwnProperty( 'children' ); //false
//however,
document.createElement( 'foo' ).hasOwnProperty( 'children' ); //true
//or even
!!document.createElement( 'foo' ).children; //true
Non-function properties often don't appear on the prototype, for a simple reason - they aren't set yet, and it doesn't make sense if they will be. Element.prototype doesn't have any children, because it's not an element, it's a prototype for elements.
It is safer to check if( 'children' in document.body) than to mess around with prototypes. Important to note the quotes, if not a variable children might be used/created...
According to QuirksMode, all browsers support children except Firefox 3 (which is a surprise to me, since it worked when I tested in that browser...), so there should be no need to test for this property.
Related
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?
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
So I did a little work on a colour picker module adding the ability to parse human readable colours. I leveraged .getComputedStyle() to perform the conversion.
I implemented detection of the feature (should be IE 9+) with:
window.hasOwnProperty('getComputedStyle')
This is when I noticed some strange behavior. In Chrome and FF this reported true as expected. However in IE 11 (which does support it) it reported false.
I'm a little stumped as to why this is happening. I've performed other ways of checking its support. I'm stumped however as to why IE reports false whilst it does support it.
Not too sure if this is overkill but this fiddle simply logs the response so you can see for yourself. https://jsfiddle.net/xrgrgrhe/
Don't perform feature detection in this way; browsers aren't always consistent about where certain properties and methods are defined on the prototype chain. Instead, simply access the property:
if ( window.getComputedStyle ) {
/* Proceed to use window.getComputedStyle */
}
Functions are truthy, while undefined is falsy. As a result, this test will pass if the method is defined anywhere on the prototype, rather than directly on the Window instance object.
For what it's worth, the original test in the question also returns true in Microsoft Edge.
I want to add some custom properties to the prototype of the DOM Object,I am able to access the Object.constructor.prototype and add properties when I am working with Firefox or Chrome but can't access it in IE8 and less because it says there is no constructor of the Object.Is there any work around for it?
The constructor property of an object is supported by IE8 in quirks and standards mode, check and see what mode the document is rendering in. You can enforce standards mode by ensuring that you have a doctype at the top of your page. However, Object.constructor === Function, so when you are modifying the Object.constructor.prototype, youre really modifying Function.prototype, which I don't think is what you are looking to do.
when get a element's style, we always use
if(document.defaultView && document.defaultView.getComputedStyle) to check whether the browser support the method or not.
why not use if(window.getComputedStyle)?
So in short, the reason why we use document.defaultView && document.defaultView.getComputedStyle is that we want a cross-browser working-on-every-element method of checking whenever it supports fetching computed styles.
Simple if(window.getComputedStyle) would fail for iframes in Firefox 3.6 (according to article linked in comment by Alex K.).
According to the MDN defaultView is no longer required
In many code samples, getComputedStyle is used from the document.defaultView object. In nearly all cases, this is needless, as getComputedStyle exists on the window object as well. It's likely the defaultView pattern was a combination of folks not wanting to write a testing spec for window and making an API that was also usable in Java.
There was a bug in Firefox 3.6 (2010/2011) that needed defaultView fix
There are lots of DOM/CSS inconsistencies between browsers. But how many core JS differences are there between browsers? One that recently tripped me up is that in Firefox, setTimeout callback functions get passed an extra parameter (https://developer.mozilla.org/en/window.setTimeout).
Also, now that browsers are implementing new functions (e.g. Array.map), it can get confusing to know what you can/can't use if you are trying to write code that must work on all browsers (even back to IE6).
Is there a website that cleanly organizes these types of differences?
I find QuirksMode and WebDevout to have the best tables regarding CSS and DOM quirks. You can bridge those incompatibilities with jQuery. There is also this great list started by Paul Irish which includes pretty much any polyfill you could ever need, including ones for ES5 methods such as Array.map.
There doesn't appear to be anything out there that clearly outlines all these issues (very surprising actually). If you use jQuery there is a nice browser compatibility doc section that outlines supported browsers and known issues. I just deal with issues as they come up (as you should be browser testing in all cases anyways) and you can document them if you want to make sure you are coding correctly or if you run into issues and need to know fixes. It's easy to find issues when you do a quick search on a particular topic.
Well, I'm going to open up a CW:
Prior to Firefox 4 Function.apply only accept an Array, not an array-like object. Ref MDC: Function.apply
Some engines (which ones?) promote the result of String.prototype methods from string to String. Ref a String.prototype's "this" doesn't return a string?
Firefox 4 may insert "event loops" into seemingly synchronous code. Ref Asynchronous timer event running synchronously ("buggy") in Firefox 4?
Earlier Firefox versions would accept a trailing , in object literals. Ref trailing comma problem, javascript (Seems "fixed" in FF6).
Firefox and IE both treat function-expression productions incorrectly (but differently).
Math.round/Math.toFixed. Ref Math.round(num) vs num.toFixed(0) and browser inconsistencies
The IE vs. W3C Event Model -- both are missing events/features of the other.