gaf-mobile
Version:
GAF mobile Web site
649 lines (594 loc) • 19.2 kB
JavaScript
'use strict';
describe('Controller: SignupCtrl', function () {
// Vars
var $scope, $location, $q, createCtrl;
// Mocks
var AuthMock, UsersMock, PostProjectMock, CaptchaMock, FacebookMock,
AnalyticsMock;
var userData = {
email: 'chuck@norris.com.au',
username: 'chuck'
};
var projectData = {
title: 'My Project',
};
// Load the controller's module
beforeEach(module('gafMobileApp'));
// Initialize the controller
beforeEach(inject(function($controller, $rootScope, _$location_, _$q_) {
$location = _$location_;
$scope = $rootScope.$new();
$q = _$q_;
createCtrl = function() {
return $controller('SignupCtrl', {
$scope: $scope,
$location: $location,
Analytics: AnalyticsMock,
Auth: AuthMock,
Users: UsersMock,
Projects: PostProjectMock,
Captcha: CaptchaMock,
Facebook: FacebookMock
});
};
// Mock location
$location.host = function () { return 'm.freelancer.com'; };
}));
// Create the mock ups
beforeEach(function() {
AuthMock = jasmine.createSpyObj('Auth', ['isAuthenticated']);
UsersMock = jasmine.createSpyObj('Users', ['create',
'createWithFacebook',
'check']);
PostProjectMock = jasmine.createSpyObj('Projects', ['getCurrent']);
CaptchaMock = jasmine.createSpyObj('Captcha', ['reload',
'get']);
FacebookMock = jasmine.createSpyObj('Facebook', ['checkConnected',
'getUserPictureUrl',
'getUser',
'login']);
AnalyticsMock = jasmine.createSpyObj('Analytics', ['trackAction',
'trackError']);
});
it('should redirect to home when the user is logged in',
function() {
AuthMock.isAuthenticated.and.returnValue(true);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() { return false; }
});
createCtrl();
expect($location.path()).toBe('/');
});
it('should expand sign up form when user is freelancer',
function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() { return false; }
});
$location.url('signup?role=freelancer');
var ctrl = createCtrl();
expect(ctrl.showSignupForm).toBeTruthy();
});
it('should load the project details when a project is ready to post',
function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
get: function() {
return projectData;
},
isReady: function() { return true; }
});
var ctrl = createCtrl();
expect(ctrl.project).toBe(projectData);
});
it('should pull facebook data if data available and in fb view', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
$location.url('signup');
FacebookMock.login.and.returnValue($q.when({}));
FacebookMock.getUserPictureUrl.and.returnValue($q.when('url'));
FacebookMock.getUser.and.returnValue($q.when(userData));
UsersMock.check.and.returnValue($q.when({ recommended_name: 'chuck' }));
var ctrl = createCtrl();
ctrl.loadFacebookSignup();
$scope.$digest();
expect(ctrl.state).toBe('facebookSignup');
expect(ctrl.user.username).toBe('chuck');
expect(ctrl.facebookPictureUrl).toBe('url');
});
it('should call the User createWithFacebook for facebook signup',
function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return false;
},
get: function() {
return projectData;
}
});
UsersMock.createWithFacebook.and.returnValue($q.when({}));
var ctrl = createCtrl();
ctrl.facebookSignup(userData, {});
$scope.$digest();
expect(UsersMock.createWithFacebook).toHaveBeenCalled();
expect(ctrl.state).toBe('success');
expect(ctrl.user).toBe(userData);
});
it('should show default signup view on facebook error',
function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
FacebookMock.login.and.returnValue($q.reject({
code: 'RANDOM_ERROR'
}));
var ctrl = createCtrl();
// Set state to non-default
ctrl.state = 'facebookSignup';
ctrl.loadFacebookSignup();
$scope.$digest();
expect(ctrl.state).toBe('signup');
});
it('should handle facebook outage by showing fb authentication error',
function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
$location.url('signup');
FacebookMock.login.and.returnValue($q.reject({
code: 'NOT_AUTHORISED'
}));
var ctrl = createCtrl();
ctrl.loadFacebookSignup();
$scope.$digest();
expect(ctrl.error.facebookNotAuthorized).toBe(true);
});
it('should display connection error if fb not connected and retry is false',
function() {
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
FacebookMock.login.and.returnValue(
$q.reject({code: 'NOT_CONNECTED'}));
var ctrl = createCtrl();
ctrl.loadFacebookSignup();
$scope.$digest();
expect(ctrl.error.facebookNotConnected).toBe(true);
});
it('should retry fb connection if fb not connected and retry is true',
function() {
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
FacebookMock.login.and.returnValue(
$q.reject({code: 'NOT_CONNECTED'}));
var ctrl = createCtrl();
ctrl.loadFacebookSignup(false, true);
// Set loadFacebookSignup as a spy to test if this will
// get called on the retry
ctrl.loadFacebookSignup = jasmine.createSpy();
$scope.$digest();
expect(ctrl.loadFacebookSignup).toHaveBeenCalled();
});
it('should display access denied if fb account inaccessible', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
$location.url('signup');
$location.hash('facebook');
FacebookMock.checkConnected.and.returnValue(
$q.reject({code: 'ACCESS_DENIED'}));
var ctrl = createCtrl();
$scope.$digest();
expect(ctrl.error.facebookAccessDenied).toBe(true);
});
it('should redirect to fb-login when facebook email is taken', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
$location.url('signup');
$location.hash('facebook');
FacebookMock.checkConnected.and.returnValue(
$q.reject({code: 'EMAIL_TAKEN'}));
var ctrl = createCtrl();
$scope.$digest();
expect(ctrl.error.facebookEmailTaken).toBe(true);
});
it('should display internal error when custom error is returned', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
$location.url('signup');
$location.hash('facebook');
FacebookMock.checkConnected.and.returnValue(
$q.reject({code: 'CUSTOM_ERROR'}));
var ctrl = createCtrl();
$scope.$digest();
expect(ctrl.error.facebookUnknownError).toBe('CUSTOM_ERROR');
});
it('should display facebook username taken signup error',
function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
UsersMock.createWithFacebook.and.returnValue($q.reject({
code: 'USERNAME_TAKEN'
}));
var ctrl = createCtrl();
ctrl.facebookSignup(userData, {});
$scope.$digest();
expect(UsersMock.createWithFacebook).toHaveBeenCalled();
expect(ctrl.error.usernameTaken).toBe(true);
});
it('should display facebook email taken signup error',
function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
UsersMock.createWithFacebook.and.returnValue($q.reject({
code: 'FACEBOOK_EMAIL_TAKEN'
}));
var ctrl = createCtrl();
ctrl.facebookSignup(userData, {});
$scope.$digest();
expect(UsersMock.createWithFacebook).toHaveBeenCalled();
expect(ctrl.error.facebookEmailTaken).toBe(true);
});
it('should display facebook email taken signup error',
function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
UsersMock.createWithFacebook.and.returnValue($q.reject({
code: 'ACCESS_DENIED'
}));
var ctrl = createCtrl();
ctrl.facebookSignup(userData, {});
$scope.$digest();
expect(UsersMock.createWithFacebook).toHaveBeenCalled();
expect(ctrl.error.accessDenied).toBe(true);
});
it('should display unknown facebook signup errors',
function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
UsersMock.createWithFacebook.and.returnValue($q.reject({
code: 'UNKNOWN_ERROR'
}));
var ctrl = createCtrl();
ctrl.facebookSignup(userData, {});
$scope.$digest();
expect(UsersMock.createWithFacebook).toHaveBeenCalled();
expect(ctrl.error.internalError).toBeDefined();
});
it('should redirect to return URL if it exists and sign up success',
function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return false;
},
get: function() {
return projectData;
}
});
UsersMock.createWithFacebook.and.returnValue($q.when({}));
$location.search({ return: '/projects/1234' });
var ctrl = createCtrl();
ctrl.facebookSignup(userData, {});
$scope.$digest();
expect(UsersMock.createWithFacebook).toHaveBeenCalled();
expect($location.url()).toBe('/projects/1234');
});
it('should call the User create for signup', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
UsersMock.create.and.returnValue($q.when(userData));
var ctrl = createCtrl();
ctrl.signup(userData, 'password');
// Promises are evaluated on next digest cycle
$scope.$digest();
// third parameter is captcha which will be undefined
expect(UsersMock.create).toHaveBeenCalledWith(userData,
'password', undefined);
});
it('should redirect to skill select funnel when user is a freelancer',
function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return false;
},
get: function() {
return projectData;
}
});
UsersMock.create.and.returnValue($q.when(userData));
var ctrl = createCtrl();
$location.search('return', '/my-projects');
userData.role = 'freelancer';
ctrl.signup(userData);
// Promises are evaluated on next digest cycle
$scope.$digest();
expect($location.path()).toBe('/skill-select');
});
it('should show error on username taken sign up failure', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
UsersMock.create.and.returnValue($q.reject({code: 'USERNAME_TAKEN'}));
var ctrl = createCtrl();
ctrl.signup(userData);
// Promises are evaluated on next digest cycle
$scope.$digest();
expect(ctrl.processing).toBe(false);
expect(ctrl.state.success).not.toBeDefined();
expect(ctrl.error.usernameTaken).toBe(true);
});
it('should show error on email taken sign up failure', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
UsersMock.create.and.returnValue($q.reject({code: 'EMAIL_TAKEN'}));
var ctrl = createCtrl();
ctrl.signup(userData);
// Promises are evaluated on next digest cycle
$scope.$digest();
expect(ctrl.processing).toBe(false);
expect(ctrl.state.success).not.toBeDefined();
expect(ctrl.error.emailTaken).toBe(true);
});
it('should show error on access denied on signup', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
UsersMock.create.and.returnValue($q.reject({code: 'ACCESS_DENIED'}));
var ctrl = createCtrl();
ctrl.signup(userData);
// Promises are evaluated on next digest cycle
$scope.$digest();
expect(ctrl.processing).toBe(false);
expect(ctrl.state.success).not.toBeDefined();
expect(ctrl.error.accessDenied).toBe(true);
});
it('should show internal error on unknown sign up failure', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
UsersMock.create.and.returnValue($q.reject({code: 'UNKNOWN_ERROR'}));
var ctrl = createCtrl();
ctrl.signup(userData);
// Promises are evaluated on next digest cycle
$scope.$digest();
expect(ctrl.processing).toBe(false);
expect(ctrl.state.success).not.toBeDefined();
expect(ctrl.error.internalError).toBe('UNKNOWN_ERROR');
});
it('should change to captcha state if captcha required', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
UsersMock.create.and.returnValue($q.reject({
message: 'Aie Caramba',
code: 'CAPTCHA_REQUIRED'
}));
var ctrl = createCtrl();
ctrl.signup(userData);
// Promises are evaluated on next digest cycle
$scope.$digest();
expect(ctrl.captcha).toBe(true);
});
it('should show error on invalid captcha on sign up failure and ' +
'reload captcha', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
UsersMock.create.and.returnValue($q.reject({ code: 'INVALID_CAPTCHA' }));
var ctrl = createCtrl();
ctrl.captcha = true;
ctrl.signup(userData);
$scope.$digest();
expect(CaptchaMock.reload).toHaveBeenCalled();
expect(ctrl.state.success).not.toBeDefined();
expect(ctrl.error.invalidCaptcha).toBe(true);
});
it('should go to default login page if button is pressed', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
var ctrl = createCtrl();
$scope.$digest();
ctrl.goToLogin();
expect($location.path()).toBe('/login');
expect($location.hash()).toBe('');
});
it('should go to fb login page if button is pressed with fb option',
function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
var ctrl = createCtrl();
$scope.$digest();
ctrl.goToLogin(true);
expect($location.path()).toBe('/login');
expect($location.hash()).toBe('facebook');
});
it('should set role to employer if role not defined on url', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
$location.path('/signup');
var ctrl = createCtrl();
$scope.$digest();
expect(ctrl.user.role).toBe('employer');
});
it('should set role to what it is in the url', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
$location.path('/signup');
$location.search('role', 'freelancer');
var ctrl = createCtrl();
$scope.$digest();
expect(ctrl.user.role).toBe('freelancer');
});
it('should load fb signup if url contains facebook redirect', function() {
AuthMock.isAuthenticated.and.returnValue(false);
PostProjectMock.getCurrent.and.returnValue({
isReady: function() {
return true;
},
get: function() {
return projectData;
}
});
$location.search({ facebook_redirect: true });
FacebookMock.checkConnected.and.returnValue($q.when({}));
FacebookMock.getUser.and.returnValue($q.when(userData));
UsersMock.check.and.returnValue($q.when({recommended_name: 'chuck'}));
var ctrl = createCtrl();
$scope.$digest();
expect(ctrl.state).toBe('facebookSignup');
expect(ctrl.user.username).toBe('chuck');
});
});