0

I'm writing a unit test for an AngularJS directive, that makes a few functions calls on the scope, and within these functions, it creates new objects on the scope.

So I've created my test like this:

fdescribe('Activity Directive Tests - ', function() {
  beforeEach(module('starter.services'));

  window.RESOURCE_ROOT = 'foo/';

  var $scope, $compile, element, $httpBackend;
  beforeEach(inject(function($rootScope, _$compile_, $injector) {
    $scope = $rootScope.$new();
    $compile = _$compile_;

    $httpBackend = $injector.get('$httpBackend');
    $httpBackend.expectGET('foo/shared/activity/activity-modal.html').respond('200','');

    element = $compile('<activity-button></activity-button>')($scope);



    $scope.$digest();
  }));


  describe('Tests of objects created when page opened - ', function() {
    it('should create a empty task obj', function() {
      element.scope().openActivity(); // call function of directive
      expect(element.scope().task).toBeDefined();
    })
  })

})

But I keep on getting scope is undefined. All our directives use just the link function and not a controller, so I think accessing the scope is not so easy. I've tried accessing the isolate scope, but that is also undefined.

This is how the directive is setup:

(function() {
  'use strict';

  angular
    .module('starter.services')

    .directive('activityButton', function(
      $window,
      SobjectService,
      $stateParams,
      $ionicModal,
      $ionicLoading,
      $location,
      LOG_TIME_CONSTANTS,
      $filter
    ) {
      return {
        restrict: 'E',
        scope: {},
        link: function(scope) {
          scope.activityModel = {};
          scope.activityModel.ActivityType__c;

          scope.activityTaskModel = {};
          scope.activityTaskModel.TaskType__c;

          scope.activityEventModel = {};
          scope.activityEventModel.EventType__c;
          scope.ActivityType = 'Task';

          scope.isValid = {};

          $ionicModal
            .fromTemplateUrl(
              $window.RESOURCE_ROOT + 'shared/activity/activity-modal.html',
              {
                scope: scope,
                animation: 'slide-in-up'
              }
            )
            .then(function(modal) {
              scope.modal = modal;
            });

          scope.openActivity = function ()  {
            scope.activity = {};
            scope.task = {};

            if ($stateParams.Id) {
              var objectName = $location.path().split('/')[1];
              console.log(objectName);
              if (
                objectName == LOG_TIME_CONSTANTS.PAGE_LEAD ||
                objectName == LOG_TIME_CONSTANTS.PAGE_CONTACT
              ) {
                getLeadDetails($stateParams.Id);
              } else {
                //for Opportunity,Account
                getRecordDetails($stateParams.Id);
              }
            }

            scope.modal.show();
          };


          scope.saveTask = function() {
            var taskToSave = buildTaskRecord();
            isTaskValid(taskToSave);

            if (scope.isValid.valid) {
              SobjectService.insert('Task__ap', taskToSave)
                .then(function(res) {
                  showToast('Task successfully saved.');
                  scope.close(scope.modal);
                })
                .catch(function(e) {
                  console.error(e);
                  showToast('Could not save Task.');
                });
            } else {
              showToast(
                'Could not save the Task, some fields are still not complete'
              );
            }
          };


        templateUrl:
          $window.RESOURCE_ROOT + 'shared/activity/activitybutton.html'
      };
    });
})();
StephenAdams
  • 521
  • 2
  • 9
  • 26
  • Is there any particular reason you are not using a controller? The link function should really only be used when you actually need the element the directive is on... – Yftach Apr 08 '18 at 09:21
  • Unfortunately, the directives have already been built before the tests were added. So they all use the Link function instead of a controller. – StephenAdams Apr 08 '18 at 16:34
  • An example project would be helpful, because right now there is no way I could guess what went wrong. Also, just for the record, I think you are going the wrong way about this. When testing you should be testing your logic and not rely on outside logic. What are you trying to test here? That angular is giving you a scope? That's a pretty weird test and you are essentially just testing angular's code for creating child scopes... – Yftach Apr 08 '18 at 16:50
  • What you should be testing, is the saveTask and maybe the inner logic of getLeadDetails and getRecordDetails. And do it by extracting the actual logic of saving to a service or something, and test that service. – Yftach Apr 08 '18 at 16:52
  • I totally agree, but this is for a project that I'm late to and all this code has been written like this. I think unless we change how our directives are written they can't be 100% covered by tests. – StephenAdams Apr 08 '18 at 16:55
  • Is this for school or something like that? Or is it for production code? 100% code coverage is honestly a big waste of time. And doesn't reflect good code coverage. Take a look at this question: https://stackoverflow.com/questions/1475520/unit-testing-code-coverage-do-you-have-100-coverage – Yftach Apr 08 '18 at 17:00

0 Answers0