UNPKG

linagora-rse

Version:
778 lines (579 loc) 27 kB
'use strict'; /* global chai, moment, sinon, _: false */ var expect = chai.expect; describe('The esn.provider module', function() { var nowDate = new Date('2015-08-20T04:00:00Z'), localTimeZone = 'Europe/Paris', uuid4; beforeEach(function() { angular.mock.module('angularMoment'); angular.mock.module('esn.provider'); }); beforeEach(module(function($provide) { $provide.value('localTimezone', 'UTC'); $provide.constant('moment', function(argument) { return moment.tz(argument || nowDate, localTimeZone); }); $provide.value('uuid4', uuid4 = { generate: sinon.spy() }); })); describe('The Providers factory', function() { var $rootScope, providers, newProvider; beforeEach(inject(function(_$rootScope_, _Providers_, _newProvider_) { $rootScope = _$rootScope_; providers = new _Providers_(); newProvider = _newProvider_; })); describe('The newProvider factory', function() { it('should generate an id with uuid4 for a provider without an id', function() { uuid4.generate = sinon.spy(function() { return '123'; }); var provider = newProvider({ name: 'provider', type: 'type1' }); expect(provider.id).to.equal('123'); expect(uuid4.generate).to.have.been.calledWith; }); it('should not generate any id for a provider with existing id', function() { var provider = newProvider({ name: 'provider', type: 'type1', id: '456' }); expect(provider.id).to.equal('456'); expect(uuid4.generate).to.not.have.been.called; }); it('should create types array when not present', function() { expect(newProvider({ type: 'type1' }).types).to.deep.equal(['type1']); }); it('should use types array when present', function() { expect(newProvider({ types: ['type1', 'type2'] }).types).to.deep.equal(['type1', 'type2']); }); it('should derive type from types array when not present', function() { expect(newProvider({ types: ['type2', 'type1'] }).type).to.equal('type2'); }); it('should use type when present', function() { expect(newProvider({ type: 'type1' }).type).to.equal('type1'); }); it('should return the provider\'s main fetcher', function() { var fetcher = function() {}, provider = newProvider({ id: 'id', fetch: fetcher }); expect(provider.fetch).to.be.a('function'); }); it('should use account when present', function() { expect(newProvider({ account: 'myAccount' }).account).to.equal('myAccount'); }); it('should use itemMatches when present', function() { var itemMatches = function() {}; expect(newProvider({ itemMatches: itemMatches }).itemMatches).to.equal(itemMatches); }); }); describe('The getAllProviderDefinitions function', function() { it('should return an array containing names, ids and uids of added providers', function() { var spy = sinon.spy(); providers.add($q.when({ id: 1, name: 'provider1', uid: 'uid1', property: 'value' })); providers.add({ id: 2, name: 'provider2', uid: 'uid2', another: 'value2' }); providers.getAllProviderDefinitions().then(spy); $rootScope.$digest(); expect(spy).to.have.been.calledWith([ { id: 1, name: 'provider1', uid: 'uid1' }, { id: 2, name: 'provider2', uid: 'uid2' } ]); }); }); describe('The getAll function', function() { it('should return all providers when no acceptedTypes is given', function(done) { providers.add({ name: 'provider', type: 'type1', buildFetchContext: sinon.stub().returns($q.when()), fetch: sinon.stub().returns($q.when()) }); providers.add($q.when({ name: 'provider2', type: 'type2', buildFetchContext: sinon.stub().returns($q.when()), fetch: sinon.stub().returns($q.when()) })); providers.getAll({}).then(function(resolvedProviders) { expect(resolvedProviders).to.shallowDeepEqual([ { name: 'provider', type: 'type1'}, { name: 'provider2', type: 'type2'} ]); done(); }); $rootScope.$digest(); }); it('should filter providers that are not in the acceptedTypes array', function(done) { providers.add({ name: 'provider', type: 'type1', buildFetchContext: sinon.stub().returns($q.when()), fetch: sinon.stub().returns($q.when()) }); providers.add({ name: 'provider2', type: 'type2', buildFetchContext: sinon.stub().returns($q.when()), fetch: sinon.stub().returns($q.when()) }); providers.getAll({acceptedTypes: ['type1']}).then(function(resolvedProviders) { expect(resolvedProviders).to.shallowDeepEqual([{ name: 'provider', type: 'type1'}]); done(); }); $rootScope.$digest(); }); it('should filter providers that are not in the acceptedTypes array, when provider has multiple types', function(done) { providers.add({ name: 'provider', types: ['type1', 'type2'], buildFetchContext: sinon.stub().returns($q.when()), fetch: sinon.stub().returns($q.when()) }); providers.getAll({ acceptedTypes: ['type3'] }).then(function(providers) { expect(providers).to.deep.equal([]); done(); }); $rootScope.$digest(); }); it('should include providers that are in the acceptedTypes array, when provider has multiple types', function(done) { providers.add({ name: 'provider', types: ['type1', 'type2'], buildFetchContext: sinon.stub().returns($q.when()), fetch: sinon.stub().returns($q.when()) }); providers.getAll({ acceptedTypes: ['type2'] }).then(function(providers) { expect(providers).to.shallowDeepEqual([{ name: 'provider' }]); done(); }); $rootScope.$digest(); }); it('should filter providers that are not in the acceptedIds array', function(done) { providers.add({ name: 'provider', type: 'type1', id: '123', buildFetchContext: sinon.stub().returns($q.when()), fetch: sinon.stub().returns($q.when()) }); providers.add({ name: 'provider2', type: 'type2', id: '456', buildFetchContext: sinon.stub().returns($q.when()), fetch: sinon.stub().returns($q.when()) }); providers.getAll({acceptedIds: ['456']}).then(function(resolvedProviders) { expect(resolvedProviders).to.shallowDeepEqual([{ name: 'provider2', type: 'type2', id: '456'}]); done(); }); $rootScope.$digest(); }); it('should build the fetch context of each provider using its own buildFetchContext function', function(done) { var getAllOptions = {expected: 'options'}, provider1 = { name: 'provider', type: 'type1', buildFetchContext: sinon.stub().returns($q.when('context1')), fetch: sinon.stub().returns($q.when()) }, provider2 = { name: 'provider2', type: 'type2', buildFetchContext: sinon.stub().returns($q.when('context2')), fetch: sinon.stub().returns($q.when()) }; providers.add(provider1); providers.add(provider2); providers.getAll(getAllOptions).then(function() { expect(provider1.buildFetchContext).to.have.been.calledWith(getAllOptions); expect(provider2.buildFetchContext).to.have.been.calledWith(getAllOptions); expect(provider1.fetch).to.have.been.calledWith('context1'); expect(provider2.fetch).to.have.been.calledWith('context2'); done(); }); $rootScope.$digest(); }); it('should skip providers unable to build their fetch contexts', function(done) { providers.add({ name: 'provider', type: 'type1', buildFetchContext: sinon.stub().returns($q.reject(new Error('WTF'))) }); providers.add({ name: 'provider2', type: 'type2', buildFetchContext: sinon.stub().returns($q.when('context2')), fetch: sinon.stub().returns($q.when()) }); providers.getAll().then(function(providers) { expect(providers).to.have.length(1); done(); }); $rootScope.$digest(); }); }); describe('The remove method', function() { var provider1, provider2, provider3, provider4, provider5; beforeEach(function() { provider1 = {id: 1, name: '1', uid: '1'}; provider2 = {id: 2, name: '2', uid: '2'}; provider3 = {id: 3, name: '3', uid: '3'}; provider4 = {id: 4, name: '4', uid: '4'}; provider5 = {id: 5, name: '5', uid: '5'}; [provider1, provider2, [provider3, provider4], provider5].forEach(function(provider) { providers.add(provider); }); }); it('should not remove any provider if any match', function() { var thenSpy = sinon.spy(); providers.remove(_.constant(false)); $rootScope.$digest(); providers.getAllProviderDefinitions().then(thenSpy); $rootScope.$digest(); expect(thenSpy).to.have.been.calledWith(_.flatten([provider1, provider2, provider3, provider4, provider5])); }); it('should correctly remove top level provider', function() { var thenSpy = sinon.spy(); providers.remove(function(provider) { return provider.id === 1; }); $rootScope.$digest(); providers.getAllProviderDefinitions().then(thenSpy); $rootScope.$digest(); expect(thenSpy.firstCall).to.have.been.calledWith(_.flatten([provider2, provider3, provider4, provider5])); providers.remove(function(provider) { return provider.id === 5; }); $rootScope.$digest(); providers.getAllProviderDefinitions().then(thenSpy); $rootScope.$digest(); expect(thenSpy.secondCall).to.have.been.calledWith(_.flatten([provider2, provider3, provider4])); $rootScope.$digest(); }); it('should correctly remove not top level provider', function() { var thenSpy = sinon.spy(); providers.remove(function(provider) { return provider.id === 3; }); $rootScope.$digest(); providers.getAllProviderDefinitions().then(thenSpy); $rootScope.$digest(); expect(thenSpy.firstCall).to.have.been.calledWith(_.flatten([provider1, provider2, provider4, provider5])); }); }); }); describe('The ByTypeElementGroupingTool factory', function() { var ByTypeElementGroupingTool; beforeEach(inject(function(_ByTypeElementGroupingTool_) { ByTypeElementGroupingTool = _ByTypeElementGroupingTool_; })); it('should build an array of empty types group objects', function() { var elementGroupingTool = new ByTypeElementGroupingTool([ 'Events', 'Contacts', 'Emails' ]); expect(elementGroupingTool.getGroupedElements()).to.deep.equal([ {name: 'Events', elements: []}, {name: 'Contacts', elements: []}, {name: 'Emails', elements: []} ]); }); it('should push a received element into the correct type group', function() { var elementGroupingTool = new ByTypeElementGroupingTool([ 'Events', 'Contacts', 'Emails' ], [ {type: 'Events', title: 'anEvent'}, {type: 'Emails', email: 'anEmail'}, {type: 'Events', title: 'anEvent2'}, {type: 'Contacts', name: 'aContact'}, {type: 'Contacts', name: 'aContact2'} ]); expect(elementGroupingTool.getGroupedElements()).to.deep.equal([ {name: 'Events', elements: [ {type: 'Events', title: 'anEvent'}, {type: 'Events', title: 'anEvent2'} ]}, {name: 'Contacts', elements: [ {type: 'Contacts', name: 'aContact'}, {type: 'Contacts', name: 'aContact2'} ]}, {name: 'Emails', elements: [ {type: 'Emails', email: 'anEmail'} ]} ]); }); }); describe('The ByDateElementGroupingTool factory', function() { var ByDateElementGroupingTool; function assertGroups(tool, element, groupName) { var elements = tool.getGroupedElements(); expect(elements).to.have.length(1); expect(elements[0].date).to.equal(element.date); expect(elements[0].group.name).to.equal(groupName); } beforeEach(inject(function(_ByDateElementGroupingTool_) { ByDateElementGroupingTool = _ByDateElementGroupingTool_; })); it('should prevent insertion of duplicate items (items with same id)', function() { var tool = new ByDateElementGroupingTool(); tool.addElement({ id: '000', date: 1 }); tool.addElement({ id: '123', date: 2 }); tool.addElement({ id: '123', date: 3 }); tool.addElement({ id: '555', date: 4 }); expect(_.pluck(tool.getGroupedElements(), 'id')).to.deep.equal(['555', '123', '000']); }); it('should allow insertion of an item with same id if previous item is removed', function() { var tool = new ByDateElementGroupingTool(), item = { id: '123', date: 2 }; tool.addElement({ id: '000', date: 1 }); tool.addElement(item); tool.addElement({ id: '555', date: 4 }); expect(_.pluck(tool.getGroupedElements(), 'id')).to.deep.equal(['555', '123', '000']); tool.removeElement(item); tool.addElement(item); expect(_.pluck(tool.getGroupedElements(), 'id')).to.deep.equal(['555', '123', '000']); }); it('should allow insertion of an item with same id after reset', function() { var tool = new ByDateElementGroupingTool(), item = { id: '123', date: 2 }; tool.addElement({ id: '000', date: 1 }); tool.addElement(item); tool.addElement({ id: '555', date: 4 }); expect(_.pluck(tool.getGroupedElements(), 'id')).to.deep.equal(['555', '123', '000']); tool.reset(); tool.addElement(item); expect(_.pluck(tool.getGroupedElements(), 'id')).to.deep.equal(['123']); }); it('should maintain the array ordered by date in descending order', function() { var tool = new ByDateElementGroupingTool(); tool.addElement({ id: 1, date: 2 }); tool.addElement({ id: 2, date: 3 }); expect(_.pluck(tool.getGroupedElements(), 'date')).to.deep.equal([3, 2]); tool.addElement({ id: 3, date: 4 }); tool.addElement({ id: 4, date: 1 }); expect(_.pluck(tool.getGroupedElements(), 'date')).to.deep.equal([4, 3, 2, 1]); }); it('should return an empty array when no elements are added', function() { expect(new ByDateElementGroupingTool().getGroupedElements()).to.deep.equal([]); }); it('should put a received element in the today group if it has the now date', function() { var element = { date: nowDate }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'Today'); }); it('should put a received element in the today group if it has the midnight date', function() { var element = { date: '2015-08-20T00:10:00Z' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'Today'); }); it('should put a received element in the today group even if it has a future date', function() { var element = { date: '2015-08-21T00:10:00Z' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'Today'); }); it('should put a received element in the yesterday group if it is 1 day old', function() { var element = { date: '2015-08-19T20:00:00Z' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'Yesterday'); }); it('should put a received element in the week group if it is 2 days old, but in the same week', function() { var element = { date: '2015-08-18T04:00:00Z' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Week'); }); it('should put a received element in the week group if it is 4 days old, but in the same week', function() { var element = { date: '2015-08-16T04:00:00Z' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Week'); }); it('should put a received element in the month group if it is 7 days old, in the previous week', function() { var element = { date: '2015-08-13T04:00:00Z' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Month'); }); it('should put a received element in the month group if it is just older than one week', function() { var element = { date: '2015-08-12T22:00:00Z' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Month'); }); it('should put a received element in the week group if it is just newer than one week with both +7 TZ', function() { localTimeZone = 'Asia/Ho_Chi_Minh'; var element = { date: '2015-08-16T08:00:00+07:00' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Week'); }); it('should put a received element in the week group if it is just newer than one week when element +7 TZ', function() { localTimeZone = 'UTC'; var element = { date: '2015-08-16T08:00:00+07:00' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Week'); }); it('should put a received element in the week group if it is just newer than one week when now +7 TZ', function() { localTimeZone = 'Asia/Ho_Chi_Minh'; nowDate = new Date('2015-08-21T05:00:00+07:00'); var element = { date: '2015-08-16T01:00:00+00:00' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Week'); }); it('should put a received element in the month group if it is just older than one week with both +7 TZ', function() { localTimeZone = 'Asia/Ho_Chi_Minh'; var element = { date: '2015-08-15T23:00:00+07:00' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Month'); }); it('should put a received element in the month group if it is just older than one week when element +7 TZ', function() { localTimeZone = 'UTC'; var element = { date: '2015-08-15T05:00:00+07:00' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Month'); }); it('should put a received element in the month group if it is just older than one week when now +7 TZ', function() { localTimeZone = 'Asia/Ho_Chi_Minh'; var element = { date: '2015-08-15T22:00:00+00:00' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Month'); }); it('should put a received element in the month group if it is just older than one week with both -7 TZ', function() { localTimeZone = 'America/Los_Angeles'; var element = { date: '2015-08-15T15:00:00-07:00' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Month'); }); it('should put a received element in the month group if it is just older than one week when element -7 TZ', function() { localTimeZone = 'UTC'; var element = { date: '2015-08-15T15:00:00-07:00' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Month'); }); it('should put a received element in the month group if it is just older than one week when now -7 TZ', function() { localTimeZone = 'America/Los_Angeles'; var element = { date: '2015-08-15T22:00:00+00:00' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Month'); }); it('should put a received element in the month group if its date is the first of the month', function() { var element = { date: '2015-08-01T04:00:00Z' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'This Month'); }); it('should put a received element in the older group if its date is the last day of the previous month', function() { var element = { date: '2015-07-31T04:00:00Z' }, elementGroupingTool = new ByDateElementGroupingTool([element]); assertGroups(elementGroupingTool, element, 'Older than a month'); }); describe('The removeElement method', function() { it('should remove the element from group', function() { var element1 = { date: '2015-05-31T04:00:00Z' }, element2 = { date: '2015-07-31T04:00:00Z' }, elementGroupingTool = new ByDateElementGroupingTool([element1, element2]); elementGroupingTool.removeElement(element2); assertGroups(elementGroupingTool, element1, 'Older than a month'); }); }); describe('The removeElements method', function() { it('should remove all elements from group', function() { var element1 = { date: '2015-05-31T04:00:00Z' }, element2 = { date: '2015-07-31T04:00:00Z' }, elementGroupingTool = new ByDateElementGroupingTool([element1, element2]); elementGroupingTool.removeElements([element2, element1]); expect(elementGroupingTool.getGroupedElements()).to.deep.equal([]); }); }); describe('The getById method', function() { it('should return undefined if the element does not exist', function() { expect(new ByDateElementGroupingTool().getById('nonExistentId')).to.equal(undefined); }); it('should return the element if the it exists', function() { var elementGroupingTool = new ByDateElementGroupingTool(), element = { id: 'myId', date: '2015-05-31T04:00:00Z' }; elementGroupingTool.addElement(element); expect(elementGroupingTool.getById('myId')).to.equal(element); }); }); }); describe('The sortByDateInDescendingOrder factory', function() { var sortByDateInDescendingOrder; beforeEach(inject(function(_sortByDateInDescendingOrder_) { sortByDateInDescendingOrder = _sortByDateInDescendingOrder_; })); it('should sort an array by date in descending order', function() { expect([{ date: 1 }, { date: 3 }, { date: 0 }].sort(sortByDateInDescendingOrder)).to.deep.equal([{ date: 3 }, { date: 1 }, { date: 0 }]); }); }); describe('The toAggregatorSource factory', function() { var toAggregatorSource, $rootScope; beforeEach(inject(function(_toAggregatorSource_, _$rootScope_) { toAggregatorSource = _toAggregatorSource_; $rootScope = _$rootScope_; })); it('should add a loadNextItems and loadRecentItems function to the provider', function() { var source = toAggregatorSource({ fetch: function() {} }); expect(source.loadNextItems).to.be.a('function'); expect(source.loadRecentItems).to.be.a('function'); }); it('should format results according to the aggregator expectations', function(done) { var provider = { templateUrl: 'templateUrl', fetch: function() { return function() { return $q.when([{ date: '2017-01-01T00:00:00Z' }]); }; } }; var source = toAggregatorSource(provider); source.loadNextItems().then(function(data) { expect(data).to.deep.equal({ data: [{ date: new Date(Date.UTC(2017, 0, 1, 0, 0, 0, 0)), templateUrl: 'templateUrl', provider: provider }], lastPage: true }); done(); }); $rootScope.$digest(); }); it('should request recent items based on the most recent item known', function(done) { var provider = { templateUrl: 'templateUrl', fetch: function() { var fetcher = function() { return $q.when([{ date: '2017-01-01T00:00:00Z' }, { date: '2016-01-01T00:00:00Z' }]); }; fetcher.loadRecentItems = function(item) { expect(item).to.deep.equal({ date: new Date(Date.UTC(2017, 0, 1, 0, 0, 0, 0)), templateUrl: 'templateUrl', provider: provider }); done(); }; return fetcher; } }; var source = toAggregatorSource(provider); source.loadNextItems(); $rootScope.$digest(); source.loadRecentItems(); $rootScope.$digest(); }); it('should update most recent item when fetching recent items', function(done) { var called = 0, provider = { templateUrl: 'templateUrl', fetch: function() { var expectedItem1 = { date: new Date(Date.UTC(2016, 0, 1, 0, 0, 0, 0)), templateUrl: 'templateUrl', provider: provider }, expectedItem2 = { date: new Date(Date.UTC(2017, 0, 1, 0, 0, 0, 0)), templateUrl: 'templateUrl', provider: provider }; var fetcher = function() { return $q.when([{ date: '2016-01-01T00:00:00Z' }]); }; fetcher.loadRecentItems = function(item) { expect(item).to.deep.equal(++called === 1 ? expectedItem1 : expectedItem2); if (called === 2) { return done(); } return $q.when([{ date: '2017-01-01T00:00:00Z' }]); }; return fetcher; } }, source = toAggregatorSource(provider); source.loadNextItems(); $rootScope.$digest(); source.loadRecentItems(); $rootScope.$digest(); source.loadRecentItems(); $rootScope.$digest(); }); }); });