I'am a newbie with Nightwatch and i would like to count the number of element. I am able to do this but I don't understand how the variable is interpreted, here my code :
browser.elements('xpath', '/html/body/div[1]/div[3]/div[2]/div/div[1]/div/div[3]/table/tbody/tr/td[2]', function (elements) {
var nb = 0
elements.value.forEach(function (elementsObj, index) {
browser.elementIdText(elementsObj.ELEMENT, function (result) {
if (result.value != "") {
nb = nb + 1
console.log(result.value)
}
//console.log("There are : " + nb)
})
//console.log("There are : " + nb)
})
This display all elements I want. The output is :
Element 1
Element 2
and so on...
Now, I would like to have this :
There are X elements :
Element 1
Element 2
And so on...
But I try to print my variable "nb" but it doesn't work... How can I store and display my "nb" variable ?
Thanks,
My guess is that those commented console.log when not commented are executed before your loop ends... and therefore they are most likely returning :
"There are : 0"
Have you tried to "await" for the forEach loop to end?
Maybe something like:
browser.elements('xpath', '/html/body/div[1]/div[3]/div[2]/div/div[1]/div/div[3]/table/tbody/tr/td[2]', function (elements) {
var nb = 0
elements.value.forEach(async function (elementsObj, index) {
await browser.elementIdText(elementsObj.ELEMENT, function (result) {
if (result.value != "") {
nb = nb + 1
console.log(result.value)
}
//console.log("There are : " + nb)
})
console.log("There are : " + nb)
})
You can store the values in an array. And then parse the length after the forEach loop is completed. something like this:
browser.elements('xpath', '/html/body/div[1]/div[3]/div[2]/div/div[1]/div/div[3]/table/tbody/tr/td[2]', function (elements) {
var nb = []
elements.value.forEach(function (elementsObj, index) {
browser.elementIdText(elementsObj.ELEMENT, function (result) {
if (result.value != "") {
console.log(result.value)
nb.push(result.value)
}
})
})
console.log('There are ' + nb.length() + 'elements')
for (const nbItem of nb) {
console.log(nbItem)
}
})
Related
I want to confirm that each my string have text 'Operational'. Here is my code
module.exports = {
test: function (client) {
var text1;
client
.maximizeWindow()
.url('https://status.gitlab.com/')
.waitForElementVisible('img[alt="Logo"]', 10 * 1000)
.elements('css selector', '.component',
function (elements) {
elements.value.forEach(function (elementsObj) {
client.elementIdText(elementsObj.ELEMENT, function (result) {
text1 = result.value
text1 = text1.replace(/\s+/g, '')
console.log(text1);
client.assert.containsText(text1, 'Operational')
})
})
})
}
};
When I run this I receive error - Testing if element <WebsiteGoogleComputeEngineOperational> contains text 'Operational' in 5000ms - expected "contains text 'Operational'" but got: "element could not be located" (5341ms)
When I run without client.assert.containsText(text1, 'Operational') I receive full list of my strings
WebsiteGoogleComputeEngineOperational
APIGoogleComputeEngineOperational
Git(sshandhttps)GoogleComputeEngineOperational
PagesGoogleComputeEngineOperational
CI/CDGoogleComputeEngineOperational
BackgroundProcessingGoogleComputeEngineOperational
SupportServicesZendeskOperational
packages.gitlab.comAWSOperational
customers.gitlab.comAzureOperational
version.gitlab.comAWSOperational
forum.gitlab.comDigitalOceanOperational
WindowsRunners(beta)GoogleComputeEngineOperational
CanaryGoogleComputeEngineOperational
dashboards.gitlab.comGoogleComputeEngineOperational
Where is the problem and how I can resolve this?
You cannot use client.assert.containsText(text1, 'Operational') as this is meant for validating the innertext of the element. What you're doing is comparing two texts for which you can use a simple if- else.
module.exports = {
test: function(client) {
var text1;
client
.maximizeWindow()
.url('https://status.gitlab.com/')
.waitForElementVisible('img[alt="Logo"]', 10 * 1000)
.elements('css selector', '.component',
function(elements) {
elements.value.forEach(function(elementsObj) {
client.elementIdText(elementsObj.ELEMENT, function(result) {
text1 = result.value.replace(/\s+/g, '')
if (text1.includes('Operational')) {
console.log('Found Operational in - ' + '"' + text1 + '"' + '\n')
} else {
console.log('Didn\'t Found Operational in - ' + '"' + text1 + '"' + '\n')
}
})
})
})
}
};
Upon Execution, you can see something like this in console -
I'm making a simple twitter app to work on my javascript.
The code below is supposed to identify every tweets location and count the number of tweets per location.
However, it doesn't increment, it just creates a new array.
What is wrong with my code? How can I make it better?
Thank you
var Twitter = require('node-twitter'),
twit = {},
loc = [];
twit.count = 0;
var twitterStreamClient = new Twitter.StreamClient(
//credentials
);
twitterStreamClient.on('close', function () {
console.log('Connection closed.');
});
twitterStreamClient.on('end', function () {
console.log('End of Line.');
});
twitterStreamClient.on('error', function (error) {
console.log('Error: ' + (error.code ? error.code + ' ' + error.message : error.message));
});
twitterStreamClient.on('tweet', function (tweet) {
if (loc.indexOf(tweet.user.location) === -1) {
loc.push({"location": tweet.user.location, "locCount": 1});
} else {
loc.loation.locCount = loc.loation.locCount + 1;
}
console.log(loc);
});
var search = twitterStreamClient.start(['snow']);
You need to rewrite on tweet callback:
var index = loc.reduce(function(acc, current, curIndex) {
return current.location == tweet.user.location ? curIndex : acc;
}, -1);
if (index === -1) {
loc.push({"location": tweet.user.location, "locCount": 1});
} else {
loc[index].locCount++;
}
Array.indexOf is not matching as you think it is. You're creating a new object and pushing it into the array, and regardless of whether its properties match a different object perfectly, it will not be === equal. Instead, you have to find it manually:
var foundLoc;
for (var i = 0; i < loc.length; i++) {
if (loc[i].location.x === location.x)
foundLoc = loc[i];
break;
}
}
if (!foundLoc) {
loc.push({location: location, count: 0});
} else {
foundLoc.count++
}
Simply my code looks like this:
var thevariable = 0;
For(){
//somecode using thevariable
$.getJSON('',{},function(e){
//success and i want to set the returned value from php to my variable to use it in the forloop
thevariable = e.result;
});
}
my main problem that the variable value stays "0", during the whole For loop, while i only want it to be "0" at the first loop, then it takes the result returned from PHP to use it on for loop.
here it my real code if you need to take a look:
var orderinvoice = 0;
for(var i=0; i<table.rows.length; i++){
var ordername = table.rows[i].cells[5].innerText;
var orderqty = ((table.rows[i].cells[1].innerText).replace(/\,/g,'')).replace(/Qty /g,'');
var orderprice = (table.rows[i].cells[2].innerText).replace(/\$/g,'');
var ordertype = table.rows[i].cells[3].innerText;
var orderlink = table.rows[i].cells[4].innerText;
$.getJSON('orderprocess.php', {'invoice': orderinvoice, 'pay_email': email, 'ord_name': ordername, 'ord_qty': orderqty, 'ord_price': orderprice, 'ord_type': ordertype, 'ord_link': orderlink}, function(e) {
console.log();
document.getElementById("result").innerText= document.getElementById("result").innerText + "Order #"+e.result+" Created Successfully ";
document.getElementById("invoker").innerText = ""+e.invoice;
orderinvoice = e.invoice;
if(i+1 == table.rows.length){
document.getElementById("result").innerText= document.getElementById("result").innerText + "With invoice #" + e.invoice;
}
});
in a loop block, before one ajax complete other one will be run and this's javascript natural treatment. For your case you can call a function at the end of success event. Do something like this:
var i = 0;
doSt();
function doSt() {
var orderinvoice = 0;
var ordername = table.rows[i].cells[5].innerText;
var orderqty = ((table.rows[i].cells[1].innerText).replace(/\,/g, '')).replace(/Qty /g, '');
var orderprice = (table.rows[i].cells[2].innerText).replace(/\$/g, '');
var ordertype = table.rows[i].cells[3].innerText;
var orderlink = table.rows[i].cells[4].innerText;
$.getJSON('orderprocess.php', { 'invoice': orderinvoice, 'pay_email': email, 'ord_name': ordername, 'ord_qty': orderqty, 'ord_price': orderprice, 'ord_type': ordertype, 'ord_link': orderlink }, function(e) {
console.log();
document.getElementById("result").innerText = document.getElementById("result").innerText + "Order #" + e.result + " Created Successfully ";
document.getElementById("invoker").innerText = "" + e.invoice;
orderinvoice = e.invoice;
if (i + 1 == table.rows.length) {
document.getElementById("result").innerText = document.getElementById("result").innerText + "With invoice #" + e.invoice;
}
i++;
if (i < table.rows.length) doSt();
});
}
I think you need a recursive function that always deals with the first element in your rows array and then splices it off and calls itself. For example, something like this:
function getStuff(rows, results) {
if (rows.length > 0) {
var ordername = rows[0].cells[5].innerText;
$.getJSON('orderprocess.php', { 'ord_name': ordername }, function (e) {
// do some stuff
results.push('aggregate some things here?');
rows.splice(0, 1);
return getStuff(rows, results);
});
} else {
return results;
}
}
When the array is spent, results will be returned with whatever aggregate you wanted at the end of the cycle. Then, you can do as you please with the results. I think you can also manipulate the DOM inside the function as you see fit if that makes more sense. Hope this helps.
So basically I have some promise, forEach, just a lot of issues with this single problem I need to solve. So the variables I work with has below structure:
persons = [object, object, object]
where each object has { user:number , username: string, latitude:number, longitude:number}
from there I try to figure out if my user/username is inside of one of these objects, if not found id like it to be created, if found found id like it to update their location. Sounds simple, I think the problem has blown out of proportion but nothing works. The code I have now does not work, its either I can never figure out when the user is not there, or I can not figure out how to get to stop creating me every time it find a user who is not me.
var getswamp = function(item, index) {
return new Promise(function(resolve, reject){
var result = false;
if (item.user === user && item.username === username) {
if ((item.latitude !== latitudenew) || (item.longitude !== longitudenew)) {
var id = item.id;
swampdragon.update('locationcurrent', {
user: user,
latitude: latitudenew,
longititude: longitudenew,
username: username,
id: id
}, function (context, data) {
console.log("data updated", data);
result = true;
resolve(result);
}, function (context, data) {
console.log("You may not be updated");
});
} else {
console.log("No location change");
result = true;
}
}else{
if ( item.index === person.index){
console.log(person);
resolve(result)
}
}
});
};
person.forEach(function (item, index) {
var swamping = getswamp(item, index);
swamping.then(function (result) {
console.log(result);
if (result === true) {
console.log("We have you");
} else if (result === false && (index === person.length - 1)) {
console.log('Index: ' + index + ' Length of list is ' + person.length);
swampdragon.create('locationcurrent', {
user: user,
latitude: latitudenew,
longititude: longitudenew,
username: username
}, function (context, data) {
console.log("data created", data);
}, function (context, data) {
console.log("You may not be created")
});
}
})
});
Any help/ideas would just be great.
The Promise is used when some asynchronous event happened.
Since I can not create such event, I made a static code as below:
var persons = new Array();
persons.indexOf = function(person) {
var index = -1;
this.forEach(function(obj, i) {
if (person.username == obj.username) {
index = i;
}
});
return index;
}
persons.addOrUpdate = function(person) {
var index = this.indexOf(person);
if (index == -1) {
person.user = this.length + 1;
this.push(person);
}
else { // update case
var obj = this[index];
obj.latitude = person.latitude;
obj.longitude = person.longitude;
}
}
persons.print = function() {
var str = "";
this.forEach(function(obj) {
str += obj.user + ". " + obj.username + " at location (" +
obj.latitude + ":" + obj.longitude + ")\n";
});
return str;
}
persons.addOrUpdate({username:'Adam', latitude:-0.0045, longitude:14.2015});
persons.addOrUpdate({username:'Eve', latitude:-0.0045, longitude:14.2015});
persons.addOrUpdate({username:'Abel', latitude:-0.0045, longitude:14.2015});
// Updating Able location
var person = {username:'Abel', latitude:10.1145, longitude:14.1234};
persons.addOrUpdate(person);
alert(persons.print());
I have an object containing an array:
<script type="text/javascript">
var statusData = {
Status: []
};
var uniqueCounter = 1
function createJsonFmtData() {
// Used as unique id at client side
var uniqueCounter =uniqueCounter + 1;
statusData.Status.push({
"Name": Name,
"Time": Time,
"Email": Mail,
"Name": Type,
"Value": Value,
"uniqueId": uniqueCounter
});
}
function DelNewlyCreStatusRow(rowId) {
// First pop elment from json data
var val;
for (val = 0; val < statusData.Status.length; ++val) {
if (statusData.Status[val].uniqueId == rowId) {
delete statusData.Status[val];
break;
}
}
</script>
When try to call DelNewlyCreStatusRow it gives the error:
TypeError: statusData.Status[val] is undefined
I am not able to figure it out here where as I have declared it as global.
This is because you are trying to delete from the array incorrectly. delete operator is quite funny on arrays. It replaces element with undefined. Check this out:
>>> var A = [1, 2, 3];
>>> delete a[1];
>>> A;
[1, undefined, 3];
Thus calling DelNewlyCreStatusRow multiple times will throw an exception, because statusData.Status[val].uniqueId cannot be evaluated ( statusData.Status[val] is undefined ).
To fix this use this code instead of delete:
var val;
for (val = 0; val < statusData.Status.length; ++val) {
if (statusData.Status[val].uniqueId == rowId) {
statusData.Status.splice( val, 1 );
break;
}
}
Note that splice modifies an array, so if you want to do multiple deletes in one go, then you will have to replace for loop with while ( and refactor the code a bit ). This is not needed here because of break statement.
You should replace
delete statusData.Status[val];
with
statusData.Status.splice(val,1);
val -= 1;
to remove an object in an array.
The function DelNewlyCreStatusRow missing a closing '}'
function DelNewlyCreStatusRow(rowId) {
// First pop elment from json data
var val;
for (val = 0; val < statusData.Status.length; ++val) {
if (statusData.Status[val].uniqueId == rowId) {
delete statusData.Status[val];
break;
}
}
}
You made an Error in your Code at the second var declaration inside the Function.
var uniqueCounter = uniqueCounter + 1 => NAN + 1.
You dont need the var a Second time so it's just
uniqueCounter = uniqueCounter + 1 => 2.
Then delete works fine in my Case.
<script type="text/javascript">
var statusData = {
Status : []
};
var uniqueCounter = 1
function createJsonFmtData() {
var statusName = $('#<%= ddlStatus.ClientID %> option:selected').text();
var dateTime = $("#body_ctl04_ctl02").val();
var forceMail = ($("#chkForceMail").is(':checked')) ? 1 : 0;
var noteType = $('#divTrackId').text();
var dataValue = $("#<%=txtTrackId.ClientID %>").val();
var curLogedUserName = $("#<%=curLoginUserName.ClientID %>").val();
// Used as unique id at client side
uniqueCounter = uniqueCounter + 1;
statusData.Status.push({
"statusName" : statusName,
"dateTime" : dateTime,
"forceEmail" : forceMail,
"typeName" : noteType,
"dataValue" : dataValue,
"uniqueId" : uniqueCounter
});
}
function DelNewlyCreStatusRow(rowId) {
// First pop elment from json data
var val;
for ( val = 0; val < statusData.Status.length; ++val) {
if (statusData.Status[val].uniqueId == rowId) {
console.log(typeof(statusData.Status[val]));
delete statusData.Status[val];
break;
}
}
}
createJsonFmtData();
console.log(statusData);
DelNewlyCreStatusRow(2);
console.log(statusData);
</script>