I'm still a beginner in Protractor so forgive me if it is not the most optimized code. Although any advice and help are appreciated.
var orderno =["100788743","100788148","100788087","100000000","100786703"];
for (var i = 0; i < orderno.length; i++) {
(function(Loop) {
element(by.css('[autoid="_is_3"]')).sendKeys(orderno[i]);
browser.actions().sendKeys(protractor.Key.ENTER).perform();
expect(element(by.cssContainingText("span.Class", "Store A")).waitReady()).toBeTruthy();
element(by.cssContainingText("span.Class", "Store A")).isDisplayed().then(function(pickfail) {
if (pickfail) {
element(by.css('[class="highlight"]')).getText().then(function(text) {
console.log(text + "-" + "Pass");
});
} else {
console.log("Order Number: Missing");
}
});
element(by.css('[autoid="_is_3"]')).clear();
})([i]);
};
*waitReady is there to wait for the element to come up but I believe it its trying to find it but couldn't so it timesout.
I've created a test where I could input a value in a textbox which would search and check if it exists or not. If it does, it passes but if it doesn't, then fails. But want the loop to continue even if it fails to see if the other remaining items exist.
I think expect would fail when it couldn't find the value thus stopping the whole test. Is there another way to check and continue the whole checking?
Related
I’ll start with the code:
var s = ["hi"];
console.log(s);
s[0] = "bye";
console.log(s);
Simple, right? In response to this, the Firefox console says:
[ "hi" ]
[ "bye" ]
Wonderful, but Chrome’s JavaScript console (7.0.517.41 beta) says:
[ "bye" ]
[ "bye" ]
Have I done something wrong, or is Chrome’s JavaScript console being exceptionally lazy about evaluating my array?
Thanks for the comment, tec. I was able to find an existing unconfirmed Webkit bug that explains this issue: https://bugs.webkit.org/show_bug.cgi?id=35801 (EDIT: now fixed!)
There appears to be some debate regarding just how much of a bug it is and whether it's fixable. It does seem like bad behavior to me. It was especially troubling to me because, in Chrome at least, it occurs when the code resides in scripts that are executed immediately (before the page is loaded), even when the console is open, whenever the page is refreshed. Calling console.log when the console is not yet active only results in a reference to the object being queued, not the output the console will contain. Therefore, the array (or any object), will not be evaluated until the console is ready. It really is a case of lazy evaluation.
However, there is a simple way to avoid this in your code:
var s = ["hi"];
console.log(s.toString());
s[0] = "bye";
console.log(s.toString());
By calling toString, you create a representation in memory that will not be altered by following statements, which the console will read when it is ready. The console output is slightly different from passing the object directly, but it seems acceptable:
hi
bye
From Eric's explanation, it is due to console.log() being queued up, and it prints a later value of the array (or object).
There can be 5 solutions:
1. arr.toString() // not well for [1,[2,3]] as it shows 1,2,3
2. arr.join() // same as above
3. arr.slice(0) // a new array is created, but if arr is [1, 2, arr2, 3]
// and arr2 changes, then later value might be shown
4. arr.concat() // a new array is created, but same issue as slice(0)
5. JSON.stringify(arr) // works well as it takes a snapshot of the whole array
// or object, and the format shows the exact structure
You can clone an array with Array#slice:
console.log(s); // ["bye"], i.e. incorrect
console.log(s.slice()); // ["hi"], i.e. correct
A function that you can use instead of console.log that doesn't have this problem is as follows:
console.logShallowCopy = function () {
function slicedIfArray(arg) {
return Array.isArray(arg) ? arg.slice() : arg;
}
var argsSnapshot = Array.prototype.map.call(arguments, slicedIfArray);
return console.log.apply(console, argsSnapshot);
};
For the case of objects, unfortunately, the best method appears to be to debug first with a non-WebKit browser, or to write a complicated function to clone. If you are only working with simple objects, where order of keys doesn't matter and there are no functions, you could always do:
console.logSanitizedCopy = function () {
var args = Array.prototype.slice.call(arguments);
var sanitizedArgs = JSON.parse(JSON.stringify(args));
return console.log.apply(console, sanitizedArgs);
};
All of these methods are obviously very slow, so even more so than with normal console.logs, you have to strip them off after you're done debugging.
This has been patched in Webkit, however when using the React framework this happens for me in some circumstances, if you have such problems just use as others suggest:
console.log(JSON.stringify(the_array));
Looks like Chrome is replacing in its "pre compile" phase any instance of "s" with pointer to the actual array.
One way around is by cloning the array, logging fresh copy instead:
var s = ["hi"];
console.log(CloneArray(s));
s[0] = "bye";
console.log(CloneArray(s));
function CloneArray(array)
{
var clone = new Array();
for (var i = 0; i < array.length; i++)
clone[clone.length] = array[i];
return clone;
}
the shortest solution so far is to use array or object spread syntax to get a clone of values to be preserved as in time of logging, ie:
console.log({...myObject});
console.log([...myArray]);
however be warned as it does a shallow copy, so any deep nested non-primitive values will not be cloned and thus shown in their modified state in the console
This is already answered, but I'll drop my answer anyway. I implemented a simple console wrapper which doesn't suffer from this issue. Requires jQuery.
It implements only log, warn and error methods, you will have to add some more in order for it to be interchangeable with a regular console.
var fixedConsole;
(function($) {
var _freezeOne = function(arg) {
if (typeof arg === 'object') {
return $.extend(true, {}, arg);
} else {
return arg;
}
};
var _freezeAll = function(args) {
var frozen = [];
for (var i=0; i<args.length; i++) {
frozen.push(_freezeOne(args[i]));
}
return frozen;
};
fixedConsole = {
log: function() { console.log.apply(console, _freezeAll(arguments)); },
warn: function() { console.warn.apply(console, _freezeAll(arguments)); },
error: function() { console.error.apply(console, _freezeAll(arguments)); }
};
})(jQuery);
Ok this is an interesting one. I am sorting a list of users in Meteor and trying to return the index number of the user to the client. i.e. I want the first user created to be position 1, the second user created to be position 2, third user position 3, etc.
I am using a Meteor method on the server:
Meteor.methods({
setPosition: function(userId) {
let usersArray = Meteor.users.find({}, {sort: {createdAt: 1}}).fetch();
if (!this.userId) {
throw new Meteor.Error('not-authorized');
}
let pos = [];
for (i = 0; i < usersArray.length; i ++) {
if (usersArray[i]._id === this.userId) {
pos = i + 1;
}
console.log('this is the position', pos);
return pos;
};
}
}); //Meteor methods
}//end of meteor isServer
The server code above is working perfectly in the terminal EXCEPT the "return pos" line, which makes the code deliver the value to the client for the first user (I see position 1), but break for the subsequent users (res is undefined). If I remove the "return pos" line, then the code works perfectly on the server for ALL users, but I cannot get a single result from my Meteor method call on the client.
This client code below is having trouble receiving the result from the Method call on the server and I don't know why:
Tracker.autorun(() => {
Meteor.subscribe('position');
Meteor.call('setPosition', Meteor.userId(), (err, res) => {
if (err) {
throw new Meteor.Error(err.message);
console.log(err);
} else {
console.log(res);
console.log(Meteor.userId());
Session.set('position', res);
}
});
});
Also, I'm a newb so I apologize for any obvious formatting errors, please point out if you feel the need. Thank you!
Let's just say that this approach is unlikely to scale well as the more users you have the longer it's going to take to find a user's position in the list of users.
Assuming that a user's position never changes (i.e. you don't care about deletions - the 4th user is always 4th even if #3 gets deleted), you'd be better off adding a sequence key to the user object on user creation. You can look at the sequence number of the most recently created user and increment that by one to give it to the next user. You'll want that key to be indexed of course. Then each user can know their sequence number with just Meteor.user().sequence
I need to do an assertion to check if an element is present inside 'elements.all'.
My first idea is to run a for loop and put an expect inside. Not a great idea because it is checking every single items on list. So if I have 30 items, I might end up with 29 fails.
element.all(by.css(element)).then(function(itemList) {
console.log("Total values in dropdown are: " + itemList.length);
for (i = 0; i < itemList.length; i++) {
itemList[i].getText().then(function(text) {
console.log(text);
expect(text).toEqual('whatever-i-need-to-assert');
});
};
});
In order to solve this problem, I nest an IF statement that will 'pre-check' for a string match. Another bad idea because if there is no match, my expect will never run, thus, giving me a false pass:
element.all(by.css(".item a.gc-exercises-link")).then(function(itemList) {
console.log("Total values in dropdown are: " + itemList.length);
for (i = 0; i < itemList.length; i++) {
itemList[i].getText().then(function(text) {
console.log(text);
if (text == 'BOATLIFT-EXERCISE') {
console.log('Match');
expect(text).toEqual('BOATLIFT-EXERCISE');
} else {
console.log('No Match');
};
});
};
});
Clearly, I am in the wrong path here. Can someone give me an idea how to properly expect for a 'Text' when using element.all. I just need to prove that a text is present on the said list.
Thanks!
Here is an example to check that there is a link with the text "Terms" in a page :
browser.get('https://www.google.co.uk/');
expect(element.all(by.css('a')).getText()).toContain('Terms');
Note that for each element, protractor needs to interogate the browser, which could be slow especially if there is a lot of elements.
A quicker solution would be to check that at least one element is present with a XPath including the expected text:
browser.get('https://www.google.co.uk/');
expect(element.all(by.xpath("//a[text()='Terms']")).count()).toBeGreaterThan(0);
If you just want to check it's present (and other list item's won't interfere), you could call .getText() on the array after element.all, before .then and use toContain()
element.all(by.css(".item a.gc-exercises-link")).getText().then(function(itemList) {
expect(itemList).toContain('some text');
};
Or if you know the index:
element.all(by.css(".item a.gc-exercises-link")).getText().then(function(itemList) {
expect(itemList[3]).toEqual('some text');
}
As a side note: you can use .each() instead of creating a for loop https://angular.github.io/protractor/#/api?view=ElementArrayFinder.prototype.each
You can use filter function.
$$("span").filter(function(elem,index){
return elem.getText().then(function(txt){
return txt === 'text to compare';
});
}).then(function(eleList){ // you get the list of elements containing the text here
console.log(eleList.length);
});
So I have a program that sends emails. The user has a list of emails that cannot be sent to. These are in arrays and I need to use a if statement to determine if what the user entered in is in the array of emails. I tried the in function which didnt work but Im probably just using it wrong. I tried for loops and if statements inside. But that didnt work either. Here is a snapshot of the code Im using to help you get the idea of what im trying to do.
function test2(){
var safe = [1]
safe[1] = "lol"
safe[2] = "yay"
var entry = "lol"
Logger.log("entry: " + entry)
for(i = 0; i < safe.length; i++){
if(entry == safe[i]){
Logger.log("positive")
}else{
Logger.log("negative")
}
}
}
Here is what I tried with the in function to show you if I did it wrong
function test(){
var safe = [1]
safe[1] = "lol"
safe[2] = "yay"
var entry = "losl"
Logger.log("entry: " + entry)
if(entry in safe){
Logger.log("came positive")
}else{
Logger.log("came negative")
}
Logger.log(safe)
}
array.indexOf(element) > -1 usually does the trick for these situations!
To expand upon this:
if (array.indexOf(emailToSendTo) < 0) {
// send
}
Alternatively, check this cool thing out:
emailsToSend = emailsToSend.filter(function(x) {
// basically, this returns "yes" if it's not found in that other array.
return arrayOfBadEmails.indexOf(x) < 0;
})
What this does is it filters the list of emailsToSend, making sure that it's not a bad email. There's probably an even more elegant solution, but this is neat.
I want to get all names of files and directories from path and recognize them as files and directories. but When i run my code sometimes it works and somentimes it shows that directories are files. Here is the code
socket.on('data',function(path){
fs.readdir('path',function(err, data) {
var filestatus=[];
var z=0;
var i=data.length-1;
data.forEach(function(file){
fs.stat(file, function(err, stats) {
filestatus[z]=stats.isDirectory()
if (z==i){
socket.emit('backinfo',{names:data,status:filestatus});
}
z++;
})
})
})
})
During tests i realized that when i slow down data.forEach loop (using console.log(something) it works better(less miss). And this is strange.
This is about 96% incorrect, thank you to JohnnyHK for pointing out my mistake, see the comments below for the real problem / solution.
Because the fs.stat() function call is asynchronous, the operations on the filestatus array are overlapping. You should either use the async library as elmigranto suggested, or switch to using fs.statSync.
More details on what's happening:
When you call fs.stat(), it basically runs in the background and then immediately goes onto the next line of code. When it has got the details of the file, it then calls the callback function, which in your code is the function where you add the information to the filestatus array.
Because fs.stat() doesn't wait before returning, your program is going through the data array very quickly, and mutliple callbacks are being run simultanously and causing issues because the z variable isn't being incremented straight away, so
filestatus[z]=stats.isDirectory()
could be executed multiple times by different callbacks before z gets incremented.
Hope that makes sense!
you are using for statement in NODEJS and this will work if turned the For Statement to recursive function please see the attached code for help
function load_Files(pat,callback) {
console.log("Searching Path is: "+ph);
fs.readdir(pat,(err,files)=>
{
if(err)
{
callback(err);
}
else
{
var onlydir=[];
var onlyfiles=[];
var d=(index)=>
{
if (index==files.length)
{
console.log("last index: "+ index);
var ar=[];
ar.concat(onlydir,onlyfiles);
callback(null,ar);
return;
}
fs.stat(files[index],(err,status)=>
{
console.log("the needed file " +files[index]);
if (status.isDirectory())
{
onlydir.push(files[index]);
}
else
{
onlyfiles.push(files[index]);
}
console.log("only Directory: "+onlydir.length);
console.log("index: "+ index);
d(index+1);
}
)
}
d(0);
}
});
}