linagora-rse
Version:
1,653 lines (1,378 loc) • 46.9 kB
JavaScript
'use strict';
/* global chai: false */
/* global sinon: false */
var expect = chai.expect;
describe('The ContactListController controller', function() {
var $rootScope, $controller, $timeout, $state, $stateParams, $alert;
var AddressBookPaginationService, AddressBookPaginationRegistryMock, contactAddressbookService, contactAddressbookDisplayService,
contactUpdateDataService, gracePeriodService, sharedContactDataService;
var CONTACT_ADDRESSBOOK_EVENTS, CONTACT_EVENTS, CONTACT_LIST_DISPLAY_MODES, DEFAULT_ADDRESSBOOK_NAME;
var addressbooks, scope, sortedContacts, openContactFormMock;
beforeEach(function() {
addressbooks = [];
$alert = {
alert: function() {}
};
gracePeriodService = {
askUserForCancel: function() {
return {promise: $q.when({})};
},
grace: function() {
return {
then: function() {}
};
},
cancel: function() {},
flush: function() {}
};
contactUpdateDataService = { contact: null, taskId: null, contactUpdatedIds: [] };
AddressBookPaginationService = function(pagination) {
this.pagination = pagination;
};
AddressBookPaginationService.prototype.loadNextItems = function(options) {
if (this.pagination && this.pagination.loadNextItems) {
return this.pagination.loadNextItems(options);
}
return $q.when({data: []});
};
AddressBookPaginationRegistryMock = {
get: function() {
return function Mock() {
};
},
put: function() {}
};
openContactFormMock = sinon.spy();
angular.mock.module('esn.core');
module('linagora.esn.contact', function($provide) {
$provide.value('$alert', function(options) { $alert.alert(options); });
$provide.value('gracePeriodService', gracePeriodService);
$provide.value('contactUpdateDataService', contactUpdateDataService);
$provide.value('AddressBookPaginationService', AddressBookPaginationService);
$provide.value('AddressBookPaginationRegistry', AddressBookPaginationRegistryMock);
$provide.value('openContactForm', openContactFormMock);
});
});
beforeEach(angular.mock.inject(function(
_$rootScope_,
_$controller_,
_$timeout_,
_$state_,
_$stateParams_,
_sharedContactDataService_,
_contactAddressbookService_,
_contactAddressbookDisplayService_,
_openContactForm_,
ALPHA_ITEMS,
_CONTACT_EVENTS_,
_CONTACT_LIST_DISPLAY_MODES_,
_CONTACT_ADDRESSBOOK_EVENTS_,
_DEFAULT_ADDRESSBOOK_NAME_
) {
$rootScope = _$rootScope_;
$controller = _$controller_;
$timeout = _$timeout_;
$state = _$state_;
$stateParams = _$stateParams_;
sharedContactDataService = _sharedContactDataService_;
contactAddressbookService = _contactAddressbookService_;
contactAddressbookService.listAggregatedAddressbooks = sinon.stub().returns($q.when(addressbooks));
contactAddressbookDisplayService = _contactAddressbookDisplayService_;
sortedContacts = ALPHA_ITEMS.split('').reduce(function(a, b) {
a[b] = [];
return a;
}, {});
scope = $rootScope.$new();
scope.contact = {};
contactAddressbookDisplayService.convertShellToDisplayShell = angular.noop;
CONTACT_EVENTS = _CONTACT_EVENTS_;
CONTACT_LIST_DISPLAY_MODES = _CONTACT_LIST_DISPLAY_MODES_;
CONTACT_ADDRESSBOOK_EVENTS = _CONTACT_ADDRESSBOOK_EVENTS_;
DEFAULT_ADDRESSBOOK_NAME = _DEFAULT_ADDRESSBOOK_NAME_;
}));
function createPaginationMocks(singleFn, searchFn) {
function SingleMock(options) {
this.options = options;
}
SingleMock.prototype.loadNextItems = singleFn;
function AggregateMock(options) {
this.options = options;
}
AggregateMock.prototype.loadNextItems = singleFn;
function SearchMock(options) {
this.options = options;
}
SearchMock.prototype.loadNextItems = searchFn;
var mocks = {
single: SingleMock,
search: SearchMock,
multiple: AggregateMock
};
AddressBookPaginationRegistryMock.get = function(type) {
return mocks[type];
};
}
function initController(AlphaCategoryService) {
var AlphaCategoryServiceMock = function() {
return {
init: angular.noop,
addItems: angular.noop,
get: angular.noop
};
};
var controller = $controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
},
AlphaCategoryService: AlphaCategoryService || AlphaCategoryServiceMock
});
$rootScope.$digest();
return controller;
}
describe('The $onInit function', function() {
it('should set status to "loading"', function() {
var controller = initController();
expect(controller.status).to.equal('loading');
});
it('should call contactAddressbookService.listAggregatedAddressbooks to get all address books if bookName is blank', function() {
$stateParams.bookName = '';
contactAddressbookService.listAggregatedAddressbooks = sinon.stub().returns($q.when([]));
initController();
expect(contactAddressbookService.listAggregatedAddressbooks).to.have.been.called;
});
it('should call contactAddressbookService.getAddressbookByBookName to get specific address books if bookName is provided', function() {
$stateParams.bookName = 'bookName';
contactAddressbookService.getAddressbookByBookName = sinon.stub().returns($q.when([]));
initController();
expect(contactAddressbookService.getAddressbookByBookName).to.have.been.calledWith('bookName');
});
it('should set status to "error" if failed to load address books', function() {
contactAddressbookService.listAggregatedAddressbooks = sinon.stub().returns($q.reject('an error'));
var controller = initController();
expect(controller.status).to.equal('error');
});
it('should get total contacts count of current viewing addressbooks', function() {
var addressbooksList = [
{ numberOfContacts: 10 },
{ numberOfContacts: 1023 }
];
contactAddressbookService.listAggregatedAddressbooks = sinon.stub().returns($q.when(addressbooksList));
initController();
expect(scope.contactsCount).to.equal(1023 + 10);
});
});
it('should display contacts as list by default', inject(function(CONTACT_LIST_DISPLAY) {
$controller('ContactListController', {
$scope: scope,
user: { _id: '123' }
});
expect(scope.displayAs).to.equal(CONTACT_LIST_DISPLAY.list);
}));
it('should display create contact button if user is viewing all contacts', function() {
var currentAddressbooks = [{
bookName: 'contacts',
canCreateContact: true
}, {
bookName: 'twitter',
canCreateContact: false
}];
contactAddressbookService.listAggregatedAddressbooks = sinon.stub().returns($q.when(currentAddressbooks));
initController();
expect(scope.canCreateContact).to.equal(true);
});
it('should display create contact button if current address book can create contact', function() {
$stateParams.bookName = 'contacts';
var currentAddressbooks = [{
bookName: 'contacts',
canCreateContact: true
}];
contactAddressbookService.getAddressbookByBookName = sinon.stub().returns($q.when(currentAddressbooks));
initController();
expect(scope.canCreateContact).to.equal(true);
});
it('should not display create contact button if current address book cannot create contact', function() {
$stateParams.bookName = 'twitter';
var currentAddressbooks = [{
bookName: 'twitter',
editable: false
}];
contactAddressbookService.getAddressbookByBookName = sinon.stub().returns($q.when(currentAddressbooks));
initController();
expect(scope.canCreateContact).to.equal(false);
});
it('should store the search query when user switches to contact view', function() {
scope.contactSearch = {
searchInput: 'some query'
};
sharedContactDataService.searchQuery = null;
$controller('ContactListController', {
$scope: scope,
user: { _id: '123' }
});
scope.$emit('$stateChangeStart', {
name: '/contact/show/:bookId/:bookName/:cardId'
});
expect(sharedContactDataService.searchQuery).to.equal(scope.contactSearch.searchInput);
});
it('should store the search query when user switches to contact edition view', function() {
scope.contactSearch = {
searchInput: 'some query'
};
sharedContactDataService.searchQuery = null;
$controller('ContactListController', {
$scope: scope,
user: { _id: '123' }
});
scope.$emit('$stateChangeStart', {
name: '/contact/edit/:bookId/:bookName/:cardId'
});
expect(sharedContactDataService.searchQuery).to.equal(scope.contactSearch.searchInput);
});
it('should clear the search query when user switches to a view that is not contact view nor contact edition view', function() {
sharedContactDataService.searchQuery = '';
$controller('ContactListController', {
$scope: scope,
user: { _id: '123' }
});
scope.$emit('$stateChangeStart', {
name: '/this/is/not/contact/show/or/edit/:bookId/:cardId'
});
expect(sharedContactDataService.searchQuery).to.be.null;
});
it('should gracePeriodService.flushAllTasks $on(\'$destroy\')', function() {
createPaginationMocks(function() {
return $q.reject('WTF');
});
gracePeriodService.flushAllTasks = sinon.spy();
contactAddressbookService.listAggregatedAddressbooks = sinon.stub().returns($q.when([]));
initController();
scope.$destroy();
$rootScope.$digest();
expect(gracePeriodService.flushAllTasks).to.have.been.called;
});
it('should register gracePeriodService.flushAllTasks on(\'beforeunload\')', function() {
gracePeriodService.flushAllTasks = 'aHandler';
var event = null;
var handler = null;
var window = {
addEventListener: function(evt, hdlr) {
event = evt;
handler = hdlr;
}
};
createPaginationMocks(function() {
return $q.reject('Fail');
});
$controller('ContactListController', {
$scope: scope,
$window: window,
user: {
_id: '123'
}
});
$rootScope.$digest();
expect(event).to.equal('beforeunload');
expect(handler).to.equal('aHandler');
});
it('should add the contact to the list on delete cancellation', function(done) {
var contact = {
lastName: 'Last'
};
var query = null;
var locationMock = {
search: function() {
return {
q: query
};
}
};
$controller('ContactListController', {
$scope: scope,
$location: locationMock,
user: {
_id: '123'
},
AlphaCategoryService: function() {
return {
addItems: function(data) {
expect(data).to.deep.equal([contact]);
done();
},
get: function() {}
};
}
});
$rootScope.$broadcast(CONTACT_EVENTS.CANCEL_DELETE, contact);
$rootScope.$digest();
});
it('should hide contact on CONTACT_EVENTS.DELETED while in search mode', function() {
var contact = { lastName: 'Last' };
$controller('ContactListController', {
$scope: scope,
user: { _id: '123' }
});
scope.contactSearch.searchInput = 'someQuery';
$rootScope.$broadcast(CONTACT_EVENTS.DELETED, contact);
expect(contact.deleted).to.be.true;
});
it('should show contact on CONTACT_EVENTS.CANCEL_DELETE while in search mode', function() {
var contact = { lastName: 'Last' };
$controller('ContactListController', {
$scope: scope,
user: { _id: '123' }
});
scope.contactSearch.searchInput = 'someQuery';
$rootScope.$broadcast(CONTACT_EVENTS.CANCEL_DELETE, contact);
expect(contact.deleted).to.be.false;
});
it('should add the contact to the contact list of addressbook on CONTACT_EVENTS.CREATED event', function() {
var bookName = 'foobar';
var currentAddressbooks = [{ bookId: 'foo', bookName: bookName }];
var contact = {
lastName: 'Last',
addressbook: currentAddressbooks[0]
};
var addItemsMock = sinon.spy();
var AlphaCategoryService = function() {
return {
addItems: addItemsMock,
get: function() {}
};
};
$stateParams.bookName = bookName;
contactAddressbookService.getAddressbookByBookName = sinon.stub().returns($q.when(currentAddressbooks));
initController(AlphaCategoryService);
$rootScope.$broadcast(CONTACT_EVENTS.CREATED, contact);
$rootScope.$digest();
expect(addItemsMock).to.have.been.calledWith([contact]);
});
it('should add the contact to the all contacts list on CONTACT_EVENTS.CREATED event', function() {
var currentAddressbooks = [{ bookId: 'foobar', bookName: 'bookName1' }, { bookId: 'foobar', bookName: 'bookName2' }];
var contact = {
lastName: 'Last',
addressbook: currentAddressbooks[0]
};
var addItemsMock = sinon.spy();
var AlphaCategoryService = function() {
return {
addItems: addItemsMock,
get: function() {}
};
};
contactAddressbookService.listAggregatedAddressbooks = sinon.stub().returns($q.when(currentAddressbooks));
initController(AlphaCategoryService);
scope.contactSearch.searchInput = null;
$rootScope.$broadcast(CONTACT_EVENTS.CREATED, contact);
$rootScope.$digest();
expect(addItemsMock).to.have.been.calledWith([contact]);
});
it('should not add the contact to the contact list of other addressbooks on CONTACT_EVENTS.CREATED event', function() {
var userId = '123';
var currentAddressbooks = [{ bookId: userId, bookName: 'bookName1' }];
var contact = {
lastName: 'Last',
addressbook: {
bookId: userId,
bookName: 'bookName2'
}
};
var addItemsMock = sinon.spy();
var AlphaCategoryService = function() {
return {
addItems: addItemsMock,
get: function() {}
};
};
$stateParams.bookName = 'bookName1';
contactAddressbookService.getAddressbookByBookName = sinon.stub().returns($q.when(currentAddressbooks));
initController(AlphaCategoryService);
scope.contactSearch.searchInput = null;
$rootScope.$broadcast(CONTACT_EVENTS.CREATED, contact);
$rootScope.$digest();
expect(addItemsMock).to.not.have.been.calledWith([contact]);
});
it('should not live refresh the search result list', function() {
var currentAddressbooks = [{ bookId: 'foo', bookName: 'bar' }];
var contact = {
lastName: 'Last',
addressbook: currentAddressbooks[0]
};
var mySpy = sinon.spy();
var addItemsSpy = sinon.spy();
var AlphaCategoryService = function() {
return {
addItems: addItemsSpy,
removeItemWithId: mySpy,
replaceItem: mySpy,
get: function() {}
};
};
contactAddressbookService.listAggregatedAddressbooks = sinon.stub().returns($q.when(currentAddressbooks));
initController(AlphaCategoryService);
scope.contactSearch.searchInput = 'someQuery';
$rootScope.$broadcast(CONTACT_EVENTS.CREATED, contact);
$rootScope.$broadcast(CONTACT_EVENTS.UPDATED, contact);
$rootScope.$broadcast(CONTACT_EVENTS.DELETED, contact);
$rootScope.$digest();
expect(addItemsSpy).to.not.have.been.calledWith([contact]);
expect(mySpy).to.have.been.callCount(0);
});
it('should update the contact in all contacts list on CONTACT_EVENTS.UPDATED event', function() {
var userId = '123';
var currentAddressbooks = [{ bookId: userId, bookName: 'bookName1' }, { bookId: userId, bookName: 'bookName2' }];
var contact = {
id: '123456',
lastName: 'Last',
addressbook: currentAddressbooks[0]
};
var replaceItemMock = sinon.spy();
var AlphaCategoryService = function() {
return {
addItems: function() {},
get: function() {},
replaceItem: replaceItemMock
};
};
contactAddressbookService.listAggregatedAddressbooks = sinon.stub().returns($q.when(currentAddressbooks));
initController(AlphaCategoryService);
$rootScope.$broadcast(CONTACT_EVENTS.UPDATED, contact);
$rootScope.$digest();
$timeout.flush();
expect(replaceItemMock).to.have.been.calledWith(contact);
});
it('should update the contact in the contacts list of addressbook on CONTACT_EVENTS.UPDATED event', function() {
var userId = '123';
var currentAddressbooks = [{ bookId: userId, bookName: 'bookName1' }];
var contact = {
id: '123456',
lastName: 'Last',
addressbook: currentAddressbooks[0]
};
var replaceItemMock = sinon.spy();
var AlphaCategoryService = function() {
return {
addItems: function() {},
get: function() {},
replaceItem: replaceItemMock
};
};
$stateParams.bookName = 'bookName1';
contactAddressbookService.getAddressbookByBookName = sinon.stub().returns($q.when(currentAddressbooks));
initController(AlphaCategoryService);
$rootScope.$broadcast(CONTACT_EVENTS.UPDATED, contact);
$rootScope.$digest();
$timeout.flush();
expect(replaceItemMock).to.have.been.calledWith(contact);
});
it('should store contact id in contactUpdatedIds on CONTACT_EVENTS.UPDATED event', function(done) {
var contact = {
id: '123456',
lastName: 'Last'
};
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
},
contactUpdateDataService: {
contactUpdatedIds: {
indexOf: function() {
return -1;
},
push: function() {
done();
}
}
}
});
$rootScope.$broadcast(CONTACT_EVENTS.UPDATED, contact);
$rootScope.$digest();
});
it('should load contact list when no query is specified in the URL', function(done) {
var query = null;
var locationMock = {
search: function() {
return {
q: query
};
}
};
createPaginationMocks(function() {
done();
}, function() {
done(new Error('This test should not call search function'));
});
$controller('ContactListController', {
$location: locationMock,
$scope: scope,
user: {
_id: '123'
}
});
$rootScope.$digest();
});
it('should not load contact list when no query is specified in the URL and a request is ongoing', function(done) {
var query = null;
var locationMock = {
search: function() {
return {
q: query
};
}
};
scope.loadingNextContacts = true;
createPaginationMocks(function() {
done(new Error('This test should not call list function'));
}, function() {
done(new Error('This test should not call search function'));
});
$controller('ContactListController', {
$location: locationMock,
$scope: scope,
user: {
_id: '123'
}
});
$rootScope.$digest();
done();
});
it('should load search result list when a query is specified in the URL', function(done) {
var query = 'Chuck Norris';
var locationMock = {
search: function() {
return {
q: query
};
}
};
createPaginationMocks(function() {
done(new Error('Should not be called'));
}, function() {
expect(scope.contactSearch.searchInput).to.equal(query);
done();
});
$controller('ContactListController', {
$location: locationMock,
$scope: scope,
user: {
_id: '123'
}
});
$rootScope.$digest();
});
it('should update the search when a query is stored in sharedContactDataService', function(done) {
var query = 'Chuck Norris';
var locationMock = {
search: function(s, value) {
if (s) {
expect(s).to.equal('q');
expect(value).to.equal('Chuck+Norris');
done();
} else {
return { q: null };
}
}
};
createPaginationMocks(function() {
return done(new Error('This test should not call list function'));
}, function() {
done();
});
$controller('ContactListController', {
$location: locationMock,
sharedContactDataService: { searchQuery: query },
$scope: scope,
user: {
_id: '123'
}
});
$rootScope.$digest();
});
it('should refresh list on route update when the queries in the URL and in the search input are different', function(done) {
var query = 'QueryA';
var mySpy = sinon.spy();
var locationMock = {
search: function() {
return {
q: query
};
}
};
createPaginationMocks(function() {
return done(new Error('This test should not call list function'));
}, function(options) {
expect(scope.contactSearch.searchInput).to.equal(options.searchInput);
mySpy();
return $q.when({
data: [],
total_hits: 0
});
});
$controller('ContactListController', {
$scope: scope,
$location: locationMock,
user: {
_id: '123'
}
});
scope.$digest();
scope.contactSearch.searchInput = 'QueryB';
scope.$digest();
$rootScope.$broadcast('$stateChangeSuccess', {name: '/some/other/place'});
expect(scope.contactSearch.searchInput).to.equal(query);
expect(mySpy).to.have.been.calledTwice;
done();
});
it('should not refresh list on route update when the queries in the URL and in the search input are the same', function(done) {
var query = 'QueryA';
var mySpy = sinon.spy();
var locationMock = {
search: function() {
return {
q: query
};
}
};
createPaginationMocks(function() {
return done(new Error('This test should not call list function'));
}, function() {
expect(scope.contactSearch.searchInput).to.equal(query);
mySpy();
return $q.when([]);
});
$controller('ContactListController', {
$scope: scope,
$location: locationMock,
user: {
_id: '123'
}
});
scope.$digest();
scope.contactSearch.searchInput = 'QueryA';
$rootScope.$broadcast('$stateChangeSuccess', {});
expect(scope.contactSearch.searchInput).to.equal(query);
expect(mySpy).to.have.been.calledOnce;
done();
});
it('should add no item to the categories when pagination returns an empty list', function(done) {
createPaginationMocks(function() {
return $q.when({data: []});
}, function() {
done(new Error('Should not be called'));
});
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
$rootScope.$digest();
$rootScope.$digest();
expect(scope.sorted_contacts).to.deep.equal(sortedContacts);
done();
});
it('should sort contacts by FN', function(done) {
var contactWithA = { displayName: 'A B'},
contactWithC = { displayName: 'C D' };
createPaginationMocks(function() {
return $q.when({data: [contactWithA, contactWithC]});
}, function() {
done(new Error('Should not be called'));
});
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
sortedContacts.A = [contactWithA];
sortedContacts.C = [contactWithC];
$rootScope.$digest();
$timeout(function() {
expect(scope.sorted_contacts).to.deep.equal(sortedContacts);
done();
});
$timeout.flush();
});
it('should correctly sort contacts when multiple contacts have the same FN', function(done) {
var contact1 = { id: 1, displayName: 'A B'},
contact2 = { id: 2, displayName: 'A B' };
createPaginationMocks(function() {
return $q.when({data: [contact1, contact2]});
}, function() {
done(new Error('Should not be called'));
});
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
sortedContacts.A = [contact1, contact2];
$rootScope.$digest();
$timeout(function() {
expect(scope.sorted_contacts).to.deep.equal(sortedContacts);
done();
});
$timeout.flush();
});
it('should correctly sort contacts when multiple contacts have the same beginning of FN', function(done) {
var contact1 = { displayName: 'A B'},
contact2 = { displayName: 'A C' };
createPaginationMocks(function() {
return $q.when({data: [contact1, contact2]});
}, function() {
done(new Error('Should not be called'));
});
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
sortedContacts.A = [contact1, contact2];
$rootScope.$digest();
$timeout(function() {
expect(scope.sorted_contacts).to.deep.equal(sortedContacts);
done();
});
$timeout.flush();
});
it('should correctly sort contacts when some contacts does not have FN', function(done) {
var contact1 = { firstName: 'A'},
contact2 = { displayName: 'A C'},
contact3 = { id: '123' };
createPaginationMocks(function() {
return $q.when({data: [contact1, contact2, contact3]});
}, function() {
done(new Error('Should not be called'));
});
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
sortedContacts.A = [{displayName: contact1.firstName, firstName: contact1.firstName}, contact2];
sortedContacts['#'] = [{displayName: contact3.id, id: contact3.id}];
$rootScope.$digest();
$timeout(function() {
expect(scope.sorted_contacts).to.deep.equal(sortedContacts);
done();
});
$timeout.flush();
});
describe('The createPagination function', function() {
var user = {
_id: 1
};
it('should set the $scope.mode', function() {
createPaginationMocks(function() {
return $q.when([]);
});
$controller('ContactListController', {
$scope: scope,
user: user
});
var mode = CONTACT_LIST_DISPLAY_MODES.single;
scope.createPagination(mode);
expect(scope.mode).to.equal(mode);
});
it('should call pagination#init', function(done) {
addressbooks.push({id: 1, name: 'foo'});
addressbooks.push({id: 2, name: 'bar'});
var mode = CONTACT_LIST_DISPLAY_MODES.list;
initController();
scope.pagination.init = function(_mode, _options) {
expect(_mode).to.equal(mode);
expect(_options.user).to.exist;
expect(_options.addressbooks).to.deep.equal(addressbooks);
done();
};
scope.createPagination(mode);
done(new Error());
});
});
describe('The clearSearchInput function', function() {
it('should clear search input and all search results', function() {
var user = {_id: 123};
scope.contactSearch = {
searchInput: 'name'
};
scope.searchResult = {
data: ['name1', 'name2', 'name3']
};
scope.totalHits = 3;
scope.loadContacts = function() {};
$controller('ContactListController', {
$scope: scope,
user: user
});
scope.clearSearchInput();
expect(scope.contactSearch.searchInput).to.be.null;
expect(scope.searchResult).to.deep.equal({});
expect(scope.totalHits).to.equal(0);
});
it('should load contacts after clear input', function(done) {
var user = {_id: 123};
createPaginationMocks(function() {
done();
}, function() {
done(new Error('Should not be called'));
});
scope.loadContacts = sinon.spy();
$controller('ContactListController', {
$scope: scope,
user: user
});
scope.clearSearchInput();
$rootScope.$digest();
});
it('should update location after clear input', function(done) {
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
scope.appendQueryToURL = done;
scope.clearSearchInput();
$rootScope.$digest();
});
});
describe('The loadContacts function', function() {
it('should call the addressBookPaginationService vcard list fn', function(done) {
var user = {_id: 123};
createPaginationMocks(function() {
done();
}, function() {
done(new Error('Should not be called'));
});
$controller('ContactListController', {
$scope: scope,
user: user
});
scope.loadContacts();
$rootScope.$digest();
});
it('should set status to "loading"', function() {
contactAddressbookService.listAggregatedAddressbooks = sinon.stub().returns($q.when([]));
var controller = initController();
$timeout.flush();
expect(controller.status).to.equal('loaded');
scope.loadContacts();
$rootScope.$digest();
expect(controller.status).to.equal('loading');
});
it('should set status to "loaded" after contacts are loaded', function() {
contactAddressbookService.listAggregatedAddressbooks = sinon.stub().returns($q.when([]));
var controller = initController();
$timeout.flush();
expect(controller.status).to.equal('loaded');
scope.loadContacts();
$rootScope.$digest();
expect(controller.status).to.equal('loading');
$timeout.flush();
expect(controller.status).to.equal('loaded');
});
it('should display error when pagination fails', function(done) {
var user = {_id: 123};
createPaginationMocks(function() {
return $q.reject('WTF');
}, function() {
done(new Error('Should not be called'));
});
$alert.alert = function(options) {
expect(options.content).to.match(/Can not get contacts/);
done();
};
$controller('ContactListController', {
$scope: scope,
user: user
});
scope.loadContacts();
scope.$digest();
});
});
describe('The openContactCreation function', function() {
it('should open create form for default address book if user clicks on create contact button while viewing all contacts', function() {
var currentAddressbooks = [{
bookName: 'twitter',
editable: false
}, {
bookName: 'collected',
editable: true
}];
contactAddressbookService.listAggregatedAddressbooks = sinon.stub().returns($q.when(currentAddressbooks));
initController();
scope.openContactCreation();
expect(openContactFormMock).to.have.been.calledWith(scope.bookId, DEFAULT_ADDRESSBOOK_NAME);
});
it('should open the contact creation form for specific address book if user is viewing that address book', function() {
var bookName = 'foobar';
$stateParams.bookName = bookName;
addressbooks = [{ bookName: bookName }];
contactAddressbookService.getAddressbookByBookName = sinon.stub().returns($q.when(addressbooks));
initController();
scope.openContactCreation();
expect(openContactFormMock).to.have.been.calledWith(scope.bookId, bookName);
});
});
describe('The search function', function() {
it('should set status to "loading" when searching contacts', function() {
var controller = initController();
$timeout.flush();
expect(controller.status).to.equal('loaded');
scope.search();
$rootScope.$digest();
expect(controller.status).to.equal('loading');
});
it('should stop the throbber when finished searching contacts', function() {
var controller = initController();
$timeout.flush();
expect(controller.status).to.equal('loaded');
scope.search();
$rootScope.$digest();
expect(controller.status).to.equal('loading');
$timeout.flush();
expect(controller.status).to.equal('loaded');
});
it('should clean previous search results', function(done) {
createPaginationMocks(function() {
return $q.when([]);
}, function() {
done(new Error('Should not be called'));
});
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
scope.searchResult = 1;
scope.loadContacts = function() {};
scope.search();
scope.$digest();
expect(scope.searchResult).to.deep.equal({});
done();
});
it('should update location on each search', function(done) {
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
scope.appendQueryToURL = done;
scope.search();
});
it('should clean search result data', function(done) {
createPaginationMocks(function() {
return $q.when({ contacts: [] });
}, function() {
done(new Error('Should not be called'));
});
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
},
AlphaCategoryService: function() {
return {
init: function() {
}
};
}
});
scope.searchResult = {
data: 1
};
scope.loadContacts = function() {};
scope.search();
scope.$digest();
expect(scope.searchMode).isTrue;
expect(scope.searchResult.data).to.not.exist;
done();
});
it('should quit search mode and get all the user contacts when searchInput is undefined', function(done) {
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
scope.loadContacts = function() {
expect(scope.searchMode).isFalse;
done();
};
scope.search();
scope.$digest();
});
it('should update the contacts list on search success', function() {
var search = 'Bruce Willis';
var contactWithA = { displayName: 'A B'};
var contactWithB = { displayName: 'B C'};
var contactWithC = { displayName: 'C D'};
var result = {
total_hits: 2,
current_page: 1,
data: [contactWithA, contactWithC]
};
createPaginationMocks(function() {
return $q.when([contactWithA, contactWithB, contactWithC]);
}, function() {
return $q.when(result);
});
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
},
bookId: '456'
});
scope.contactSearch.searchInput = search;
scope.totalHits = 0;
scope.search();
scope.$digest();
expect(scope.searchResult.data).to.deep.equal(result.data);
expect(scope.searchResult.count).to.equal(2);
expect(scope.searchResult.formattedResultsCount).to.exist;
expect(scope.searchFailure).to.be.false;
});
it('should contactDisplayError on search failure', function(done) {
var search = 'Bruce Willis';
createPaginationMocks(function() {
return $q.when([]);
}, function() {
return $q.reject(new Error('Search failure'));
});
$controller('ContactListController', {
$scope: scope,
contactDisplayError: function(error) {
expect(error).to.match(/Can not search contacts/);
done();
},
user: {
_id: '123'
},
bookId: '456'
});
scope.contactSearch.searchInput = search;
scope.search();
scope.$digest();
});
it('should prevent fetching next results page while loading current result page', function() {
var search = 'Bruce Willis';
var contactWithA = { displayName: 'A B'};
var contactWithB = { displayName: 'B C'};
var contactWithC = { displayName: 'C D'};
var contactWithD = { displayName: 'D E'};
var contactWithE = { displayName: 'E F'};
var result = {
total_hits: 4,
data: [contactWithA, contactWithB]
};
createPaginationMocks(function() {
return $q.when([contactWithA, contactWithB, contactWithC, contactWithD, contactWithE]);
}, function() {
return $q.when(result);
});
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
},
bookId: '456'
});
scope.contactSearch.searchInput = search;
scope.search();
expect(scope.loadingNextContacts).to.be.true;
scope.$digest();
expect(scope.searchFailure).to.be.false;
expect(scope.loadingNextContacts).to.be.false;
});
it('should allow fetching next result page when there are undisplayed results', function() {
var search = 'Bruce Willis';
var contactWithA = { displayName: 'A B'};
var contactWithB = { displayName: 'B C'};
var contactWithC = { displayName: 'C D'};
var contactWithD = { displayName: 'D E'};
var contactWithE = { displayName: 'E F'};
var result = {
total_hits: 4,
data: [contactWithA, contactWithB]
};
createPaginationMocks(function() {
return $q.when([contactWithA, contactWithB, contactWithC, contactWithD, contactWithE]);
}, function() {
return $q.when(result);
});
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
},
bookId: '456'
});
scope.$digest();
scope.contactSearch.searchInput = search;
scope.totalHits = 0;
scope.search();
scope.$digest();
expect(scope.searchFailure).to.be.false;
expect(scope.lastPage).to.be.false;
});
it('should prevent fetching next result page when the previous search fails', function() {
var search = 'Bruce Willis';
createPaginationMocks(function() {
return $q.when([]);
}, function() {
return $q.reject(new Error('Fail'));
});
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
},
bookId: '456'
});
scope.contactSearch.searchInput = search;
scope.search();
scope.$digest();
expect(scope.searchFailure).to.be.true;
});
it('should prevent search when previous search is not complete', function() {
var search = 'Bruce Willis';
var called = 0;
var promise = $q.defer().promise;
createPaginationMocks(function() {
return $q.when([]);
}, function() {
called++;
// the search will be never resolved
return promise;
});
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
},
bookId: '456',
$location: {
search: function() {
return {};
}
}
});
$rootScope.$digest();
scope.appendQueryToURL = function() {};
scope.contactSearch.searchInput = search;
scope.$digest();
scope.search();
scope.$digest();
scope.search();
scope.$digest();
expect(called).to.equal(1);
});
it('should store the search input value if the previous search request is still pending', function() {
var endOfSearch = $q.defer();
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
$rootScope.$digest();
scope.appendQueryToURL = scope.createPagination = angular.noop;
scope.pagination.service.loadNextItems = function(searchQuery) {
if (searchQuery) {
return endOfSearch.promise;
}
return $q.reject(new Error('Fail'));
};
scope.contactSearch.searchInput = 'openpaas';
scope.search();
scope.$digest();
scope.contactSearch.searchInput = 'openpaasng';
scope.search();
scope.$digest();
expect(scope.updatedDuringSearch).to.equal('openpaasng');
});
it('should reset the stored value if a new search request occurs and no changes occured between', function() {
var endOfSearch;
var fakeResult = {
total_hits: 0,
data: []
};
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
$rootScope.$digest();
scope.appendQueryToURL = scope.createPagination = angular.noop;
scope.pagination.service.loadNextItems = function(searchQuery) {
if (searchQuery) {
endOfSearch = $q.defer();
return endOfSearch.promise;
}
return $q.reject(new Error('Fail'));
};
scope.contactSearch.searchInput = 'openpaas';
scope.search();
scope.$digest();
endOfSearch.resolve(fakeResult);
scope.search();
scope.$digest();
expect(scope.updatedDuringSearch).to.be.null;
});
it('should send a new query search if a stored value exists', function() {
var endOfSearch;
var fakeResult = {
total_hits: 0,
data: []
};
var searchRequests = 0;
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
$rootScope.$digest();
scope.appendQueryToURL = scope.createPagination = angular.noop;
scope.pagination.service.loadNextItems = function(searchQuery) {
if (searchQuery) {
searchRequests++;
endOfSearch = $q.defer();
return endOfSearch.promise;
}
return $q.reject(new Error('Fail'));
};
scope.contactSearch.searchInput = 'openpaas';
scope.search();
scope.$digest();
scope.contactSearch.searchInput = 'openpaasng';
endOfSearch.resolve(fakeResult);
scope.search();
scope.$digest();
expect(searchRequests).to.equal(2);
});
it('should not send a new query search if no changes occured during a search query', function() {
var endOfSearch;
var fakeResult = {
total_hits: 0,
data: []
};
var searchRequests = 0;
$controller('ContactListController', {
$scope: scope,
user: {
_id: '123'
}
});
$rootScope.$digest();
scope.appendQueryToURL = scope.createPagination = angular.noop;
scope.pagination.service.loadNextItems = function(searchQuery) {
if (searchQuery) {
searchRequests++;
endOfSearch = $q.defer();
return endOfSearch.promise;
}
return $q.reject(new Error('Fail'));
};
scope.contactSearch.searchInput = 'openpaas';
scope.search();
scope.$digest();
endOfSearch.resolve(fakeResult);
expect(searchRequests).to.equal(1);
});
});
describe('When Deleted Addressbook event is fired', function() {
it('should change to aggregated contacts view if the current viewing addressbook is deleted', function() {
var bookName = 'twitter';
var currentAddressbooks = [{
bookName: bookName
}];
$state.go = sinon.spy();
$stateParams.bookName = bookName;
contactAddressbookService.getAddressbookByBookName = sinon.stub().returns($q.when(currentAddressbooks));
initController();
$rootScope.$broadcast(CONTACT_ADDRESSBOOK_EVENTS.DELETED, { bookName: bookName });
expect($state.go).to.have.been.calledWith('contact.addressbooks', { bookName: null });
});
it('should not change state if the current viewing addressbook is not the one is deleted', function() {
var currentAddressbooks = [{
bookName: 'twitter',
name: 'Twitter Contacts'
}];
$state.go = sinon.spy();
$controller('ContactListController', {
$scope: scope,
user: { _id: '123' },
addressbooks: currentAddressbooks
});
$rootScope.$broadcast(CONTACT_ADDRESSBOOK_EVENTS.DELETED, { bookName: 'google' });
expect($state.go).to.not.have.been.called;
});
});
describe('When Updated Addressbook event is fired', function() {
it('should update addressbook title in subheader if the current viewing addressbook is updated', function() {
var currentAddressbooks = [{
bookName: 'twitter'
}];
$stateParams.bookName = 'twitter';
contactAddressbookService.getAddressbookByBookName = sinon.stub().returns($q.when(currentAddressbooks));
initController();
$rootScope.$broadcast(CONTACT_ADDRESSBOOK_EVENTS.UPDATED, {
name: 'Twitter Contacts',
bookName: 'twitter'
});
expect(scope.bookTitle).to.equal('Twitter Contacts');
});
it('should not update addressbook title in subheader if the current viewing addressbook is not the one is updated', function() {
var currentAddressbooks = [{
bookName: 'twitter',
name: 'Twitter Contacts'
}];
$stateParams.bookName = 'twitter';
contactAddressbookService.getAddressbookByBookName = sinon.stub().returns($q.when(currentAddressbooks));
initController();
$rootScope.$broadcast(CONTACT_ADDRESSBOOK_EVENTS.UPDATED, {
name: 'Google Contacts',
bookName: 'goole'
});
expect(scope.bookTitle).to.equal('Twitter Contacts');
});
});
describe('When deleted addressbook subscription event is fired', function() {
it('should change to aggregated contacts view if the current viewing addressbook is deleted', function() {
var bookName = 'twitter';
var currentAddressbooks = [{
bookName: bookName
}];
$state.go = sinon.spy();
$stateParams.bookName = bookName;
contactAddressbookService.getAddressbookByBookName = sinon.stub().returns($q.when(currentAddressbooks));
initController();
$rootScope.$broadcast(CONTACT_ADDRESSBOOK_EVENTS.SUBSCRIPTION_DELETED, { bookName: bookName });
expect($state.go).to.have.been.calledWith('contact.addressbooks', { bookName: null });
});
it('should not change state if the current viewing addressbook is not the one is deleted', function() {
var currentAddressbooks = [{
bookName: 'twitter',
name: 'Twitter Contacts'
}];
$state.go = sinon.spy();
$controller('ContactListController', {
$scope: scope,
user: { _id: '123' },
addressbooks: currentAddressbooks
});
$rootScope.$broadcast(CONTACT_ADDRESSBOOK_EVENTS.SUBSCRIPTION_DELETED, { bookName: 'google' });
expect($state.go).to.not.have.been.called;
});
});
});