How to develop a custom protractor locator? - javascript

I have an angular-application where I put custom html-attributes ("data-testid='saveButton'") for identification on e.g. buttons, inputs etc.
Protractor has no built-in locator for this: the xpath-way does not work as this will always search from the document root (to overcome this limitation I would have to do quite a lot of string-magic to build the xpath-string, so I discarded this variant).
So I wanted to write my own locator, and consulted the official Protractor Documentation.
The documentation leaves me with an important question:
What methods are available on the parent-element-object? In their example they use using.querySelectorAll('button'); but how do they know they can use this?
I searched for 'querySelectorAll' in the protractor-documentation to see if it is maybe a method of ElementFinder or WebElement, but I didn't find it.
Also I found no way to debug the locator (only stop the protractor-test by browser.pause()), so I can't look at runtime to see what I can do with the given parent-element.
So does anybody know how I can get information about what methods the parent-element has?

The parent-element, which is essentially the context of the selector is a DOM element that gets handled by the browser - it can use whatever DOM function there is, in this case Element.querySelectorAll. As the addLocator's example says about the function you pass to it:
This function will be serialized as a string and will execute in the browser.
Also, keep in mind that there is a way to provide context to the xpath selectors thus avoiding the search from root:
var context = element(by.css('.some-parent-element-class'));
var divDirectDescendants = context.element(by.xpath('div'));
var divAllDescendants = context.element(by.xpath('.//div'));
With CSS these would be:
var divDirectDescendants = element(by.css('.some-parent-element-class > div'));
var divAllDescendants = element(by.css('.some-parent-element-class div'));
Also, there's a way to achieve what you want with a CSS selector (which is what querySelectorAll is, after all):
var everyElementWithMyAttr = element.all(by.css('[data-testid="saveButton"]'));

Related

Get all properties of an HTML element without running JS inside browser

I need to find all available properties of any HTML element.
Using javascript if we have to find all properties of an html element we do this
function getAllProps(objects){
props = []
for(var key in objects) {
props.push(key)
}
return props;
}
And we use above function in this way:
var btn = document.createElement("BUTTON");
document.body.appendChild(btn);
console.log(getAllProps(btn));
Above code is completely browser dependent. We need to run this code inside browser to get it running.
I want to know, is it possible to do the same using cscript.exe or any other external JS interpreter?
Thanks in Advance,
Obviously you can not do this. To get the properties of an object you need that object and the get that object you need an implementation of that object. The best thing you can do is to look into the DOM specification and read what properties should be present in a conforming implementation.
There are implementation of the DOM for JavaScript runtimes that are not browser runtimes but then you are still depending on a specific implementation. Here is one for Node.js but I have no idea how good or complete it is.

What does a query selector return in zombie.js?

I am learning Zombie.js with node.js using sys.debug() statements to track my progress. What is returned by calls like this t = browser.body.querySelector(".navigation"); ? It is hard to tell what is going on without browser developer tools or something like php's var_dump. The API doesn't really explain it.
How do I unpack this?
t = browser.body.querySelector(".navigation");
sys.debug(t); //returns "DEBUG: [ UL.navigation]" I don't know what this means.
.querySelector() is defined as part of a DOM API, specifically the Selectors API, which Zombie.js is using an implementation of.
So, as it does in other browsers, it should return:
[...] the first element that is a descendent of the element on which it is invoked that matches the specified group of selectors.
In this case, based on the UL.navigation in the log, t is an HTMLUListElement. Or:
<ul class="navigation"></ul>
And, in cases where no matching Element can be found, it'll return null.

How to tell the type of a JavaScript and/or jQueryobject

This question pertains as much to the ECMAScript language implementation we know as JavaScript as it does to jQuery and the developer tools availble in most popular browsers.
When you execute a statement like so:
var theElement = $('#theId').closest();
what is the type of theElement?
I assume that in a jQuery situation like above, many jQuery methods including the one above actually return the jQuery object itself, which packages the stuff you actually want to get to. This, so that it may maintain a fluent API and let you join method calls in a single statement like so:
$('#selector').foo().bar().gar().har();
However, in the case of jQuery then, how do you determine what the real underlying type is? For example, if the element returned was a table row with the Id tableRowNumber25, how do you get to that, say, using FireBug.
When I look at either a jQuery returned object or a simple JavaScript object in the watches window of Firebug or any of the Developer Tools in most popular browsers, I see a long laundry list of properties/keys and I don't know which one to look at. In a jQuery object, most of the properties are lamdas.
So, really, my question is -- how do you know the underlying type, how do you know what's actually being returned?
The type of theElement will be [object jQuery].
If you want the HTML element itself, you have to select it:
console.log(theElement[0]) //Return <div id='theId'>
console.log(theElement.get(0)) //Return <div id='theId'>
If you want the node name, there is a property in the HTML node element call nodeName wich return the capitalised node name:
console.log(theElement[0].nodeName)// Return DIV
typeof(jQueryElementList.get(0)) will return a string of the type.
Some browsers might return this as upper or lower case, I think. IE probably uppercases (see Testing the type of a DOM element in JavaScript). Apparently you can check the nodeType attribute (jQueryElementList.get(0).nodeType) to determine whether it is an html object/tag.

