This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 5 years ago.
I'm trying to check that a list of elements from a column on a webpage are in descending order. I come from a Java background so I'm still trying to figure out why this wont work. To my knowledge when it hits that final expect, isDescending should be properly set, but instead it never changes from what I initialize it as.
I've put print statements in the loop previously and everything is working fine in there.
I did some digging and it probably has to do with either it running the expect at the bottom before it finishes the loop, or isDescending is not actually getting set properly for some reason.
I tried a number of things like setTimeout and others but nothing fixed the issue.
Here is the below code, looking for any suggestions or link to pages where I can research more.
function checkIfDescending(){
// Will hold list of webelements that each have one account number
const accountNumbersDescending = pa_search.account_no_column_elements();
let previousDescendingValue = '';
let isDescending = true;
accountNumbersDescending.each((accountNumberElement) => {
accountNumberElement.getText().then((text) => {
if (previousDescendingValue !== '') {
if (!(text >= previousDescendingValue)) {
isDescending = false;
}
}
previousDescendingValue = text;
});
});
expect(isDescending).toBe(true);
}
As a final note, if I put the expect within the if statement, it properly works. Problem is that it then will run several times if there is a failure early on.
Thanks to Mark Schultheiss for leading me to this answer.
I'm not 100% it's the right way to do things but it probably passes/fails now.
function checkIfDescending(){
const accountNumbersDescending = pa_search.account_no_column_elements();
let previousDescendingValue = '';
let isDescending = true;
accountNumbersDescending.each((accountNumberElement) => {
accountNumberElement.getText().then((text) => {
if (previousDescendingValue !== '') {
if (!(text >= previousDescendingValue)) {
isDescending = false;
}
}
previousDescendingValue = text;
})
}).then(() => {
expect(isDescending).toBe(true);
});
}
You can take a look at chai-increasing plugin.
You need to store values in an array or a promise and make an expect assertion.
Related
This question already has answers here:
Is it possible to use .contains() in a switch statement?
(2 answers)
Closed 2 years ago.
I've got this code
if (header.classList.contains("capricorn")) {
//star sign description
para.innerHTML = starSign.Capricorn;
} else if (header.classList.contains("aquarius")) {
para.innerHTML = starSign.Aquarius;
} else if (header.classList.contains("pisces")) {
para.innerHTML = starSign.Pisces;
I want to turn it in a switch statement, is that possible?
Consider parameterizing your checks instead, based on the properties of starSign object:
function chooseSign(classList, signs) {
return signs.find(s => classList.contains(s.toLowerCase());
}
... and using it accordingly:
const sign = chooseSign(header.classList, Object.keys(starSign));
if (sign) {
para.innerHTML = starSign[sign];
}
I assumed starSign is a collection of texts with only 12 keys. If that's not the case, consider making a separate array out of those.
In general, when you have a looooong series of if - else if - else if checks doing essentially the same stuff over and over, think about using separate function for the same purpose. Not only this gives you a chance to simplify the code (like in this example), but also isolates the business logic decision making your code both more readable and more testable.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I am fairly new to javascript and I am learnig by doing a project.
I have a situtation in which I collect statuses of various tasks to an array.
var statuses = ["deployed", "deployed", "pending", "staged"];
now I want to call clearInterval(interval) when all the items in the array are deployed
var statuses = ["deployed", "deployed", "pending", "staged"];
if(statuses.every(x=>x === "deployed")){
//clearInterval(interval);
}
console.log(statuses.every(x=>x === "deployed"))
You can use every to check if all elements in array are deployed. The above code is based solely on your description I want to call clearInterval(interval) when all the items in the array are deployed
Use the every method:
if (statuses.every(status => status === "deployed")) {
clearInterval(interval);
}
Iterate over 'statuses', checking each current value for NOT "deployed". The first time that condition is met, you know you do not need to perform the 'clearInterval' logic. This means that if the condition is never met, you can proceed with that logic.
So here is what I think you should do, and it works pretty well. Ill break everything down so it makes sense.
/// I just dont like using strings when ints will suffice, so im using 0,1,2 instead of your defined strings.
var valueRef = { 0: "Deployed", 1: "Pending", 2: "Staged" };
/// Info contains your sample data.
var info = [0,0,1,2]
/// This will be needed to clear the repeating fn call
var timeoutKey;
function checkIfAllDeployed(){
/// Get the size of your info array
var len = info.length;
for (index in info){
/// Loop through all items in the array to check to see if they are 0 (deployed)
if (info[index] == 0){
/// it is 0, subtract 1.
len --;
}
}
/// since you have the length (this sample is 4), when the function finally runs and they are all deployed, then len will now be 0 here.
if (len <= 0){
/// Turn off the timeout.
clearTimeout(timeoutKey);
}
/// I use bind so that what the scope is the same as the parent, so it has access to timeoutKey
}.bind(this);
/// Sets your timeout. This is where you kick it all off at. It will run at an interval of whatever you want. 1000 == 1 second. So 500 = 0.5 seconds.
timeoutKey = setInterval(checkIfAllDeployed, 500)
Now, that covers loops, but since you are doing ES6, there are some cool tricks such as the every function for arrays. It takes a function to compare.
var timeoutKey
function checkIfAllDeployed(){
if (info.every(function(item){ return item == 0}){
clearTimeout(timeoutKey)
}
}
setInterval(checkIfAllDeployed, 500);
Or if you want to use shorthand:
var timeoutKey
function checkIfAllDeployed(){
/// Now in my example, i use 0, but you can use the string "deployed" here.
if (info.every(x => x == 0){
clearTimeout(timeoutKey)
}
}
setInterval(checkIfAllDeployed, 500);
Now the reason I use INTS etc is that it takes up less space. There are far less strings. Imagine a HUGE array of strings. Not too good, but with a map you can easily rereference.
If you decide you every need data for a given row you can just say:
valueRef[info[index]]
and it will give you the String you are looking for. This is kinda like an enum, Which you could also used if you wanted. Since you have a static set of states, you could just create an enum and it would work similar to the map example i gave you.
Ciasto!
From my understanding, you are just trying to iterate through the statuses array and verify that each element of that array only contains the strings "deployed". This code below is a simple implementation of that and I've inserted a few console log statements to help show the logic of stepping through the process.
function isDeployed(array) {
for (var i = 0; i < statuses.length; i++) {
if (statuses[i] !== 'deployed') {
return false;
}
}
return true;
}
var statuses = ["deployed", "deployed", "pending", "staged"];
// var statuses = ["deployed", "deployed", "deployed", "deployed"];
var result = isDeployed(statuses);
console.log(result);
if (result) {
console.log('Add more code to deal with your next steps');
}
Let me know if you need further clarification or if this isn't quite what you were asking!
This question already has answers here:
Merge sort, the recursion part
(3 answers)
Closed 5 years ago.
I am trying to understand the recursion in merge sort.
// merge sort
var arr = [1,5,3,0];
function mergeSort(arr) {
if(arr.length == 1)
return arr;
if(arr.length > 1) {
let breakpoint = Math.ceil((arr.length/2));
// Left list starts with 0, breakpoint-1
let leftList = arr.slice(0,breakpoint);
// Right list starts with breakpoint, length-1
let rightList = arr.slice(breakpoint,arr.length);
// Make a recursive call
leftList = mergeSort(leftList);
rightList = mergeSort(rightList);
var a = merge(leftList,rightList);
return a;
}
}
function merge(leftList,rightList) {
let result = [];
while(leftList.length && rightList.length) {
if(leftList[0] <= rightList[0]) {
result.push(leftList.shift());
}else{
result.push(rightList.shift());
}
}
while(leftList.length)
result.push(leftList.shift());
while(rightList.length)
result.push(rightList.shift());
return result;
}
console.log(mergeSort(arr));
The program works fine, but I do not understand the recursion here. In spite of having multiple return statements, why does the program only print :
[0,1,3,5]
How does the result get printed, how the recursion is working here?
The program prints only once, because there is only one output statement in the entire logic flow: when mergeSort returns the final, sorted array to the main program, that result comes back as the value for the one and only console.log call.
Remember that a return sends program control back to the spot that called that instance of the function. merge is called only from the bottom of mergeSort. However, mergeSort gets called from the main program and from two places within itself. For the given example, you will sometimes have three instances of mergeSort on the stack at the deepest point. The two higher ones will return to their call points within mergeSort; only the original will return to the main program's log command.
I need to push value in array and stored in cookies when user click on GO button.
if value is more than 10 i need to remove the first added item in the array and updated cookies , displayed in front end.
but i'm tried multiple ways some time i am getting values sometimes not , the code is not consistently working.
please find below the code
var cookieName = 'orderList';
$scope.orderList = $cookies.getObject(cookieName) || [];
$scope.saveCookie = function (val) {
if ($scope.orderList.length >= 10) {
$scope.orderList.shift();
}
$scope.orderList.push({productName: val});
$scope.orderList = $cookies.putObject(cookieName,$scope.orderList);
}
Note : I am using angular 1.5 and cookie 1.5 version .and i am getting console error .
http://plnkr.co/edit/K17uJv72U2ytG6JHZBtn?p=preview
You didn't realize one thing. The error only appears when you click the button the second time.
The reason why you're getting this error is the last line in your code-
$scope.orderList = $cookies.putObject(cookieName,$scope.orderList);
when you replace it with -
console.log(typeof $cookies.putObject(cookieName,$scope.orderList));
you'll get undefined in the console. And that is the catch. When the function runs the second time, it is evaluating length of undefined, and hence, the error.
Just replace the line with $cookies.putObject(cookieName,$scope.orderList), because your $scope.orderList is already equal to the array with the new value pushed.
EDIT:
Updated Code
var cookieName = 'orderList';
$scope.saveCookie = function (val) {
$scope.orderList = $cookies.getObject(cookieName) || [];
if ($scope.orderList.length >= 10) {
$scope.orderList.shift();
}
$scope.orderList.push({productName: val});
$cookies.putObject(cookieName,$scope.orderList);
}
I brought the definition of $scope.orderList inside the function, since, in case the value of it is lost, it will reevaluate on each button click. Its not crucial in all cases. You might keep it out of the function, depending on your application flow.
This question already has an answer here:
CasperJS posting only the last item multiple times from my for-loop
(1 answer)
Closed 6 years ago.
Im using phantomjs and casperjs to test out my website.
In my JavaScript I have a for loop using var i, and another var rando inside the loop which increments.
I am calling
console.log(i);
console.log(rando);
for testing, but it does not print the correct value to the command line. However, I know that the variable is changing, as the code does as intended, for example the for loop is incrementing.
I tried using
console.log("%d", i);
but no luck.
My Code using a suggested solution still no luck:
for (i=0; i<100000; i++) { //// first loop
casper.wait(13000, function () {
casper.then(function () {
console.log(String.valueOf(i));
console.log(String.valueOf(rando));
casper.click(x(('/html/body/div[2]/div/div[2]/div/article/div[2]/section[2]/a/span')));
console.log(timeStamp());
});
});
casper.then(function () {
casper.click(x(('/html/body/div[2]/div/div[1]/div/div/a[2]')));
});
if (rando == 14) {
casper.then(function () {
casper.click(x(('/html/body/div[2]/div/div[2]/div/article/header/span/button')));
console.log(timeStamp());
});
rando = 0;
} else {
rando++;
}
}
The result is printing i as 100000 and rando as 10 every time, even when they are incremented.
Try to use
console.log(String.valueOf(i))
If didn't work please show your code
You are probably not handling the promises that the methods to get values from the DOM return.
"Crawling" frameworks massively use promises, to retrieve values from the DOM, because most of the times those values are changed dynamically and are not available as soon as the DOM is retrieved to the client.
more info about Promises here
This is an old gist i made using webdriverjs wich is similar to casper/phantom: link to gist. I specifically made this gist to pratice promise handling.