Proper use of element.all & .get() with page objects - javascript

I have noticed that if I am using element.all & get() with page objects that if I put the get() on the page object side it works but if I move it to the spec side it does not work. For example take this element locator.
element.all(by.repeater('some_element'));
If I want to select the first item in this element array. I can write the page object like this:
==mypage.js==
this.myfoo = element.all(by.repeater('some_element')).get(0);
And then call it from my spec like this and it will get the first element in the array.
==myspec.js==
mypage.myfoo;
The above works fine, But it does not work if I move the .get(0) to the spec side and remove it from the page object side.
==mypage.js==
this.myfoo = element.all(by.repeater('some_element'));
==myspec.js==
mypage.myfoo.get(0);
Anyone know why? Is it just better programming to have it on the page object side? I don't mind using it the way it is working. I'm just curious why it doesn't work if I use the .get() on the spec side.

Related

Selenium - Universal Way to Convert "WebElement" to Javascript or JQuery Object

I have a a simple WebElement and I want to perform a series(one or more) of JS/JQuery type actions on my object.
Most of the time this is easy, I simply get the ID of the object, pass that into the "ExecuteScript" function, and viola works great:
RemoteWebDriver driver = ...;
var element = driver.FindElementByXPath("..."); //Or any other type of lookup
driver.ExecuteScript(#"$('#" + element.GetAttribute("id") + "')."DoSomeStuff...;");
20% this doesn't work at all because the item doesn't have an ID. Of course there are many ways to lookup items in Selenium and many ways to lookup items in jQuery or Javascript, but they don't always map, and while it may be possible to construct a query in jQuery that can lookup a Selenium object, that methodology cannot be the same for every object type.
Searching around it seems most people use the "id" method(Examples: 1, 2, 3). You can do this the opposite way. Another idea would be to give each element a unique ID in selenium before accessing it in jQuery, but it doesn't look like that would work because to set it you need to using Javascript or jQuery.
I've yet to find a way to do this Universally for every element, how can this be done?
You can, and always have been able to, pass element references back and forth in JavaScript via ExecuteScript. Whether those raw DOM elements can be converted to be used by JQuery is a matter upon which I am not qualified to speak. Nevertheless, the code for referencing a WebDriver-found element in your JavaScript code would be something like this:
// Assume element holds a reference to an already-found
// IWebElement, found using the standard WebDriver FindElement
// methods, and that driver is a properly-instantiated
// IWebDriver object.
// N.B., doing proper casting here, since it's idiomatic in
// the WebDriver library to code to the interface, not the concrete
// implementation.
IJavaScriptExecutor executor = driver as IJavaScriptExecutor;
executor.ExecuteScript("alert(arguments[0].tagName);", element);
The above code will throw up an alert (and block your Selenium code), showing the element's tagName JavaScript property. You can use this technique to use the element just as you would in JavaScript in the page.

Why specify [0] when using new FormData()?

I've just spent a good few minutes debugging why new FormData($("#ImageEditorForm")); isn't working. After turning to Stack Overflow, I found a suggestion in another thread to use new FormData($("#ImageEditorForm")[0]); instead.
I made the change, not expecting anything to happen. Instead, the code now works perfectly and as expected. Previously, nothing was being submitted to the server. Now, form data and files appear as expected.
My question is why is the "[0]" required? There is only one element with that ID in the DOM. Selecting by ID should surely return only one element? What is going on here?
$("#ImageEditorForm") returns a jQuery object and FormData requires a DOM Node.
You can use document.getElementById(id); which returns a DOM Node.
FormData(document.getElementById("ImageEditorForm"));
Or use document.querySelector(selector); which takes a css selector and returns the node if found and null otherwise.
When selecting with jQuery, the returned object is a jQuery object, and to get the actual DOM-node this represents, you use [0] on the jQuery object.
If you had used a selector which returned a couple of results, it would be easier to understand why you would need to index into the object to get to the actual DOM-node, but this is standard jQuery.
And as andlrc said, you need to pass an actual DOM-node to the FormData function.

Do you need to check if a jQuery object exists?

Let's say you have a website of 100 pages and there is a div with an id of #unique-div that only appears in page-5.html, but not in the other 99 pages and to be extra simple with the example you have a JS file that is loaded on all pages, and inside it there is this:
var uniqueDiv = $('#unique-div');
uniqueDiv.addClass('random-class');
does that have any negative impact in any possible way (for instance, performance)? Would it better to do a length check first?
var uniqueDiv = $('#unique-div');
if ( uniqueDiv.length ) {
uniqueDiv.addClass('random-class');
}
If so, why?
Or what about if you are chaining objects like this:
var uniqueDiv = $('#unique-div');
someVar.add(moreVars).add(uniqueDiv).addClass('random-class');
If the object doesn't exist, what happens?
I tried looking this up, but I have always wondered this.
It is the responsibility of ANY jQuery method to have a "proper" behavior whether there are 0, 1 or more than 1 DOM objects in the current jQuery object that they are called on. So, as long as you aren't using some broken jQuery plug-in methods, you do not have to test the length before calling a method and this includes situations where you are using chaining.
So, in your case this would be perfectly fine, even if you had no idea whether #unique-div actually existed:
$('#unique-div').addClass('random-class');
If the div didn't exist, then the .addClass() method would just do nothing.
Note: that some methods that retrieve a value such as .val() are coded to only operate on the first DOM element in a jQuery object and you will have to check with an individual method like that what they are coded to return if there are no DOM objects in the jQuery object. For example, .val() will return undefined when there are no DOM objects in the jQuery object.
There might be some infinitesimal amount of performance saving, but it's really negligible. There are probably going to be plenty of times in your code you'll do a for-loop through an array, acknowledging the length might be zero.
JQuery objects always have some size to them, and all methods I know of (ie, addClass) are equipped for empty sets, so I don't see any issue with skipping the length check.

Update one deeply structured javascript object from another in knockout.js

I have a javascript object (viewModel) that is binded to view . I'm getting new version of it (newViewModel) from server . (You can imagine stock market price application at this point)
I don't want to bind newViewModel because I dont want to loose old viewModel's reference.
So I need update all properties of my existing javascript object from server response !
This is maybe javascript question but my viewModel have so many observable properties and sub-properties. (knockout's observable)
Ps: jQuery's $.extend does not work.
UPDATED (It seems ok):
ko.mapping.fromJS(newViewModel,viewModel); seems working .. I could not recognize it, because "Vs.Net Intellisense" did not show overloads of it.
My object is very deeply structured. if I see any problems I will inform you.
UPDATED (Does not work):
viewModel.x[] length=2
newViewModel.x[] length=12
The code above replaces all x with new ones. (I lost viewModel.x[0],viewModel.x[1] references) !!
So my html is not synchronized with my objects. viewModel.x[0] in the basket on the right side but it
is not in the basket on the left side (screen)
There is no magic way for it.. Because I need to match old array elements with news. "Code" needs to know "keys" of array elements..
I visit all array elements if I could find newElement in my old array I update oldElement's properties if I could not find I add newElement to oldArray.
Painful but I had to do.

Control references in jQuery

function eegetdropdownvalue_str(ctl){return ctl.selectedIndex>=0&&ctl[ctl.selectedIndex]?ctl[ctl.selectedIndex].value:''}
The above function is called with
co.p1A10=eegetdropdownvalue_str(document.formc.p1A10);
I want to switch the call over to jQuery to drop the document.form reference however doing this
co.p1A10=eegetdropdownvalue_str($('p1A10'));
Does not reference the control correctly - How should I do this?
There's two things wrong with your code.
First, $('p1A10') references nothing.
jQuery selectors work almost identically (if not completely identically) to the way css works.
So, just ask yourself how you would reference the object(s) in question in CSS and you're half way there.
I'm assuming that p1A10 is the name or id of an object. Since we're using CSS/jQuery syntax, this should be an id, although you can select by other attributes such as $("select[name='p1A10']") .
To reference an object by ID we use the # character (again, just like in CSS). So we can select your node via $('#p1A10').
The second problem is that your function is expecting a DOM object not a jQuery object. To keep your code intact, we need to say $('#p1A10')[0] where 0 is the first element within the collection of jQuery elements.
I've provided two examples to explain this a little better. One uses your existing infrastructure and one replaces it.
http://jsfiddle.net/TD6Uu/5/
Hope it helps.
Given a form with id formc and a select with name p1A10 you could e.g. use:
o.p1A10 = eegetdropdownvalue_str($('#formc select[name="p1A10"]').get(0));
If this doesn't do it, please provide use with the exact HTML structure

Categories