Iterating elements using NightWatchJS - automation

How do i click a button returned by elements command in night watch
client.elements('xpath', ".//a[#class='abcd')]", function (allButtons){
console.log('Element value is '+element)
allButtons.value.forEach(function (element) {
this.elementIdClick(element, function(res){});
}
}
While running i am getting an error as
Element value is [object Object]
TypeError: Object #<Object> has no method 'elementIdClick'
So how do i get each element from the element list returned by client.elements
I realized the parameters for elementIdClick is wrong, i updated the code as
client.elements('xpath', ".//a[#class='abcd')]", function (allButtons){
allButtons.value.forEach(function (element) {
console.log('Element value is '+element)
this.elementIdClick(this.elementIdAttribute(allButtons.value[element].ELEMENT, 'id'), function(res){});
Now the error is
Element value is [object Object]
TypeError: Cannot read property 'ELEMENT' of undefined
So again back to original question. How do i get individual elements from a list of webelements using nightwatchJS

The following worked for me:
function iter(elems) {
elems.value.forEach(function(element) {
client.elementIdClick(element.ELEMENT)
})
};
client.elements('css selector', 'button.my-button.to-iterate', iter);
Each element is a JSON object of the form { ELEMENT: string } (so, has no method itself.)
this in forEach does not point to the element, nor client: you need to invoke client.elementIdClick() or will get a TypeError.
Hope it helps.

I used the following strategy to iterate over DOM elements using Nightwatch:
// Executing a function in the application context.
client.execute(function () {
// Get elements by CSS selector.
var elements = document.querySelectorAll('.elements');
// Iterate over them.
[].forEach.call(elements, function (element) {
// Manipulate each element.
element.click();
});
});
That snippet is inside a test of course.
If you use jQuery or something similar you can use that too.

I think the error is getting generated by your console.log() statement.
From the elements() command, allButtons.value will be an array of several objects. To access key pairs in that array, you need need to specify where in the array and then reference the object: allButtons.value[index].ELEMENT
Because you gave your .forEach() loop only one arg, it's interpreting that as the index for the array, and in my code sample below I replaced your local variable element with index for clarity. There is also no need to use the .elementIdAttribute() function; the number returned by allButtons.value[0].ELEMENT will work as the id.
client.elements('xpath', ".//a[#class='abcd')]", function (allButtons){
allButtons.value.forEach(function (index) {
console.log('Element value is '+index.ELEMENT)
client.elementIdClick(index.ELEMENT);}})
Hope that helps.

Related

Cypress, how to check property exists

I'm new to cypress and am trying a couple of different methods to get a checkbox property...
checkBox().should('have.prop', 'checked')
checkBox().its('checked').should('exist')
The first line works fine but I was expecting the second to also pass but I get a "expected Undefined to exist" response.
Thanks
Assuming checkBox() function returns cy.get('.checkbox'), I think
checkBox().its('checked').should('exist')
fails because checkBox() does not return an object containing just the attributes. It returns the whole element (I think as an array). so you can't use its('checked') directly on checkbox().
Anyways, to do what you are expecting to do, you can use several methods,
using invoke('attr', 'checked')
checkBox().invoke('attr', 'checked')
.should('exist')
using getAttribute js function and expect chai assertion
checkBox().then($el => {
expect($el[0].getAttribute('checked')).to.exist;
})
using attributes in js and (its, wrap) in cypress.
Note: As mentioned earlier, you can't directly use its on the cy.get(). You need to extract the attributes from the object and use cy.wrap()
checkBox().then($el => {
cy.wrap($el[0].attributes)
.its('checked')
.should('exist')
})
you can use any of those methods, but the one I recommend is your first method.
cheers. Hope it helps.

Webdriver.io browser.getText() sometimes returns undefined

I have this piece of code:
getText: (selector) => {
browser.waitUntil(function () {
return browser.isExisting(selector) === true;
},timeout,
'Could not find element after: ' + timeout,
pollingTime);
return browser.getText(selector);
}
And sometimes this function (getText(selector), but in deep browser.getText(selector)) returns undefined for the selector that looks like this:
article[data-product-id="test-00020"] li.product-entry__summary__item.is-price span
This doesn't happen every time test is run, but it happens occasionally. It is driving me nuts because the behavior is inconsistent. Sometimes it works and sometimes it doesn't.
Did anybody have similar problems? Please help! Thank you.
getText is dependent on the element being visible in the viewport of the page (so if it's scrolled off the page it will return an empty string)
Instead, you can use getHTML(false) to get the text content of an element (just ensure it's the inner-most element, otherwise you'll get HTML elements in the returned content)
If you use getHTML which I also did, you can strip out the HTML tags if they are not innerHTML:
var strArray = browser.getHTML("//div[myxpath]");
for(var i =0; i<strArray.length; i++){
strArray[i]=strArray[i].replace(/(<([^>]+)>)/ig, "");
strArray[i] = strArray[i].trim();
}
sorry for the Hungarian notation.

Why evaluate() in Protractor?

When I run the below snippet, I got the following output. But I'm still unclear why and when evaluate() has to used ....
browser.get('https://weather.com/en-IN');
$$("input[data-ng-change='goSearch()']").evaluate('placeholderText').then(function(value) {
console.log(value);
});
evaluate() is rarely used, but has a unique purpose - it gives you an access to the scope of the current element you are working with. This is usually needed when a value you are looking for is not exposed in the HTML as an attribute or element's text.
For example, when you have a repeater over an array of objects and you need to access some object property that is not in the HTML:
element.all(by.repeater("address in addresses")).filter(function (elm) {
return elm.evaluate("address.zipCode").then(function (zipCode) {
return zipCode === "10801";
});
});

dojo Query the first matching element

Is there a specific syntax to query the first matching element in dojo?
I am currently using:
require (["dojo/query"], function (query) {
var foundNode = query (".className")[0];
});
Is there a more efficient way?
If you just want the first node of the NodeList as a DOM node object, then I think tha's the correct way to do it.
If you want to return the first DOM node as a NodeList, then you can use the first() function of dojo/NodeList-traverse. This means you can use further NodeList-operations. Read more about them at the reference guide.
The example below gives the first node of the NodeList a yellow background:
require(["dojo/query", "dojo/NodeList-traverse", "dojo/NodeList-dom", "dojo/domReady!"], function(query) {
query(".className").first().style({
"backgroundColor": "#FF0"
});
});
I also made a JSFiddle to demonstrate this.

KoLite asyncCommand accessing element data

So I'm displaying a observable array in my view, and I want to be able to remove an element from that list using asyncCommand. However, I'm not sure how I should be getting that element. Is there a way of accessing or passing the selected element into the asyncCommand method?
Thanks for the input
addGroupCmd = ko.asyncCommand({
execute: function (data, complete) {
//access your observable here with the data object
//EX. var demo = data.id();
},
canExecute: function (isExecuting) {
return !isExecuting && isEditing();
}
}),
Ok, so I figured it out with it little bit of google's help. All you have to do is pass in the data parameter and ko.lite will figure out what object your talking about. pretty nice, not really sure how it works, but it does.