UNPKG

linagora-rse

Version:
679 lines (614 loc) 22.8 kB
'use strict'; /* global chai: false */ var expect = chai.expect; describe('The esn.activitystream Angular module', function() { describe('activitystreamAggregator service', function() { beforeEach(function() { var filteredcursorInstance = { nextItems: function() {}, endOfStream: false }; this.asAPI = { get: function() {} }; this.asDecorator = function(callback) { return callback; }; this.restcursor = function() { return { nextItems: function() {}, endOfStream: false }; }; this.filteredcursorInstance = filteredcursorInstance; this.filteredcursor = function() { return filteredcursorInstance; }; this.asfilter = function() { return { filter: function() {return true;} }; }; var self = this; angular.mock.module('esn.activitystream'); angular.mock.module(function($provide) { $provide.value('activitystreamAPI', self.asAPI); $provide.value('activitystreamMessageDecorator', self.asDecorator); $provide.value('restcursor', self.restcursor); $provide.value('filteredcursor', self.filteredcursor); $provide.value('activitystreamFilter', self.asfilter); }); }); beforeEach(inject(function(activitystreamAggregator, $rootScope) { this.agg = activitystreamAggregator; this.$rootScope = $rootScope; })); it('should be a function', function() { expect(this.agg).to.be.a('function'); }); it('should return an object having a endOfStream property', function() { var instance = this.agg({activity_stream: {uuid: 'ID1'}}, {activity_stream: {uuid: 'ID2'}}, [], 30); expect(instance).to.have.property('endOfStream'); }); it('should return an object having a loadMoreElements method', function() { var instance = this.agg({activity_stream: {uuid: 'ID1'}}, {activity_stream: {uuid: 'ID2'}}, [], 30); expect(instance).to.respondTo('loadMoreElements'); }); describe('endOfStream property', function() { it('should return the endofstream property of the associated filteredcursor', function() { var instance = this.agg({activity_stream: {uuid: 'ID1'}}, {activity_stream: {uuid: 'ID2'}}, [], 30); expect(instance.endOfStream).to.be.false; this.filteredcursorInstance.endOfStream = true; expect(instance.endOfStream).to.be.true; }); }); describe('loadMoreElements method', function() { it('should call the nextItems method of the associated filteredcursor', function(done) { var instance = this.agg({activity_stream: {uuid: 'ID1'}}, {activity_stream: {uuid: 'ID2'}}, [], 30); this.filteredcursorInstance.nextItems = function() {done();}; instance.loadMoreElements(); }); }); }); describe('activitystreamMessageDecorator service', function() { beforeEach(function() { this.msgAPI = { get: function() {} }; var self = this; angular.mock.module('esn.activitystream'); angular.mock.module(function($provide) { $provide.value('messageAPI', self.msgAPI); }); }); beforeEach(inject(function(activitystreamMessageDecorator, $rootScope) { this.decorator = activitystreamMessageDecorator; this.$rootScope = $rootScope; })); it('should be a function', function() { expect(this.decorator).to.be.a('function'); }); it('should return a function', function() { var instance = this.decorator(function() {}); expect(instance).to.be.a('function'); }); it('should forward any error', function(done) { var instance = this.decorator(function(err) { expect(err).to.equal('ERROR'); done(); }); instance('ERROR'); }); it('should call messageAPI.get with according ids', function(done) { var tl = [ {object: { _id: 'ID5' }}, {object: { _id: 'ID2' }} ]; this.msgAPI.get = function(options) { expect(options).to.deep.equal({'ids[]': ['ID5', 'ID2']}); done(); }; var instance = this.decorator(function() { }); instance(null, tl); }); it('should call messageAPI.get with parent message ids when there is a inReplyTo field', function(done) { var tl = [ {object: { _id: 'ID5' }}, {object: { _id: 'ID2' }, inReplyTo: [{_id: 'ID3'}]} ]; this.msgAPI.get = function(options) { expect(options).to.deep.equal({'ids[]': ['ID5', 'ID3']}); done(); }; var instance = this.decorator(function() { }); instance(null, tl); }); it('should not call messageAPI.get if the array of ids is empty', function() { var msgAPIcalled = false; this.msgAPI.get = function() { msgAPIcalled = true; }; var instance = this.decorator(function() { }); instance(null, []); expect(msgAPIcalled).to.be.false; }); it('should forward messageAPI.get error', function(done) { var tl = [ {object: { _id: 'ID5' }}, {object: { _id: 'ID2' }} ]; this.msgAPI.get = function() { return $q.reject({ data: 'ERROR' }); }; var instance = this.decorator(function(err) { expect(err).to.equal('ERROR'); done(); }); instance(null, tl); this.$rootScope.$digest(); }); it('should return an error if some messages cannot be fetched', function(done) { var tl = [ {object: { _id: 'ID5' }}, {object: { _id: 'ID2' }} ]; var msgResp = [ {_id: 'ID5', objectType: 'whatsup' }, {error: 404, message: 'Not found', details: 'message ID2 could not be found'} ]; this.msgAPI.get = function() { return $q.when({ data: msgResp }); }; var instance = this.decorator(function(err) { expect(err.code).to.equal(400); expect(err.message).to.equal('message download failed'); expect(err.details).to.be.an.array; expect(err.details).to.have.length(1); done(); }); instance(null, tl); this.$rootScope.$digest(); }); it('should return the decorated timeline object', function(done) { var tl = [ {object: { _id: 'ID5' }}, {object: { _id: 'ID2' }} ]; var msgResp = [ {_id: 'ID5', objectType: 'whatsup', content: 'yolo' }, {_id: 'ID2', objectType: 'whatsup', content: 'lgtm' } ]; this.msgAPI.get = function() { return $q.when({ data: msgResp }); }; var instance = this.decorator(function(err, response) { expect(response).to.deep.equal([ {object: {_id: 'ID5', objectType: 'whatsup', content: 'yolo' }}, {object: {_id: 'ID2', objectType: 'whatsup', content: 'lgtm' }} ]); done(); }); instance(null, tl); this.$rootScope.$digest(); }); }); describe('activitystreamAPI service', function() { beforeEach(function() { angular.mock.module('esn.activitystream'); }); beforeEach(inject(function(activitystreamAPI, $httpBackend) { this.api = activitystreamAPI; this.$httpBackend = $httpBackend; })); describe('get method', function() { it('should exist', function() { expect(this.api).to.respondTo('get'); }); it('should send a request GET /api/activitystreams/:uuid', function() { this.$httpBackend.expectGET('/api/activitystreams/test').respond([]); this.api.get('test'); this.$httpBackend.flush(); }); it('should send a request GET /api/activitystreams/:uuid, allowing passing some options', function() { this.$httpBackend.expectGET('/api/activitystreams/test?before=someID&limit=30').respond([]); this.api.get('test', {before: 'someID', limit: 30}); this.$httpBackend.flush(); }); }); }); describe('activitystreamFilter service', function() { beforeEach(function() { angular.mock.module('esn.activitystream'); }); beforeEach(inject(function(activitystreamFilter) { this.filter = activitystreamFilter; })); it('should be a function', function() { expect(this.filter).to.be.a('function'); }); it('should return an object with filter, addToSentList and addToRemovedList methods', function() { var f = this.filter(); expect(f).to.respondTo('filter'); expect(f).to.respondTo('addToSentList'); expect(f).to.respondTo('addToRemovedList'); }); describe('filter method', function() { it('should respond true for a new timeline entry', function() { var f = this.filter(); var tle = { verb: 'post', object: { _id: 'ID1' } }; expect(f.filter(tle)).to.be.true; }); it('should respond false for a new timeline entry having the verb remove', function() { var f = this.filter(); var tle = { verb: 'remove', object: { _id: 'ID1' } }; expect(f.filter(tle)).to.be.false; }); it('should respond false for a new timeline entry it already knows', function() { var f = this.filter(); var tle = { verb: 'post', object: { _id: 'ID1' } }; f.filter(tle); expect(f.filter(tle)).to.be.false; }); it('should respond false for a new timeline entry it already knows and that was "remove"d', function() { var f = this.filter(); var tle = { verb: 'post', object: { _id: 'ID1' } }; var tle2 = { verb: 'remove', object: { _id: 'ID1' } }; f.filter(tle2); expect(f.filter(tle)).to.be.false; }); describe('comments support', function() { it('should respond true for a new comment', function() { var f = this.filter(); var cmt = { verb: 'post', object: { _id: 'comment1' }, inReplyTo: [{_id: 'message1'}] }; expect(f.filter(cmt)).to.be.true; }); it('should respond false for a new comment when a comment has already been posted for the same parent message', function() { var f = this.filter(); var cmt = { verb: 'post', object: { _id: 'comment1' }, inReplyTo: [{_id: 'message1'}] }; var cmt2 = { verb: 'post', object: { _id: 'comment2' }, inReplyTo: [{_id: 'message1'}] }; f.filter(cmt); expect(f.filter(cmt2)).to.be.false; }); it('should respond false for a new comment when the parent message has already been posted', function() { var f = this.filter(); var cmt = { verb: 'post', object: { _id: 'comment1' }, inReplyTo: [{_id: 'message1'}] }; var parent = { verb: 'post', object: { _id: 'message1' } }; f.filter(parent); expect(f.filter(cmt)).to.be.false; }); it('should respond false for a new comment when the parent message has been removed', function() { var f = this.filter(); var cmt = { verb: 'post', object: { _id: 'comment1' }, inReplyTo: [{_id: 'message1'}] }; var parent = { verb: 'remove', object: { _id: 'message1' } }; f.filter(parent); expect(f.filter(cmt)).to.be.false; }); }); }); }); describe('activityStreamUpdates service', function() { beforeEach(function() { angular.mock.module('esn.activitystream'); this.restcursor = function() { return { nextItems: function() {}, endOfStream: false }; }; this.asAPI = { get: function() {} }; this.messageAPI = { get: function() {} }; }); it('must be a function', function() { var self = this; angular.mock.module(function($provide) { $provide.value('activitystreamAPI', self.asAPI); $provide.value('messageAPI', self.messageAPI); $provide.value('restcursor', self.restcursor); }); inject(function(activityStreamUpdates) { expect(activityStreamUpdates).to.be.a('function'); }); }); it('must create a restcursor', function(done) { var self = this; this.restcursor = function() { expect(arguments).to.have.length(3); expect(arguments[0]).to.be.a('function'); expect(arguments[1]).to.be.an.object; done(); return { nextItems: function() {}, endOfStream: false }; }; angular.mock.module(function($provide) { $provide.value('activitystreamAPI', self.asAPI); $provide.value('messageAPI', self.messageAPI); $provide.value('restcursor', self.restcursor); }); inject(function(activityStreamUpdates) { activityStreamUpdates('0987654321', {mostRecentActivityId: 'message1'}); }); }); it('must call cursor.nextItems', function(done) { var self = this; this.restcursor = function() { return { nextItems: function() {done();}, endOfStream: false }; }; angular.mock.module(function($provide) { $provide.value('activitystreamAPI', self.asAPI); $provide.value('messageAPI', self.messageAPI); $provide.value('restcursor', self.restcursor); }); inject(function(activityStreamUpdates) { activityStreamUpdates('0987654321', {mostRecentActivityId: 'message1'}); }); }); describe('provided API', function() { it('must use the activitystreamAPI with provided activity stream ID', function(done) { var self = this; this.restcursor = function(api) { api(); return { nextItems: function() {}, endOfStream: false }; }; this.asAPI = { get: function() { expect(arguments[0]).to.equal('0987654321'); done(); }}; angular.mock.module(function($provide) { $provide.value('activitystreamAPI', self.asAPI); $provide.value('messageAPI', self.messageAPI); $provide.value('restcursor', self.restcursor); }); inject(function(activityStreamUpdates) { activityStreamUpdates('0987654321', {mostRecentActivityId: 'message1'}); }); }); }); describe('on REST call error', function() { it('should forward the error', function(done) { var self = this; this.restcursor = function() { return { nextItems: function(callback) {return callback(new Error('down'));}, endOfStream: false }; }; angular.mock.module(function($provide) { $provide.value('activitystreamAPI', self.asAPI); $provide.value('messageAPI', self.messageAPI); $provide.value('restcursor', self.restcursor); }); inject(function(activityStreamUpdates, $rootScope) { activityStreamUpdates('0987654321', {mostRecentActivityId: 'message1'}).then( function() {done(new Error('I should not be called'));}, function() {done();} ); $rootScope.$digest(); }); }); }); describe('on REST call success', function() { it('should update the scope with the provided timeline entries', function(done) { var self = this; var entries = [ {_id: 'tl1', object: {_id: 'msg1'}}, {_id: 'tl2', object: {_id: 'msg2'}}, {_id: 'tl3', object: {_id: 'msg3'}}, {_id: 'tl4', object: {_id: 'msg4'}}, {_id: 'tl5', object: {_id: 'msg5'}} ]; this.restcursor = function() { return { nextItems: function(callback) { this.endOfStream = true; return callback(null, entries); }, endOfStream: false }; }; this.activitystreamOriginDecorator = function(stream, streams, callback) { return callback; }; var scope = { mostRecentActivityId: 'message1', threads: [] }; angular.mock.module(function($provide) { $provide.value('activitystreamAPI', self.asAPI); $provide.value('restcursor', self.restcursor); $provide.value('activitystreamOriginDecorator', self.activitystreamOriginDecorator); }); inject(function(activityStreamUpdates, $rootScope) { activityStreamUpdates('0987654321', scope).then( function() { expect(scope.threads).to.have.length(5); expect(scope.threads[0]._id).to.equal('msg5'); expect(scope.threads[1]._id).to.equal('msg4'); expect(scope.threads[2]._id).to.equal('msg3'); expect(scope.threads[3]._id).to.equal('msg2'); expect(scope.threads[4]._id).to.equal('msg1'); done(); }, function() {done(new Error('I should not be called'));} ).catch(function(err) { throw err; }); $rootScope.$digest(); }); }); it('should update the scope, taking care of the elements ordering', function(done) { var self = this; var entries = [ {_id: 'tl1', object: {_id: 'msg1'}}, {_id: 'tl2', object: {_id: 'msg2'}}, {_id: 'tl3', object: {_id: 'msg3'}}, {_id: 'tl4', object: {_id: 'msg2'}}, {_id: 'tl5', object: {_id: 'msg5'}} ]; this.restcursor = function() { return { nextItems: function(callback) { this.endOfStream = true; return callback(null, entries); }, endOfStream: false }; }; this.activitystreamOriginDecorator = function(stream, streams, callback) { return callback; }; var scope = {mostRecentActivityId: 'message1', threads: [] }; angular.mock.module(function($provide) { $provide.value('activitystreamAPI', self.asAPI); $provide.value('restcursor', self.restcursor); $provide.value('activitystreamOriginDecorator', self.activitystreamOriginDecorator); }); inject(function(activityStreamUpdates, $rootScope) { activityStreamUpdates('0987654321', scope).then( function() { expect(scope.threads).to.have.length(4); expect(scope.threads[0]._id).to.equal('msg5'); expect(scope.threads[1]._id).to.equal('msg2'); expect(scope.threads[2]._id).to.equal('msg3'); expect(scope.threads[3]._id).to.equal('msg1'); done(); }, function() {done(new Error('I should not be called'));} ).catch(function(err) { throw err; }); $rootScope.$digest(); }); }); it('should update the scope, recursively fetching timeline entries per batches of 30', function(done) { var self = this; var entries1 = [ {_id: 'tl1', object: {_id: 'msg1'}}, {_id: 'tl2', object: {_id: 'msg2'}}, {_id: 'tl3', object: {_id: 'msg2'}}, {_id: 'tl4', object: {_id: 'msg2'}}, {_id: 'tl5', object: {_id: 'msg2'}}, {_id: 'tl6', object: {_id: 'msg2'}}, {_id: 'tl7', object: {_id: 'msg2'}}, {_id: 'tl8', object: {_id: 'msg2'}}, {_id: 'tl9', object: {_id: 'msg2'}}, {_id: 'tl10', object: {_id: 'msg18'}}, {_id: 'tl11', object: {_id: 'msg2'}}, {_id: 'tl12', object: {_id: 'msg2'}}, {_id: 'tl13', object: {_id: 'msg14'}}, {_id: 'tl14', object: {_id: 'msg2'}}, {_id: 'tl15', object: {_id: 'msg2'}}, {_id: 'tl16', object: {_id: 'msg2'}}, {_id: 'tl17', object: {_id: 'msg1'}}, {_id: 'tl18', object: {_id: 'msg2'}}, {_id: 'tl19', object: {_id: 'msg2'}}, {_id: 'tl20', object: {_id: 'msg2'}}, {_id: 'tl21', object: {_id: 'msg2'}}, {_id: 'tl22', object: {_id: 'msg2'}}, {_id: 'tl23', object: {_id: 'msg2'}}, {_id: 'tl24', object: {_id: 'msg2'}}, {_id: 'tl25', object: {_id: 'msg3'}}, {_id: 'tl26', object: {_id: 'msg2'}}, {_id: 'tl27', object: {_id: 'msg2'}}, {_id: 'tl28', object: {_id: 'msg2'}}, {_id: 'tl29', object: {_id: 'msg2'}}, {_id: 'tl30', object: {_id: 'msg4'}} ]; var entries2 = [ {_id: 'tl31', object: {_id: 'msg14'}}, {_id: 'tl32', object: {_id: 'msg2'}}, {_id: 'tl33', object: {_id: 'msg2'}}, {_id: 'tl34', object: {_id: 'msg18'}} ]; var entries = [entries1, entries2]; this.restcursor = function() { return { nextItems: function(callback) { if (entries.length === 1) { this.endOfStream = true; } return callback(null, entries.shift()); }, endOfStream: false }; }; this.activitystreamOriginDecorator = function(stream, streams, callback) { return callback; }; var scope = {mostRecentActivityId: 'message1', threads: [] }; angular.mock.module(function($provide) { $provide.value('activitystreamAPI', self.asAPI); $provide.value('restcursor', self.restcursor); $provide.value('activitystreamOriginDecorator', self.activitystreamOriginDecorator); }); inject(function(activityStreamUpdates, $rootScope) { activityStreamUpdates('0987654321', scope).then( function() { expect(scope.threads).to.have.length(6); expect(scope.threads[0]._id).to.equal('msg18'); expect(scope.threads[1]._id).to.equal('msg2'); expect(scope.threads[2]._id).to.equal('msg14'); expect(scope.threads[3]._id).to.equal('msg4'); expect(scope.threads[4]._id).to.equal('msg3'); expect(scope.threads[5]._id).to.equal('msg1'); done(); }, function() {done(new Error('I should not be called'));} ).catch(function(err) { throw err; }); $rootScope.$digest(); }); }); }); }); });