How to recover Jasmine spy name in custom matcher - javascript

Im going to create a custom matcher in Jasmine 2.0 to verify spies against some additional conditions. In huge simplification, something like:
var customMatchers = {
toDoSomething: function(util, customEqualityTesters) {
return {
compare: function(spy) {
var comparison = {};
comparison.pass = testSomeCondition(spy);
if (!comparison.pass) {
comparison.message = "Expect " + /insert code here/ + " to do something";
}
return comparison;
}
}
}
};
beforeEach(function() {
jasmine.addMatchers(customMatchers);
});
My question is, how to recover the spy name, passed as a first argument of factory method: createSpy(name, originalFn)?
I cannot find anything in Jasmine documentation v2.6 neither in online tutorials.
console.log(spy) returns function(...) {...}

I don't know if it is the right thing to do so, but found in Jasmine source code how toHaveBeenCalled was originally implemented and found:
spy.and.identity()
It works well also in a custom matcher.

Related

How can I migrate my custom matchers from Jasmine 1 to Jasmine 2

Version 2 of the JavaScript testing framework jasmine unfortunately introduced several breaking changes. One of these changes is the way custom matchers are handled, as is outlined here:
http://jasmine.github.io/2.0/upgrading.html
The addMatchers function is no longer on the spec (this) it is now on the global jasmine object.
/* was:
this.addMatchers({
*/
jasmine.addMatchers({
A matcher is set up a bit different now. The factory receives a util object which contains things like jasmines equality functions, and any registered customEqualityTesters. The factory is expected to return an object with a compare function which will be called with the actual and expected directly, instead of the actual value being on this
/* was:
toBeCustom: function(expected) {
var passed = this.actual == expected;
*/
toBeCustom: function(util, customEqualityTesters) {
return {
compare: function(actual, expected) {
var passed = actual == expected
The comparison should now return an object with pass and message attributes.
I am looking for an easy way to migrate our existing matchers, so that we can easily switch to the new jasmine version.
To ease the transition to the new jasmine version the following special migration object will help.
Instead of adding the matcher on the this object, you add them on the jasmineMigrate object. But this is really all you need to to. The jasmineMigrate object will take care of the rest.
/* was:
this.addMatchers({
*/
jasmineMigrate .addMatchers({
The implementation of the migration object:
var jasmineMigrate = {};
jasmineMigrate.addMatchers = function (matchers) {
Object.keys(matchers).forEach(function (matcherName) {
var matcher = matchers[matcherName],
migratedMatcher = {};
migratedMatcher[matcherName] = function (util, customEqualityTesters) {
return {
compare: function (actual) {
var matcherArguments,
thisForMigratedMatcher,
matcherResult,
passed;
//In Jasmine 2 the first parameter of the compare function
//is the actual value.
//Whereas with Jasmine 1 the actual value was a property of the matchers this
//Therefore modify the given arguments array and remove actual
matcherArguments = [].slice.call(arguments)
matcherArguments.splice(0, 1);
//Add actual to the this object we'll be passing to the matcher
thisForMigratedMatcher = {
actual: actual
};
//Now call the original matcher aufgerufen, with the modified
//arguments and thisForMigratedMatcher which will be applied to
//the matcher
passed = matcher.apply(thisForMigratedMatcher, matcherArguments);
matcherResult = {
pass: passed,
message: thisForMigratedMatcher.message
};
return matcherResult;
}
}
};
jasmine.addMatchers(migratedMatcher);
});
}
The add-matchers library lets you write matchers which are compatible with Jasmine v1, Jasmine v2, and Jest.

How to pass parameter from spec to reporter in Jasmine?

I am writing a jasmine reporter, and I want to be able to pass parameters from individual specs to the reporter. For example:
the spec:
// I prefer this way
it("my spec 1", function() { ... }, { myParam: true });
// But this way would also be fine if it can work
it("my spec 2", function() {
this.myParam = true;
...
});
the reporter:
this.specDone = function(specResult) {
var myParam = // some way to access myParam
...
}
I haven't found any documentation for something like this, nor any example of something similar in other reporters.
I also tried debugging the flow of jasmine to see what objects get passed to each method but so far I had no luck in finding a simple solution.
How can this be done?
I found one possible solution - in boot.js
var jasmineInterface = {
it: function(desc, func, properties) {
var spec = env.it(desc, func);
spec.result.myParam = (properties || {}).myParam;
return spec;
},
...
and then in the reporter:
this.specDone = function(specResult) {
var myParam = specResult.myParam;
...
}
of course you can (and should) make this more generic to fit other cases.

custom matcher makes jasmine to hang

Trying to call this custom matcher in jasmine testing tool but I got this error:
TypeError: matcherCompare is undefined
var result = matcherCompare.apply(null, args);
jasmine.js (line 1192)
My matcher:
/*
* Extends jasmine expectations by defining new matchers
*/
beforeEach(function () {
jasmine.addMatchers({
toEqualArray: function(){
var s = typeof this.actual,
result = false;
if (s === 'object'){
if (this.actual){
if (Object.prototype.toString.call(this.actual) === Object.prototype.toString.call([])) { //'[object Array]'
result = true;
}
}
}
this.message = function(){
if (result){
return "Is Array";
}
return "Is not an Array";
};
return result;
}
});
});
The core of the code inside toEqualArray is already tested as a simple js function and is ok. My matcher doesn't have an argument as you can see. I use jasmine 2.0 standalone for my tests and my matcher resides in an external js file like in the example at the standalone version of jasmine. I even moved my matcher inside my specs replacing jasmine with this but with no result!
What am I doing wrong?
Jasmine hangs when I put in my spec this specific command:
expect(o.get('any')).toEqualArray();
where o is my object that returns (I tested and it's ok) an array!
I have to debug jasmine now :(
For jasmine 2.0, the syntax for custom matchers was changed. Updated documentation is here: http://jasmine.github.io/2.0/custom_matcher.html

How to implement chained stub in javascript with Jasmine and AngularJs?

I'm not sure if I'm writing the title correct, but here's what I want to do.
I have this code
var callback = function(result) {
if(result.count < 5) {
msg_id = result.msg_id;
MovieService.getMovies(msg_id, result.count).get(callback, error);
}
if(result.movies.length !== 0) {
setDataToDisplay(result);
}
if(result.count === 5) {
$scope.loading = false;
}
}
MovieService.getMovies(msg_id, 0).get(callback, error);
Basically, when user comes in the first time MovieService will be called and it gets called until the count equals to 5 times. It's like a recursive loop. Now if I want to test this code, I don't know how to do chained stub in Jasmine. I could do something similar in Mockito.
Here's my test so far.
it("should give me the lot of movies", function() {
var movie1 = new MovieBuilder().withTweetId('8').build();
var movie2 = new MovieBuilder().withId('3812').withTweetId('8').build();
var movie3 = new MovieBuilder().withId('3813').withTweetId('8').build();
var movie4 = new MovieBuilder().withId('3814').withTweetId('8').build();
movieService = {
getMovies : function() {
return {
get : function(callback, error) {
callback(
{
'msg_id' : '8',
'count' : '5',
'movies' : [movie1, movie2, movie3, movie4]
});
}
}
}
}
ctrl = controller('MovieTwitterCtrl', {$scope : scope, MovieService : movieService});
expect(scope.movie_groups[0].length).toBe(4);
expect(scope.msg_id).toBe('8');
});
But if I want to test the second, third, fourth and fifth call. How do I do that? Does Jasmine offer something like Mockito? Or how do I do that in pure javascript?
Thanks a lot.
You might want to take a look at Sinon, which is a library that provides methods for spys, stubs and mocks and is compatible with Jasmine.
In order to automatically invoke your callbacks, you would use stub.yields() or stub.yieldsTo(). You've also got spy.getCall(n) that will let you verify the way your method was called during the nth time. Sinon is written in a way that stubs are also spies... so if you create a stub for your movieService, you'll have access to both yields() and getCall(n).

Is there any way to use Jasmine default matchers within custom matchers?

I have a custom matcher in some Jasmine test specs of the form:
this.addMatchers({
checkContains: function(elem){
var found = false;
$.each( this.actual, function( actualItem ){
// Check if these objects contain the same properties.
found = found || actualItem.thing == elem;
});
return found;
}
});
Of course, actualItem.thing == elem doesn't actually compare object contents- I have to use one of the more complex solutions in Object comparison in JavaScript.
I can't help but notice, though, that Jasmine already has a nice object equality checker: expect(x).toEqual(y). Is there any way to use that within a custom matcher? Is there any general way to use matchers within custom matchers?
Yes, it is slightly hacky but entirely possible.
The first thing we need to do is make the Jasmine.Env class available. Personally I have done this in my SpecRunner.html since its already setup there anyway. On the load of my SpecRunner I have the following script that runs:
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var trivialReporter = new jasmine.TrivialReporter();
jasmineEnv.addReporter(trivialReporter);
jasmineEnv.specFilter = function(spec) {
return trivialReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
};
})();
So after the execJasmine function declaration I push the jasmineEnv into the global namespace by adding this:
this.jasmineEnv = jasmineEnv;
Now, in any of my spec files I can access the jasmineEnv variable and that is what contains the matchers core code.
Looking at toEqual specifically, toEqual calls the jasmine.Env.prototype.equals_ function. This means that in your customMatcher you can do the following:
beforeEach(function(){
this.addMatchers({
isJasmineAwesome : function(expected){
return jasmineEnv.equals_(this.actual, expected);
}
});
});
Unfortunately, using this method will only give you access to the following methods:
compareObjects_
equals_
contains_
The rest of the matchers reside the jasmine.Matchers class but I have not been able to make that public yet. I hope this helps you out in someway or another

Categories

Resources