gaf-mobile
Version:
GAF mobile Web site
482 lines (394 loc) • 15.5 kB
JavaScript
/* global FixedHiremeMock */
/* global HourlyHiremeMock */
describe('Component: Hireme Modal', function() {
var $scope, $compile, $q;
var defaultFixedValues, defaultHourlyValues, currenciesMock, userMock,
currencyMock;
function compileDirective(html) {
var element, compiledElement;
html = html || '<hireme-modal ' +
'user="{ id: 1, username: \'hiremefreelancer\' }"' +
'currency="{ code: \'USD\', sign: \'$\', exchange_rate: null, id: 1 }"' +
'close="function"' +
'></hireme-modal>';
element = angular.element(html);
compiledElement = $compile(element)($scope);
$scope.$digest();
return compiledElement;
}
beforeEach(module('gafMobileApp'));
beforeEach(module('components/hireme-modal/hireme-modal.html'));
beforeEach(inject(function($rootScope, _$compile_, $templateCache, Hireme,
_$q_) {
$templateCache.put('/views/main.html', '');
$scope = $rootScope.$new();
$compile = _$compile_;
$q = _$q_;
userMock = { id: 1, username: 'hiremefreelancer' };
currencyMock = { code: 'USD', sign: '$', exchange_rate: 2, id: 1 };
defaultHourlyValues = HourlyHiremeMock();
defaultFixedValues = FixedHiremeMock();
defaultFixedValues.days = 3;
currenciesMock = {
getList: function() {
return [
{ id: 1, code: 'USD', sign: '$' },
{ id: 2, code: 'PHP', sign: 'P' },
];
}
};
spyOn(Hireme, 'getCurrencies').and.returnValue($q.when(currenciesMock));
spyOn(Hireme, 'getDefaultValues').and.callFake(function(u, c, projectType) {
if (projectType === 'hourly') {
return defaultHourlyValues;
} else {
return defaultFixedValues;
}
});
spyOn(Hireme, 'minimumBudget').and.callFake(function(currency, type) {
if (currency.code === 'USD' && (type === 'fixed' || !type)) {
return $q.when(10);
} else if (currency.code === 'USD' && type === 'hourly') {
return $q.when(2);
} else if (currency.code === 'PHP' && (type === 'fixed' || !type)) {
return $q.when(500);
} else if (currency.code === 'PHP' && type === 'hourly') {
return $q.when(100);
}
});
spyOn(Hireme, 'maximumBudget').and.callFake(function(currency) {
if (currency.code === 'USD') {
return $q.when(20);
} else if (currency.code === 'PHP') {
return $q.when(1000);
}
});
}));
describe('Initialization', function() {
var controller;
beforeEach(function() {
var modal = compileDirective();
controller = modal.controller('hiremeModal');
});
it('should set the defaults for the currencies, hireme project, ' +
'minimum budget, and maximum budget', function() {
expect(controller.currencies).toEqual(currenciesMock.getList());
expect(controller.minimumBudget).toEqual(10);
expect(controller.maximumBudget).toEqual(20);
expect(controller.hiremeProject).toEqual(defaultFixedValues);
});
});
describe('Creating the hireme project after deposit success', function() {
var controller, currentProject;
beforeEach(inject(function(Projects, Hireme) {
currentProject = {
user: userMock,
currency: currencyMock,
type: 'fixed',
hireme: true
};
spyOn(Hireme, 'createForUser').and.returnValue($q.when({}));
spyOn(Projects, 'getCurrent').and.returnValue({
get: function() { return currentProject; }
});
controller = compileDirective().isolateScope().ctrl;
}));
it('should set the hireme project then proceed to creating it',
function() {
expect(controller.hiremeProject).toEqual(currentProject);
});
});
describe('Hireme Modal form', function() {
var modal, isolateScope, form, controller;
beforeEach(function() {
// TODO: Cleanup AB test for creating Hourly Hireme projects
inject(function(Experiments) {
spyOn(Experiments, 'activateTest').and.returnValue(true);
});
modal = compileDirective();
isolateScope = modal.isolateScope();
controller = isolateScope.ctrl;
form = isolateScope.hiremeForm;
});
describe('Form field for project type', function() {
it('should initially be set to fixed', function() {
expect(controller.hiremeProject.type)
.toEqual('fixed');
});
});
describe('Form field for currency', function() {
it('should initially be the currency of employer', function() {
expect(form.currency.$valid).toBeTruthy();
expect(form.currency.$viewValue).toEqual(currencyMock);
});
it('should call the controller function for currency change', function() {
var newCurrency = {
id: 2,
code: 'PHP',
sign: 'P'
};
spyOn(isolateScope.ctrl, 'onCurrencyChange');
form.currency.$setViewValue(newCurrency);
angular.element(modal.find('select')).triggerHandler('change');
expect(isolateScope.ctrl.onCurrencyChange)
.toHaveBeenCalledWith(newCurrency);
});
});
describe('Form field for budget', function() {
it('should initially be the default minimum budget wrt to currency of ' +
'employer', function() {
expect(form.budget.$viewValue).toEqual('10'); // string in form
expect(form.budget.$valid).toBeTruthy();
});
it('should be valid if minimum <= amount <= maximum', function() {
form.budget.$setViewValue('10');
expect(form.budget.$valid).toBeTruthy();
form.budget.$setViewValue('11');
expect(form.budget.$valid).toBeTruthy();
form.budget.$setViewValue('20');
expect(form.budget.$valid).toBeTruthy();
});
it('should be invalid if amount < minimum', function() {
form.budget.$setViewValue('9');
expect(form.budget.$valid).toBeFalsy();
expect(form.budget.$error.min).toBeTruthy();
});
it('should be invalid if amount > maximum', function() {
form.budget.$setViewValue('21');
expect(form.budget.$valid).toBeFalsy();
expect(form.budget.$error.max).toBeTruthy();
});
it('should be invalid if amount is not a number', function() {
form.budget.$setViewValue('abc');
expect(form.budget.$valid).toBeFalsy();
expect(form.budget.$error.number).toBeTruthy();
});
it('should be invalid if amount does not have a value', function() {
form.budget.$setViewValue();
expect(form.budget.$valid).toBeFalsy();
expect(form.budget.$error.required).toBeTruthy();
});
});
describe('Form field for days', function() {
it('should initially be the default days', function() {
expect(form.days.$viewValue).toEqual('3'); // string in form
expect(form.days.$valid).toBeTruthy();
});
it('should be valid if 1 <= days <= 1000', function() {
form.days.$setViewValue('1');
expect(form.days.$valid).toBeTruthy();
form.days.$setViewValue('2');
expect(form.days.$valid).toBeTruthy();
form.days.$setViewValue('1000');
expect(form.days.$valid).toBeTruthy();
});
it('should be invalid if days < 1', function() {
form.days.$setViewValue('0');
expect(form.days.$valid).toBeFalsy();
expect(form.days.$error.min).toBeTruthy();
});
it('should be invalid if days > 1000', function() {
form.days.$setViewValue('1001');
expect(form.days.$valid).toBeFalsy();
expect(form.days.$error.max).toBeTruthy();
});
it('should be invalid if days is not a number', function() {
form.days.$setViewValue('abc');
expect(form.days.$valid).toBeFalsy();
expect(form.days.$error.number).toBeTruthy();
});
it('should be invalid if days does not have a value', function() {
form.days.$setViewValue();
expect(form.days.$valid).toBeFalsy();
expect(form.days.$error.required).toBeTruthy();
});
it('should be hidden if project type is set to hourly', function() {
controller.hiremeProject.type = 'hourly';
isolateScope.$digest();
expect(form.days).not.toBeDefined();
expect(form.$valid).toBeTruthy();
});
});
describe('Form submit button', function() {
var submitBtn;
beforeEach(function() {
submitBtn = modal.find('button');
});
it('should be enabled if form is valid', function() {
expect(submitBtn.attr('disabled')).toBeFalsy();
});
it('should be disabled if form is invalid', function() {
form.$setValidity('hiremeForm.budget.$error.min', false);
$scope.$digest();
expect(submitBtn.attr('disabled')).toBeTruthy();
});
it('should call the hireMe() function of the controller', function() {
spyOn(isolateScope.ctrl, 'hireMe');
angular.element(modal.find('form')).triggerHandler('submit');
expect(isolateScope.ctrl.hireMe).toHaveBeenCalled();
});
});
describe('Modal close button', function() {
var closeBtn;
beforeEach(function() {
closeBtn = modal.find('a');
});
it('should call the closeModal() on controller when clicked', function() {
spyOn(isolateScope.ctrl, 'close');
angular.element(closeBtn).triggerHandler('click');
expect(isolateScope.ctrl.close).toHaveBeenCalled();
});
});
});
describe('Changing the project type', function() {
var controller, newType;
beforeEach(function() {
var modal = compileDirective();
controller = modal.controller('hiremeModal');
newType = 'hourly';
});
it('should refresh the minimum budget', function() {
expect(controller.minimumBudget).toEqual(10);
controller.onTypeChange(newType);
$scope.$digest();
expect(controller.minimumBudget).toEqual(2);
});
it('should remove the `hourly_project_info` property and add the `days`' +
'property with default value when set to fixed', function() {
controller.onTypeChange('fixed');
expect(controller.hiremeProject.hourly_project_info).not.toBeDefined();
expect(controller.hiremeProject.days).toEqual(defaultFixedValues.days);
});
it('should remove the `days` property and add the `hourly_project_info`' +
'property with default values when set to hourly', function() {
controller.onTypeChange('hourly');
expect(controller.hiremeProject.days).not.toBeDefined();
expect(controller.hiremeProject.hourly_project_info)
.toEqual(defaultHourlyValues.hourly_project_info);
});
});
describe('Changing the currency', function() {
var controller, newCurrency;
beforeEach(function() {
var modal = compileDirective();
controller = modal.controller('hiremeModal');
newCurrency = { id: 2, code: 'PHP', sign: 'P' };
});
it('should refresh the budget range', function() {
expect(controller.minimumBudget).toEqual(10);
expect(controller.maximumBudget).toEqual(20);
controller.onCurrencyChange(newCurrency);
$scope.$digest();
expect(controller.minimumBudget).toEqual(500);
expect(controller.maximumBudget).toEqual(1000);
});
});
describe('Submitting a valid form', function() {
var Projects, controller, newProject;
beforeEach(function() {
var modal = compileDirective();
controller = modal.controller('hiremeModal');
});
describe('for creating a fixed hireme project', function() {
beforeEach(inject(function(_Projects_, Hireme) {
Projects = _Projects_;
newProject = { get: function() { return { id: 123 }; } };
spyOn(Projects, 'setCurrent');
spyOn(Hireme, 'createForUser').and.returnValue($q.when(newProject));
spyOn(controller, 'close');
controller.hiremeProject.type = 'fixed';
controller.hireMe();
$scope.$digest();
}));
describe('when the hireme project was posted successfully', function() {
it('should set the project as current and close the modal', function() {
expect(Projects.setCurrent).toHaveBeenCalledWith(newProject);
expect(controller.close).toHaveBeenCalled();
});
});
});
describe('for creating an hourly hireme project', function() {
describe('if employer has verified payment sources', function() {
var $location, projectId;
beforeEach(inject(function(Deposits, Hireme, _$location_) {
$location = _$location_;
projectId = 999;
newProject = {
get: function() {
return {
id: projectId,
hireme_initial_bid: { bidder_id: userMock.id }
};
}
};
spyOn($location, 'url');
spyOn(Hireme, 'createForUser').and.returnValue($q.when(newProject));
spyOn(Deposits, 'getVerifiedPaymentSources').and.returnValue(
$q.when({ 'payment_source': [1, 2, 3] }));
controller.hiremeProject.type = 'hourly';
controller.hireMe();
$scope.$digest();
}));
it('should create the project then redirect to the ' +
'PVP\'s management tab', function() {
expect($location.url).toHaveBeenCalledWith(
'/projects/project-' + projectId +
'?createMilestoneFor=' + userMock.id +
'#management');
});
});
});
describe('when the hireme project was posted unsuccessfully', function() {
var Hireme, modal, controller, error;
describe('due to duplicate title', function() {
beforeEach(inject(function(_Hireme_) {
Hireme = _Hireme_;
error = {
code: 'DUPLICATE_TITLE',
hiremeDuplicateTitle: true
};
spyOn(Hireme, 'createForUser').and.returnValues(
$q.reject(error),
$q.reject(error),
$q.when()
);
modal = compileDirective();
controller = modal.controller('hiremeModal');
controller.hireMe();
$scope.$digest();
}));
it('should increment the title then retry until success', function() {
expect(Hireme.createForUser.calls.count()).toEqual(3);
expect(Hireme.createForUser.calls.argsFor(1)).toEqual([ userMock, 10,
currencyMock, 'title -- 2',
{ days: 3, type: 'fixed' }
]);
expect(Hireme.createForUser.calls.argsFor(2)).toEqual([ userMock, 10,
currencyMock, 'title -- 3',
{ days: 3, type: 'fixed' }
]);
});
});
describe('due to a reason other than duplicate title', function() {
var Hireme;
beforeEach(inject(function(_Hireme_) {
Hireme = _Hireme_;
error = {
code: 'INTERNAL_ERROR',
internalError: true
};
spyOn(Hireme, 'createForUser').and.returnValue($q.reject(error));
modal = compileDirective();
controller = modal.controller('hiremeModal');
controller.hireMe();
$scope.$digest();
}));
it('should store the error', function() {
expect(Hireme.createForUser.calls.count()).toEqual(1);
expect(controller.error).toEqual(error);
});
});
});
});
});
;