Test return value of a spy - jasmine

I am developing an Ionic app. The calling function lets the user call the number in factory.call.
factory.call = '345-678-9087';
factory.calling = function(){
return $window.location.href = 'tel:' + factory.call;
};
This is the Jasmine test for the above,
it('calling method', function(){
spyOn(factory, 'calling');
factory.calling();
expect(typeof(windowMock.location.href)).toEqual('string');
});
The above test passes just fine, but it does not test the exact value that factory.calling() returns. I have tried the following with no luck.
1)
it('calling method', function(){
var emergency = spyOn(factory, 'calling');
factory.calling();
expect(emergency).toEqual("'tel:' + factory.call");
});
2) spyOn(factory, "calling").andCallThrough().
3) spyOn(factory, "calling").andReturn("'tel:' + factory.call").

Not sure you still need this, but call info contains "returnValue" property.
So it can be tested like this:
expect($scope.isFilterError.calls.first().returnValue).toBeFalsy();

First, your factory is not returning anything:
factory.calling = function(){
return $window.location.href = 'tel:' + factory.call;
};
Calls to $window.location.href that are an assignment will not return anything. Seems to me that that call should not be there and your method should be:
factory.calling = function(){
return 'tel:' + factory.call;
};
Doing it this way, you have a return value. Also, you are not storing the value that is returned anywhere that you can test it. In general, you use a spy to check to see if the method was called, like this:
it('calling method', function(){
spyOn(factory, 'calling');
factory.calling();
expect(factory.calling).toHaveBeenCalled();
});
To check what the method returns, you can call it within the expect block like this:
it('calling method', function(){
expect(factory.calling()).toEqual('tel: ' + factory.call);
});
Or you can call it via an anonymous function like this:
it('calling method', function(){
expect(function(){return factory.calling();}).toEqual('tel: ' + factory.call);
});
Or you can call it first and then check the value it returns like this:
it('calling method', function(){
var result = factory.calling();
expect(result).toEqual('tel: ' + factory.call);
});
I might also suggest that you test with fixed data that you provide since a test of this type should not be hitting a database. Also, you should always stick to OAPT (like you have done.)

Related

How do I check for a console log in Karma/Jasmine?

