linagora/openpaas-esn

View on GitHub
modules/linagora.esn.contact/frontend/app/controllers/contact-show.controller.spec.js

Summary

Maintainability
F
1 wk
Test Coverage
'use strict';

/* global sinon, chai: false */

var expect = chai.expect;

describe('The ContactShowController', function() {
  var $window, $controller, $state, $rootScope, $alert, $timeout, $stateParams, $location;
  var scope, contactUpdateDataService, ContactShellDisplayBuilder, gracePeriodService, ContactAPIClient, contactAddressbookDisplayService;
  var ContactShell, notificationFactory, selectionService, VcardBuilder, ContactLocationHelper;
  var CONTACT_AVATAR_SIZE, CONTACT_EVENTS;
  var bookId = '123456789', bookName = 'bookName', cardId = '987654321';

  beforeEach(function() {
    module('esn.core');
    module('linagora.esn.contact');

    ContactShellDisplayBuilder = {
      build: function(shell) {return shell;}
    };

    ContactShell = function() {};
    notificationFactory = {
      weakError: sinon.spy(),
      weakInfo: sinon.spy(),
      strongError: sinon.spy()
    };
    $location = {
      path: function() {},
      url: function() {},
      search: function() {
        return {
          q: {
            replace: function() {}
          }
        };
      }
    };
    $stateParams = {
      bookId: bookId,
      bookName: bookName
    };
    selectionService = {
      clear: function() {}
    };
    $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: [] };

    ContactAPIClient = {
      addressbookHome: function() {
        return {
          addressbook: function() {
            return {
              list: function() { return $q.when([]); },
              get: function() { return $q.when({ name: 'My Contacts' }); },
              vcard: function() {
                return {
                  get: function() { return $q.when(); },
                  list: function() { return $q.when({}); },
                  search: function() { return $q.when({ data: [] }); },
                  create: function() { return $q.when(); },
                  update: function() { return $q.when(); },
                  remove: function() { return $q.when(); }
                };
              }
            };
          }
        };
      }
    };

    VcardBuilder = {
      toVcard: function() {
        return 'vcard';
      }
    };

    ContactLocationHelper = {
      home: function() {},
      contact: {
        new: function() {},
        show: function() {},
        edit: function() {}
      }
    };

    module(function($provide) {
      $provide.value('notificationFactory', notificationFactory);
      $provide.value('$location', $location);
      $provide.value('selectionService', selectionService);
      $provide.value('$stateParams', $stateParams);
      $provide.value('$alert', function(options) { $alert.alert(options); });
      $provide.value('gracePeriodService', gracePeriodService);
      $provide.value('contactUpdateDataService', contactUpdateDataService);
      $provide.decorator('$window', function($delegate) {
        $delegate.addEventListener = angular.noop;

        return $delegate;
      });
      $provide.value('ContactShell', ContactShell);
      $provide.value('ContactAPIClient', ContactAPIClient);
      $provide.value('VcardBuilder', VcardBuilder);
      $provide.value('ContactLocationHelper', ContactLocationHelper);
      $provide.value('ContactShellDisplayBuilder', ContactShellDisplayBuilder);
    });
  });

  beforeEach(function() {
    inject(function(
      _$window_,
      _$controller_,
      _$rootScope_,
      _$timeout_,
      _$state_,
      _contactAddressbookDisplayService_,
      _CONTACT_AVATAR_SIZE_,
      _CONTACT_EVENTS_
    ) {
      $window = _$window_;
      $controller = _$controller_;
      $rootScope = _$rootScope_;
      $timeout = _$timeout_;
      $state = _$state_;
      contactAddressbookDisplayService = _contactAddressbookDisplayService_;
      CONTACT_AVATAR_SIZE = _CONTACT_AVATAR_SIZE_;
      CONTACT_EVENTS = _CONTACT_EVENTS_;
    });

    scope = $rootScope.$new();
    contactAddressbookDisplayService.convertShellToDisplayShell = angular.noop;

    createVcardMock(function() {
      return {
        get: function() { return $q.when({}); }
      };
    });
  });

  function createVcardMock(vcardFn, bookId, bookName) {
    ContactAPIClient.addressbookHome = function(id) {
      if (bookId) {
        expect(id).to.equal(bookId);
      }

      return {
        addressbook: function(name) {
          if (bookName) {
            expect(name).to.equal(bookName);
          }

          return {
            vcard: vcardFn,
            get: function() { return $q.when({ bookId: bookId, bookName: bookName, name: 'My Contacts' }); }
          };
        }
      };
    };
  }

  function initController() {
    $controller('ContactShowController', { $scope: scope });
    scope.$digest();
  }

  it('should change the state to the new contact destination after contact is moved', function(done) {
    $state.go = sinon.spy();

    initController();

    var contact = {
      id: scope.cardId,
      addressbook: {
        bookName: 'new-addressbook'
      }
    };

    $rootScope.$broadcast(CONTACT_EVENTS.UPDATED, contact);

    expect($state.go).to.have.been.calledWith('contact.addressbooks.show', {
      bookId: scope.bookId,
      bookName: 'new-addressbook',
      cardId: scope.cardId
    }, { location: 'replace' });

    done();
  });

  it('should go to the contact list state when the contact is deleted', function(done) {
    $state.go = sinon.spy();

    initController();

    var contact = {
      id: scope.cardId,
      addressbook: {
        bookName: 'new-addressbook'
      }
    };

    $rootScope.$broadcast(CONTACT_EVENTS.DELETED, contact);

    expect($state.go).to.have.been.calledWith('contact.addressbooks', {
      bookId: scope.bookId,
      bookName: 'new-addressbook'
    }, { location: 'replace' });

    done();
  });

  it('should have bigger size for contact avatar', function() {
    initController();
    expect(scope.avatarSize).to.equal(CONTACT_AVATAR_SIZE.bigger);
  });

  it('should display an error if the contact cannot be loaded initially', function(done) {
    createVcardMock(function() {
      return {
        get: function() { return $q.reject('WTF'); }
      };
    });
    $alert.alert = function() { done(); };

    initController();
  });

  describe('The fillContactData function', function() {
    it('should fill the scope with the contact', function() {
      contactUpdateDataService.contact = {};
      initController();
      var contact = { emails: [{ type: 'work', value: 'me@work.com' }, {type: 'home', value: 'me@home.com' }] };

      scope.fillContactData(contact);
      contactUpdateDataService.contact = contact;
      expect(scope.contact).to.deep.equal(contact);
    });

    it('should fill the scope with the contact emails', function() {
      contactUpdateDataService.contact = {};
      initController();
      var contact = { emails: [{ type: 'work', value: 'me@work.com' }, {type: 'home', value: 'me@home.com' }] };

      scope.fillContactData(contact);
      expect(scope.emails.length).to.equal(2);
    });

    it('should fill the scope with the contact phones', function() {
      contactUpdateDataService.contact = {};
      initController();
      var contact = { tel: [{ type: 'work', value: '+33333333' }, { type: 'home', value: '+33444444' }] };

      scope.fillContactData(contact);
      expect(scope.phones.length).to.equal(2);
    });

    it('should fill the scope with the contact formattedBirthday', function() {
      contactUpdateDataService.contact = {};
      initController();
      var contact = { birthday: '123', tel: [{ type: 'work', value: '+33333333' }, { type: 'home', value: '+33444444' }] };

      scope.fillContactData(contact);
      expect(scope.formattedBirthday).to.be.defined;
    });

    it('should build the display shell', function() {
      var display = {foo: 'bar'};

      ContactShellDisplayBuilder.build = function() {
        return display;
      };
      contactUpdateDataService.contact = {};
      initController();
      var contact = { birthday: '123', tel: [{ type: 'work', value: '+33333333' }, { type: 'home', value: '+33444444' }] };

      scope.fillContactData(contact);
      expect(scope.displayShell).to.deep.equal(display);
    });

  });

  describe('The $scope.getAddress function', function() {
    it('should filter only passed in address type', function() {
      contactUpdateDataService.contact = {
        addresses: [
          {
            city: '',
            country: 'France',
            street: '',
            type: 'work',
            zip: ''
          },
          {
            city: '',
            country: 'Vietnam',
            street: '',
            type: 'home',
            zip: ''
          }
        ]
      };

      initController();

      var address = {
        city: '',
        country: 'France',
        street: '',
        type: 'work',
        zip: ''
      };

      expect(scope.getAddress('work')).to.deep.equal(address);
    });

    it('should filter out undefined address type', function() {
      contactUpdateDataService.contact = {
        addresses: [
          {
            city: '',
            country: 'France',
            street: '',
            type: 'work',
            zip: ''
          },
          {
            city: '',
            country: 'Vietnam',
            street: '',
            zip: ''
          }
        ]
      };

      initController();

      var address = {
        city: '',
        country: 'France',
        street: '',
        type: 'work',
        zip: ''
      };

      expect(scope.getAddress('work')).to.deep.equal(address);
    });
  });

  describe('The $scope.shouldDisplayWork function', function() {

    it('should return false when nothing defined', function() {
      contactUpdateDataService.contact = {};
      initController();
      expect(scope.shouldDisplayWork()).to.be.false;
    });

    it('should return true when orgName is defined', function() {
      contactUpdateDataService.contact = { orgName: 'linagora' };
      initController();
      expect(scope.shouldDisplayWork()).to.be.true;
    });

    it('should return true when orgRole is defined', function() {
      contactUpdateDataService.contact = { orgRole: 'CTO' };
      initController();
      expect(scope.shouldDisplayWork()).to.be.true;
    });

    it('should return true when work address is filled', function() {
      contactUpdateDataService.contact = { addresses: [{ type: 'work', value: 'Paris' }] };
      initController();
      expect(scope.shouldDisplayWork()).to.be.true;
    });
  });

  describe('The $scope.shouldDisplayHome function', function() {

    it('should return false when nothing defined', function() {
      contactUpdateDataService.contact = {};
      initController();
      expect(scope.shouldDisplayHome()).to.be.false;
    });

    it('should return true when home address is filled', function() {
      contactUpdateDataService.contact = { addresses: [{ type: 'home', value: 'Montpellier' }] };
      initController();
      expect(scope.shouldDisplayHome()).to.be.true;
    });

    it('should return true when birthday is filled', function() {
      contactUpdateDataService.contact = { birthday: '15/12/1978' };
      initController();
      expect(scope.shouldDisplayHome()).to.be.true;
    });

    it('should return true when nickname is filled', function() {
      contactUpdateDataService.contact = { nickname: 'yolo' };
      initController();
      expect(scope.shouldDisplayHome()).to.be.true;
    });
  });

  describe('The $scope.shouldDisplayOthers function', function() {

    it('should return false when nothing defined', function() {
      contactUpdateDataService.contact = {};
      initController();
      expect(scope.shouldDisplayOthers()).to.be.false;
    });

    it('should return true when other address is defined', function() {
      contactUpdateDataService.contact = { addresses: [{ type: 'other', value: 'Toulouse' }] };
      initController();
      expect(scope.shouldDisplayOthers()).to.be.true;
    });

    it('should return false when other tags are defined but empty', function() {
      contactUpdateDataService.contact = { tags: [] };
      initController();
      expect(scope.shouldDisplayOthers()).to.be.false;
    });

    it('should return true when other tags are defined and not empty', function() {
      contactUpdateDataService.contact = { tags: ['js', 'node'] };
      initController();
      expect(scope.shouldDisplayOthers()).to.be.true;
    });

    it('should return true when notes are defined', function() {
      contactUpdateDataService.contact = { notes: 'This guy is so funky' };
      initController();
      expect(scope.shouldDisplayOthers()).to.be.true;
    });

    it('should return false when other urls are defined but empty', function() {
      contactUpdateDataService.contact = { urls: [] };
      initController();
      expect(scope.shouldDisplayOthers()).to.be.false;
    });

    it('should return true when other tags are defined and not empty', function() {
      contactUpdateDataService.contact = { urls: ['foo', 'bar'] };
      initController();
      expect(scope.shouldDisplayOthers()).to.be.true;
    });
  });

  describe('Tests show contact during graceperiod task', function() {

    it('should show the contact taken from contactUpdateDataService', function() {
      contactUpdateDataService.contact = { id: 'myId' };
      initController();
      expect(scope.contact).to.eql(contactUpdateDataService.contact);
    });

    it('should clear contactUpdateDataService.contact when switch to other path', function() {
      contactUpdateDataService.contact = { id: 'myId' };
      initController();

      scope.$emit('$stateChangeStart', {
        name: '/some/path/other/than/contact/edit'
      });

      scope.$digest();
      expect(contactUpdateDataService.contact).to.be.null;
    });

    it('should update contactUpdateDataService.contact when ther user edits contact again', function() {
      contactUpdateDataService.contact = { id: 'myId' };
      initController();

      scope.contact = { id: 'myOtherId' };
      scope.bookId = bookId;
      scope.bookName = bookName;
      scope.cardId = cardId;

      scope.$emit('$stateChangeStart', {
        name: 'contact.addressbooks.edit'
      },
      {
        bookId: bookId,
        bookName: bookName,
        cardId: cardId
      });

      scope.$digest();
      expect(contactUpdateDataService.contact).to.eql(scope.contact);
    });

    it('should flush the task when switch to other path', function(done) {
      contactUpdateDataService.contact = { id: 'myId' };
      contactUpdateDataService.taskId = 'a taskId';

      gracePeriodService.flush = function(taskId) {
        expect(taskId).to.equal('a taskId');
        done();
      };

      initController();

      scope.$emit('$stateChangeStart', {
        name: '/some/path/other/than/contact/edit'
      });

      scope.$digest();
    });

    it('should update contact on CONTACT_EVENTS.CANCEL_UPDATE event', function() {
      contactUpdateDataService.contact = { id: 'myId', firstName: 'Bob' };
      contactUpdateDataService.taskId = 'a taskId';

      initController();
      scope.cardId = 'myId';
      var newContact = { id: 'myId', firstName: 'Alice' };

      scope.$emit(CONTACT_EVENTS.CANCEL_UPDATE, newContact);

      scope.$digest();

      expect(scope.contact).to.eql(newContact);
    });

    it('should flush the task on beforeunload event', function(done) {
      contactUpdateDataService.contact = { id: 'myId' };
      contactUpdateDataService.taskId = 'a taskId';

      gracePeriodService.flush = sinon.spy();
      $window.addEventListener = function(evt, handler) {
        expect(evt).to.equal('beforeunload');
        handler();
        expect(gracePeriodService.flush.calledWithExactly('a taskId')).to.be.true;
        done();
      };

      initController();

    });

  });

  describe('The deleteContact function', function() {

    it('should call deleteContact service with the right bookId, bookName and cardId', function() {
      scope.bookName = 'bookName';
      scope.contact = { id: 1, firstName: 'Foo', lastName: 'Bar', addressbook: {} };
      var spy = sinon.spy();

      $controller.bind(null, 'ContactShowController', {
        $scope: scope,
        deleteContact: spy
      })();
      scope.deleteContact();
      $timeout.flush();
      expect(spy).to.have.been.calledWith(bookId, scope.bookName, scope.contact);
    });
  });
});