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.
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
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.
I'm trying to add a simple drop down control above a list such that I can sort it by "created" or "title".
The list template is called posts_list.html. In it's helper .js file I have:
posts: function () {
var sortCriteria = Session.get("sortCriteria") || {};
return Posts.find({},{sort: {sortCriteria: 1}});
}
Then, I have abstracted the list into another template. From here I have the following click event tracker in the helper.js
"click": function () {
// console.log(document.activeElement.id);
Session.set("sortCriteria", document.activeElement.id);
// Router.go('history');
Router.render('profile');
}
Here I can confirm that the right Sort criteria is written to the session. However, I can't make the page refresh. The collection on the visible page never re-sorts.
Frustrating. Any thoughts?
Thanks!
You can't use variables as keys in an object literal. Give this a try:
posts: function() {
var sortCriteria = Session.get('sortCriteria');
var options = {};
if (sortCriteria) {
options.sort = {};
options.sort[sortCriteria] = 1;
}
return Posts.find({}, options);
}
Also see the "Variables as keys" section of common mistakes.
thanks so much for that. Note I've left commented out code below to show what I pulled out. If I required a truly dynamic option, versus the simply binary below, I would have stuck w/ the "var options" approach. What I ended up going with was:
Template.postList.helpers({
posts: function () {
//var options = {};
if (Session.get("post-list-sort")) {
/*options.sort = {};
if (Session.get("post-list-sort") == "Asc") {
options.sort['created'] = 1;
} else {
options.sort['created'] = -1;
}*/
//return hunts.find({}, options);}
console.log(Session.get("hunt-list-sort"));
if (Session.get("hunt-list-sort") == "Asc") {
return Hunts.find({}, {sort: {title: 1}});
}
else {
return Hunts.find({}, {sort: {title: -1}});
};
}
}
});
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 am using the option "allowedExtensions" without any problem but there is a situation where I have to permit any type of extension but two.
Is there a simple way to do that? I didn't find an option like 'restrictedExtensions' to do that in the code.
Thanks
From the docs:
The validate and validateBatch events are thrown/called before the default Fine Uploader validators (defined in the options) execute.
Also, if your validation event handler returns false, then Fine Uploader will register that file as invalid and not submit it.
Here's some code you could try in your validate event handler. It has not been tested yet so YMMV.
var notAllowedExts = ['pptx', 'xlsx', 'docx'];
/* ... */
onValidate: function (fileOrBlobData) {
var valid = true;
var fileName = fileOrBlobData.name || '';
qq.each(notAllowedExts, function(idx, notAllowedExt) {
var extRegex = new RegExp('\\.' + notAllowedExt + "$", 'i');
if (fileName.match(extRegex) != null) {
valid = false;
return false;
}
});
return valid;
}
/* ... */