Why shouldn't I access elements more "directly" (elemId.innerHTML)

I've seen some JavaScript code to access HTML elements like this: elementID.innerHTML, and it works, though practically every tutorial I searched for uses document.getElementById(). I don't even know if there's a term for the short addressing.
At first I thought simplistically that each id'ed HTML element was directly under window but using getParent() shows the tree structure is there, so it didn't matter that elements I wanted were nested. I wrote a short test case:
http://jsfiddle.net/hYzLu/
<div id="fruit">Mango<div id="color">red</div></div>
<div id="car">Chevy</div>
<div id="result" style="color: #A33"></div>
result.innerHTML = "I like my " + color.innerHTML + " " + car.innerHTML;
The "short" method looks like a nice shortcut, but I feel there is something wrong with it for it practically not appearing in tutorials.
Why is document.getElementById() preferred, or may be even required in some cases?
Why shouldn't I access elements more “directly” (elemId.innerHTML)
Because, according to the others in this thread, referencing arbitrarily by id name is not fully supported.
So, what I think you should be doing instead is store their selections into a var, and then reference the var.
Try instead
var color = document.getElementById('color');
color.innerHTML = 'something';
The reason why this would be a good thing to do is that performing a lookup in the DOM is an expensive process, memory wise. And so if you store the element's reference into a variable, it becomes static. Thus you're not performing a lookup each time you want to .doSomething() to it.
Please note that javascript libraries tend to add shim functions to increase general function support across browsers. which would be a benefit to using, for example, jquery's selectors over pure javascript. Though, if you are in fact worried about memory / performance, native JS usually wins speed tests. (jsperf.com is a good tool for measuring speed and doing comparisons.)
It's safer I guess. If you had a variable named result in the same context that you are doing result.HTML I'm pretty sure the browser will throw a wobbler. Doing it in the way of document.getElementById() in this instance would obviously provide you with the associated DOM element.
Also, if you are dynamically adding HTML to the page I may be wrong, but you could also encounter unexpected behaviour in terms of what result is :)
Also I will add that not all ID's can have values that will not work as variable names. For instance if your ID is "nav-menu".
Although I suppose you could write window["nav-menu"].innerHTML
Which makes me think, what happens if you create a window level variable with the same name as an ID?
Checkout this jsfiddle (tested in chrome): http://jsfiddle.net/8yH5y/
This really seems like a bad idea altogether. Just use document.getElementById("id") and store the result to a variable if you will be using the reference more than once.

Using $.data() in jQuery to store flag on element

I am authoring a simple jQuery plugin that turns an input tag into a time-formatted element (on blur it will change 245p into 2:45 pm).
Since I do not want to apply the time format events to the same element twice, I need a way to detect that the specific element in the list provided has not already had the format applied.
This is the relevant part of the code:
var methods = {
init : function(sel) {
var $this = $(sel);
return $this.each(function(){
var data = $(this).data('time_formatted');
if (data) {
return;
} else {
$(this).data('time_formatted', true);
I have heard that using $(sel).data() in a plugin is not a good idea; instead, use $.data(). I don't know why, that's just what I've heard; honestly, I don't know what the difference is.
So my question is, is this the way to accomplish checking if a specific element has had the time formatter applied to it in a plugin?
If you care to see the plugin in it's current development state, see http://jsfiddle.net/userdude/xhXCR/.
Thanks!
Jared
Where have you heard that using .data() is not good? jQuery's plugin autoring page says:
Often times in plugin development, you may need to maintain state or check if your plugin has already been initialized on a given element. Using jQuery's data method is a great way to keep track of variables on a per element basis. However, rather than keeping track of a bunch of separate data calls with different names, it's best to use a single object literal to house all of your variables, and access that object by a single data namespace.
So it should be perfectly fine.

Categories

Resources