I'm mocking a function called isLoggedIn():
auth = {
isLoggedIn: function () {
return true;
}
};
and apply is in a beforeEach loop
beforeEach(function () {
angular.mock.module(function ($provide) {
$provide.value('Auth', auth);
});
});
At the moment isLoggedIn() will always return true. This function needs to be able to return false for some particular tests.
Is there a way to pass a variable into the mock from my tests.
E.g. something like
var loggedIn = ;
auth = {
isLoggedIn: function () {
return loggedIn;
}
};
Yes, you can for instance put it inside your test:
var loggedIn;
beforeEach(function () {
auth = {
isLoggedIn: function () {
return loggedIn;
}
};
angular.mock.module(function ($provide) {
$provide.value('Auth', auth);
});
});
It is also possible to have it as a separate file, but for this example it seems overkill.
Related
I am building an angular app which uses Firebase as the front-end. But i am unable to see how to implement unit tests for the Firebase code in my app.
In conclusion, my question is:
How do you implement Firebase testing in an angular app?
As an example could someone unit test the following method?
service.subscribeForEvent = function (eventKey) {
service.dbRef = firebase.database().ref(eventKey);
service.dbRef.on('value', function (result) {
onMessage(result.val());
});
};
I have created a fake of firebase:
firebase = {
__ref: {
events: {
'child_added': [],
'child_changed': []
},
push: function (data) {
angular.forEach(this.events["child_added"], function (each) {
each(data);
});
},
update: function (data) {
angular.forEach(this.events["child_changed"], function (each) {
each(data);
});
},
child: function () {
return {
on: function (eventType, callback) {
window.firebase.__ref.events[eventType].push(callback);
}
};
}
},
database: function () {
return {
ref: function () {
return window.firebase.__ref;
},
$clean: function () {
window.firebase.__ref.events['child_added'] = [];
window.firebase.__ref.events['child_changed'] = [];
}
};
};
and expect after new child is added in firebase, the callback function to be called:
it('subscribe for added event and receive message for it', function () {
var eventName = 'new event';
var callback = jasmine.createSpy('callback');
pushApi.bind(eventName, callback);
ref.push({
val: function () {
return {event: {key: eventName}};
}
});
expect(callback).toHaveBeenCalledWith({key: eventName});
};
But when run test it expected default firebase to be created.
I have this service in my app. Service to set and get user in localstorage. But the getUser function was returning the JSON.parse function not my object.
Anybody know how to resolve this insue?
The code is here:
.service('UserService', function() {
// For the purpose of this example I will store user data on ionic local storage but you should save it on a database
var setUser = function(user_data) {
window.localStorage.extract = JSON.stringify(user_data);
};
var getUser = function(){
console.log(JSON.parse(window.localStorage.user || '{}'));
return JSON.parse(window.localStorage.user || '{}');
};
var clearUser = function(){
delete window.localStorage.user;
};
return {
getUser: getUser,
setUser: setUser,
clearUser: clearUser
};
})
Thanks
I use the localStorage.get/set item methods like below. So your service would look like
.service('UserService', function() {
var getUser = function(){
return JSON.parse(window.localStorage.getItem('user'));
};
var setUser = function(user){
JSON.stringify(window.localStorage.setItem('user', user));
};
return {
getUser: getUser,
setUser: setUser
};
})
I am trying to get the value returned through an authorization getCurrentUser function. When calling the function, I get this resource holding a Promise. I can see the _id value in there! How do I access it?
Thank you in advance!
Console Output
Here's a bit of the Auth service where getCurrentUser is defined:
(function config() {
function AuthService($location, $http, $cookies, $q, appConfig, Util, User) {
const safeCb = Util.safeCb;
let currentUser = {};
let Auth = {};
const LOCAL_HOST = 'localhost';
if ($cookies.get('token') && $location.path() !== '/logout') {
currentUser = User.get();
}
Auth = {
getCurrentUser(callback) {
if (arguments.length === 0) {
return currentUser;
}
const value = currentUser.hasOwnProperty('$promise') ? currentUser.$promise : currentUser;
return $q.when(value).then(user => {
safeCb(callback)(user);
return user;
}, () => {
safeCb(callback)({});
return {};
});
}
...
Here is where I call it:
angular.module('toroApp').directive('csvreaderDirective', ['$http', function ($http, Auth) {
return {
controller(Auth) {
const currentUser = Auth.getCurrentUser();
console.log(currentUser);
},
compile(element, Auth) {
...
Auth.getCurrentUser() is returning a $q promise so you need to use the promise API to get the result.
controller(Auth) {
Auth.getCurrentUser().then(function (user) {
const currentUser = user;
console.log(currentUser);
});
}
Parent Service:
module proj.Stuff {
export class ParentService {
//...properties, constructor, etc
public refreshStuff(id: number) {
this.childService
.getStuff(id)
.then((response) => this.stuff = response);
}
}
}
Child service:
module proj.Stuff {
export class ChildService{
//... properties, constructor, etc
public getStuff(id: number) {
var request: IPromise<any> = this.$http.get(
ChildService.apiUrlBase + "getStuff/" + id
);
return request
.then(response => {
return response.data.value;
}, response => {
this.$log.error("unable to get...");
});
}
}
}
Tests for the parent service:
describe("ParentService", () => {
// (property declarations omitted for brevity)
beforeEach(angular.mock.module(["$provide", ($provide) => {
var obj = {
getStuff: (id: number) => {
functionCalled = true;
return {
then: (callback) => {
return callback(["result"]);
}
};
}
};
$provide.value("ChildService", obj);
}]));
beforeEach(mock.inject((_$http_, _$log_, _$q_, _$httpBackend_, _$rootScope_, _ChildService_) => {
cService = _ChildService_;
pService = new ParentService(cbService);
}));
it("can be created", () => {
expect(pService).toBeDefined();
expect(pService).not.toBeNull();
});
it("can refresh stuff", () => {
pService.refreshStuff(1);
expect(pService.stuff).toEqual(["result"]);
expect(functionCalled).toBeTruthy();
// ***** what I want to do: *****
// expect(cService.getStuff).toHaveBeenCalled();
});
});
I'm wondering how can I spy on cService.getStuff instead of using the 'functionCalled' boolean?
When I try to spy on it, it complains that .then isn't defined - e.g. in the first beforeEach if I try spyOn(obj, "getStuff") it doesn't like it.
The tests pass as is, but would rather spyOn instead of using the boolean.
then method mocks are rarely justified, Angular DI allows to use unmocked promises and to focus on unit testing.
beforeEach(angular.mock.module(["$provide", ($provide) => {
// allows to inject $q, while $provide.value doesn't
$provide.factory("ChildService", ($q) => ({
// fresh promise on every call
getStuff: jasmine.createSpy('getStuff').and.callFake(() => $q.when('result'))
}));
}]));
Works best with Jasmine promise matchers, otherwise routine promise specs should be involved:
var result;
...then((_result) => { result = _result; })
$rootScope.$digest();
expect(result)...
I'm trying to wrap the PushPlugin in a Angular factory, based on devgirls post, but so far without success.
angular.module('phonegap', [])
.factory('phonegapReady', function ($rootScope, $q) {
var loadingDeferred = $q.defer();
document.addEventListener('deviceready', function () {
$rootScope.$apply(loadingDeferred.resolve);
});
return function phonegapReady() {
return loadingDeferred.promise;
};
})
.factory('push', function ($rootScope, phonegapReady) {
return {
registerPush: phonegapReady().then(function (onSuccess, onError) {
// stripped handlers
if (device.platform === 'android' || device.platform === 'Android') {
pushNotification.register(
function () {
var that = this,
args = arguments;
if (onSuccess) {
$rootScope.$apply(function () {
onSuccess.apply(that, args);
});
}
},
function () {
var that = this,
args = {
'senderID': '123',
'ecb': 'onNotificationGCM'
};
if (onError) {
$rootScope.$apply(function () {
onError.apply(that, args);
});
}
}
);
} else {
pushNotification.register(
function () {
var that = this,
args = arguments;
if (onSuccess) {
$rootScope.$apply(function () {
onSuccess.apply(that, args);
});
}
},
function () {
var that = this,
args = {
'badge': 'true',
'sound': 'true',
'alert': 'true',
'ecb': 'onNotificationAPN'
};
if (onError) {
$rootScope.$apply(function () {
onError.apply(that, args);
});
}
}
);
}
})
};
});
Getting an error:
TypeError: '[object Object]' is not a function (evaluating 'e.registerPush(function(a){console.log("fun"),console.log(a)})')
What am I doing wrong?
When a you call then on a promise, it returns the promise so you can chain the callbacks.
I think wrapping registerPush with a function would work, like:
registerPush: function(onSuccess, onError) {
phonegapReady().then(function () {
// Do something with closured onSuccess and onError
});
},..