How can we resolve promise to a normal number value .
I have use case in protractor automation in the first i have to call a asynchronous operation then that result value which should not be a promise .
I am using protractor framework
EDIT
var mobileNumber = database.generateMobileNumber().then(function(mobileNumber){
done();
return mobileNumber;
});
var number=Promise.resolve(mobileNumber);
Not quite sure why you might want to work with non-promise values, but i think you should play with browser.wait()
I didn't checked this, test this code to see if it will work.
This approach is bad, think twice before use it:
function getMobileNumber() {
var result;
var promise = database.generateMobileNumber().then(mobileNumber=> {
result = mobileNumber;
return true;
});
browser.wait(promise, 10000)
return result;
}
How about this ? You can find in this article more information about managing promises with protractor.
var mobileNumber = database.generateMobileNumber().then(function(mobileNumber){
done();
var deferred = protractor.promise.defer();
return deferred.fulfill(mobileNumber);
});
EDIT
var mobileNumber = database.generateMobileNumber().then(function(value){
done();
var deferred = protractor.promise.defer();
return deferred.fulfill(value);
});
the previous one is not clean as the same name (mobileNumber) is used in two different contexts. I don't know the result of this.
Related
When spying on a method, we can either callThrough (use original implementation) or callFake (use a custom implementation).
What I want is a behaviour similar to callThrough but inspect/modify its return value before returning it to the caller.
So I can do something like this:
spyOn(foo, "fetch").and.afterCall(function(result) {
expect(result).toBeDefined();
result.bar = "baz";
return result;
});
Right now the simplest way is doing something like this:
var original = foo.fetch;
foo.fetch = function() {
var result = original.apply(this, arguments);
expect(result).toBeDefined();
result.bar = "baz";
return result;
}
Which is somewhat annoying because now I have to manually restore the spy instead of having the framework automatically does it for me.
Does Jasmine have an after-advice spy?
Generally: no.
You could extend the SpyStrategy object with such a function though:
this.callThroughAndModify = function(resultModifier) {
var result;
plan = function() {
result = originalFn.apply(this, arguments);
return resultModifier(result);
};
return getSpy();
};
You've to clone the above SpyStrategy file and insert that method.
Usage:
var obj = {
fn: function(a) { return a * 2; }
};
spyOn(obj, "fn").and.callThroughAndModify(function(result) {
console.log("Original result: ", result);
return 1;
});
expect(obj.fn(2)).toBe(1);
Drawbacks:
You've to replace the whole SpyStrategy.js
You've to load that script before Jasmine initializes the original SpyStrategy at boot
I have the following code to handle double taps...
var onClick = function (e) {
if ((d3.event.timeStamp - last) < 500) {
return callback(e);
}
last = d3.event.timeStamp;
};
But this returns...
{
"uuid":"e2befb22-849b-4b56-91b4-8c297311491b",
"title":"JRG-024",
"weight":3,
"x":-4120.238083042915,
"y":2759.9261895569307,
"px":-4102.444457966419,
"py":2753.0045790866943
}
Notice the x,y,px,py, etc I want to avoid these and get the clean data that was originally bound. I also tried return callback(d3.select(this).data()[0]) but this still returns the location data. Is there a way to remove this data from the response, short of filtering?
Here's an example based on my comment
d3.select('body')
.selectAll('.data')
.data([10,20,30])
.enter()
.append('div')
.attr('class', 'data');
var node = d3.select('.data').node();
console.log(node.__data__);
The console output is 10
I ended up just putting everything in a property and passing it like that. Something similar to this...
var d3Data = data.map(function(item){
var result = {
...
originalData : item
}
return result
})
Not accepting because it is hacky hacky hacky.
Is there a way to globally and automatically modify a message before emitting it? Something along the lines of jQuery ajax's beforeSend.
Right now, I'm manually adding a timestamp to the payload for each emit and it would be much less error-prone to have that done automatically.
Thanks!
You can either override the .emit() method (saving the original so you can call it) or if you control all the code that calls .emit(), then just make your own method that adds the timestamp to the payload and then calls .emit().
To patch the original .emit(), you could do this:
(function() {
var origEmit = Socket.prototype.emit;
Socket.prototype.emit = function(msg, data) {
if (typeof data === "object") {
data.timeStamp = Date.now();
}
return origEmit.apply(this, arguments);
}
})();
To create your own emit method that all your code could use, you could do this:
Socket.prototype.emitT = function(msg, data) {
if (typeof data === "object") {
data.timeStamp = Date.now();
}
return this.emit.apply(this, arguments);
}
I'm pretty new to CasperJS, but isn't there a way to open a URL and execute CasperJS commands in for loops? For example, this code doesn't work as I expected it to:
casper.then(function() {
var counter = 2013;
for (i = counter; i < 2014; i++) {
var file_name = "./Draws/wimbledon_draw_" + counter + ".json";
// getting some local json files
var json = require(file_name);
var first_round = json["1"];
for (var key in first_round) {
var name = first_round[key].player_1.replace(/\s+/g, '-');
var normal_url = "http://www.atpworldtour.com/Tennis/Players/" + name;
// the casper command below only executes AFTER the for loop is done
casper.thenOpen(normal_url, function() {
this.echo(normal_url);
});
}
}
});
Instead of Casper is calling thenOpen on each new URL per iteration, it gets only called AFTER the for loop executes. Casper thenOpen then gets called with the last value normal_url is set to. Is there no Casper command to have it work each iteration within the for loop?
Follow up: How do we make casper thenOpen return a value on the current iteration of the for loop?
Say for example, I needed a return value on that thenOpen (maybe if the HTTP status is 404 I need to evaluate another URL so I want to return false). Is this possible to do?
Editing casper.thenOpen call above:
var status;
// thenOpen() only executes after the console.log statement directly below
casper.thenOpen(normal_url, function() {
status = this.status(false)['currentHTTPStatus'];
if (status == 200) {
return true;
} else {
return false;
}
});
console.log(status); // This prints UNDEFINED the same number of times as iterations.
If you need to get context then use the example here:
https://groups.google.com/forum/#!topic/casperjs/n_zXlxiPMtk
I used the IIFE (immediately-invoked-function-expression) option.
Eg:
for(var i in links) {
var link = links[i];
(function(index) {
var link = links[index]
var filename = link.replace(/#/, '');
filename = filename.replace(/\//g, '-') + '.png';
casper.echo('Attempting to capture: '+link);
casper.thenOpen(vars.domain + link).waitForSelector('.title h1', function () {
this.capture(filename);
});
})(i);
}
links could be an array of objects and therefore your index is a reference to a group of properties if need be...
var links = [{'page':'some-page.html', 'filename':'page-page.png'}, {...}]
As Fanch and Darren Cook stated, you could use an IIFE to fix the url value inside of the thenOpen step.
An alternative would be to use getCurrentUrl to check the url. So change the line
this.echo(normal_url);
to
this.echo(this.getCurrentUrl());
The problem is that normal_url references the last value that was set but not the current value because it is executed later. This does not happen with casper.thenOpen(normal_url, function(){...});, because the current reference is passed to the function. You just see the wrong url, but the correct url is actually opened.
Regarding your updated question:
All then* and wait* functions in the casperjs API are step functions. The function that you pass into them will be scheduled and executed later (triggered by casper.run()). You shouldn't use variables outside of steps. Just add further steps inside of the thenOpen call. They will be scheduled in the correct order. Also you cannot return anything from thenOpen.
var somethingDone = false;
var status;
casper.thenOpen(normal_url, function() {
status = this.status(false)['currentHTTPStatus'];
if (status != 200) {
this.thenOpen(alternativeURL, function(){
// do something
somethingDone = true;
});
}
});
casper.then(function(){
console.log("status: " + status);
if (somethingDone) {
// something has been done
somethingDone = false;
}
});
In this example this.thenOpen will be scheduled after casper.thenOpen and somethingDone will be true inside casper.then because it comes after it.
There are some things that you need to fix:
You don't use your counter i: you probably mean "./Draws/wimbledon_draw_" + i + ".json" not "./Draws/wimbledon_draw_" + counter + ".json"
You cannot require a JSON string. Interestingly, you can require a JSON file. I still would use fs.read to read the file and parse the JSON inside it (JSON.parse).
Regarding your question...
You didn't schedule any commands. Just add steps (then* or wait*) behind or inside of thenOpen.
I'm attempting to write tests around a form that uses Angular.
After following this solution, I'm able to access the form's scope inside the e2e test. Now with this code:
scope('Form', function(scope) {
scope.email = "test#test.com";
scope.password = "abcd1234";
expect(scope.form.$valid).toBe(true);
})
For whatever reason, scope.form.$valid is false. If I wrap that inside a setTimeout(), it works perfectly well. Angular's sleep() method is of no use.
Any pointers?
You should $digest the scope adding scope.$digest() after the last scope.password.
Thanks to mimo's advice, I arrived at a final solution.
A custom dsl statement had to be constructed, in order to fool expect into taking a Future.
angular.scenario.dsl('expectScope', function() {
var _retrieve = function(source, target) {
if(target == '') return source;
var targets = target.split('.');
var nextTarget = targets[0];
return _retrieve(source[nextTarget], targets.splice(1).join('.') );
};
var chain = angular.extend({}, angular.scenario.matcher);
chain.not = function() {
this.inverse = true;
return chain;
};
return function(scope, name) {
this.future = new angular.scenario.Future('scope.'+name, function() {});
this.future.value = _retrieve(scope, name);
return chain;
};
});
By calling scope.$digest before expectScope(scope, 'value.othervalue'), everything now works as expected.