Let's say I have this function I want to test:
var test = function () {
console.log('words!');
};
I'd write something like this
define('test()', function () {
it('prints "words!" to the screen', function() {
test();
expect(<browser logs>).toContain('words!'); // TODO
}
}
But I don't know how to view the console logs or if this is even possible. Preferably, I'd do this in any browser, or at least PhantomJS.
You may create the spy on console.log function. The code may look like ...
describe("log reporting", function () {
beforeEach(function(){
spyOn(window.console, 'log');
});
it('should print log message to console', function(){
test();
expect(window.console.log).toHaveBeenCalled();
})
});
With this example you would know your console.log function was called. This is exactly what you need to know. You don't want to compare logged message with expected value, simply because you would unit test not your code, but window.console.log function itself, which you didn't write ;) You may call ".and.callFake(function(){do something});". In this case you would do something instead of actual console.log call, for example check your value.

Ecma 6 Promise complete

I am experimenting with Promise from ES6, but I can't find any alternative to complete as in jQuery ajax. I need to execute function after all the registered handlers with "then".
Thanks!
As mentioned by Bergi, what you want is the disposer pattern. Your central conception of a promise appears to be a bit off, and I think that is making this harder for you to reason about. When you call .then, you are not conceptually "attaching a handler", you are creating a new promise that will by definition resolve after all of its .then handlers have run.
Given your central issue based on code like this:
// a.js
module.exports = function(){
// Where 'Promise.resolve()' is a stand in for your ajax.
return Promise.resolve()
.then(function(){
// Want this to run after 'B'.
});
}
// b.js
var makePromise = require('./a');
module.exports = function specialMakePromise(){
return makePromise().then(function(){
// Should run first.
});
}
They will always run in the wrong order, because by definition, the .then handler from a.js must run and complete before the .then handler from b.js.
One way to approach this problem would instead to structure your code like this:
// a.js
module.exports = function(callback){
return Promise.resolve()
.then(callback)
.then(function(){
// Want this to run after 'B'.
});
}
// b.js
var makePromise = require('./a');
module.exports = function specialMakePromise(){
return makePromise(function(){
// Should run first.
});
}

RxJS: How would I "manually" update an Observable?

I think I must be misunderstanding something fundamental, because in my mind this should be the most basic case for an observable, but for the life of my I can't figure out how to do it from the docs.
Basically, I want to be able to do this:
// create a dummy observable, which I would update manually
var eventObservable = rx.Observable.create(function(observer){});
var observer = eventObservable.subscribe(
function(x){
console.log('next: ' + x);
}
...
var my_function = function(){
eventObservable.push('foo');
//'push' adds an event to the datastream, the observer gets it and prints
// next: foo
}
But I have not been able to find a method like push. I'm using this for a click handler, and I know they have Observable.fromEvent for that, but I'm trying to use it with React and I'd rather be able to simply update the datastream in a callback, instead of using a completely different event handling system. So basically I want this:
$( "#target" ).click(function(e) {
eventObservable.push(e.target.text());
});
The closest I got was using observer.onNext('foo'), but that didn't seem to actually work and that's called on the observer, which doesn't seem right. The observer should be the thing reacting to the data stream, not changing it, right?
Do I just not understand the observer/observable relationship?
In RX, Observer and Observable are distinct entities. An observer subscribes to an Observable. An Observable emits items to its observers by calling the observers' methods. If you need to call the observer methods outside the scope of Observable.create() you can use a Subject, which is a proxy that acts as an observer and Observable at the same time.
You can do like this:
var eventStream = new Rx.Subject();
var subscription = eventStream.subscribe(
function (x) {
console.log('Next: ' + x);
},
function (err) {
console.log('Error: ' + err);
},
function () {
console.log('Completed');
});
var my_function = function() {
eventStream.next('foo');
}
You can find more information about subjects here:
https://github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/subject.md
http://reactivex.io/documentation/subject.html
I believe Observable.create() does not take an observer as callback param but an emitter. So if you want to add a new value to your Observable try this instead:
var emitter;
var observable = Rx.Observable.create(e => emitter = e);
var observer = {
next: function(next) {
console.log(next);
},
error: function(error) {
console.log(error);
},
complete: function() {
console.log("done");
}
}
observable.subscribe(observer);
emitter.next('foo');
emitter.next('bar');
emitter.next('baz');
emitter.complete();
//console output
//"foo"
//"bar"
//"baz"
//"done"
Yes Subject makes it easier, providing Observable and Observer in the same object, but it's not exactly the same, as Subject allows you to subscribe multiple observers to the same observable when an observable only send data to the last subscribed observer, so use it consciously.
Here's a JsBin if you want to tinker with it.
var observer = Observable.subscribe(
function(x){
console.log('next: ' +
var my_function = function(){
Observable.push('hello')
One of the way to update an observable.

Jasmine 1.3 - is it possible to unspy?

We can define the following test:
spyOn(x, 'funk').andReturn(true);
If we then wanted to define:
spyOn(x, 'funk').andReturn(false);
We would get an error saying that funk had already been spied on.
How could we effectively unspy so that could respy with the new return value?
You can re-train spies:
//--- CODE --------------------------
x = {
funk: function() {
return 1;
}
}
// --- SPECS -------------------------
describe('test x', function () {
it("trains spies", function () {
spyOn(x, 'funk');
x.funk.andReturn('a');
expect(x.funk()).toBe('a');
x.funk.andCallThrough();
expect(x.funk()).toBe(1);
});
});
See fiddle here - http://jsfiddle.net/eitanp461/88kvnzx3/
Yes it's possible to unspy.
As the spy is just a function that replaces whatever function you want to spy on, you can replace it again with another function.
Two sensible ways of doing this are as follows - first, just add an empty function, Jasmine will have all it needs for a new spy:
x.funk = function() {}
Or, if the functionality of original function is important, just store it in a value like so:
var tempFunk = x.funk
/* do stuff */
x.funk = tempFunk

Angular $http method called in function only works once

I have this function in an angular service that I want to call multiple times throughout my app.
Version 1
getNearbyRestaurants: function(){
$http.get(url)
.success(function(data){
console.log("works here")
// do stuff with the data
})
.error(function(){
console.log("got an error");
// do stuff with the error
});
}
Version 2
getNearbyRestaurants: function(lat, lng){
var latLng = "ll=" + lat + "," + lng
return $http.get(url + latLng)
}
The first time I call this function all is well, but any subsequent calls won't do anything. I make it into the function just fine, but the $http service doesn't actually make a call to the url and neither the success nor the error functions get called. I'm not entirely sure what's wrong here. It should work everytime. Am I missing some basic understanding of the $http service?
So I resolved this issue. What was happening was I was calling the function from outside of Angular (from the google maps event callback). So all I needed to do was wrap the function call in $rootScope.$apply and everything worked perfect.

Resources