最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to change constant value in a Karma test - Stack Overflow

programmeradmin1浏览0评论

I have an Angular directive which sets the value of some $scope property based on the value of an injected constant. I want to test that this value is being correctly initialized from the constant, so I would like to change the constant's value within an individual it block. (Preferably within one, but changing the value between multiple blocks would be OK too)

Is this possible, and how can I do it?

simplified example:

//////// directive ////////
angular.module('myApp.directives', [])
.constant('THE_CONSTANT', 'hello world')
.directive('myDirective', ['THE_CONSTANT', function (THE_CONSTANT) {

    return {
        restrict: 'E',
        link: function ($scope) {
            $scope.propertyBasedOnConstant = THE_CONSTANT;
        }
    };
}]);

//////// test ////////
describe('myDirective', function () {
    var $element, $scope;

    beforeEach(module('myApp.directives'));

    beforeEach(module(function ($provide) {
        $provide.constant('THE_CONSTANT', 'foo');
    }));

    beforeEach(inject(function ($rootScope, $pile) {
        $scope = $rootScope;
        $element = angular.element('<my-directive></my-directive>');
        $pile($element)($scope);
        $scope.$digest();
    }));

    afterEach(function () {
        $scope.$destroy();
        $element.remove();
    });

    it("should correctly reflect the constant's value", function() {
        expect( $scope.propertyBasedOnConstant ).to.equal('foo');

        // now I want to change the constant's value and re-initialize the directive
    });    
});

I have an Angular directive which sets the value of some $scope property based on the value of an injected constant. I want to test that this value is being correctly initialized from the constant, so I would like to change the constant's value within an individual it block. (Preferably within one, but changing the value between multiple blocks would be OK too)

Is this possible, and how can I do it?

simplified example:

//////// directive ////////
angular.module('myApp.directives', [])
.constant('THE_CONSTANT', 'hello world')
.directive('myDirective', ['THE_CONSTANT', function (THE_CONSTANT) {

    return {
        restrict: 'E',
        link: function ($scope) {
            $scope.propertyBasedOnConstant = THE_CONSTANT;
        }
    };
}]);

//////// test ////////
describe('myDirective', function () {
    var $element, $scope;

    beforeEach(module('myApp.directives'));

    beforeEach(module(function ($provide) {
        $provide.constant('THE_CONSTANT', 'foo');
    }));

    beforeEach(inject(function ($rootScope, $pile) {
        $scope = $rootScope;
        $element = angular.element('<my-directive></my-directive>');
        $pile($element)($scope);
        $scope.$digest();
    }));

    afterEach(function () {
        $scope.$destroy();
        $element.remove();
    });

    it("should correctly reflect the constant's value", function() {
        expect( $scope.propertyBasedOnConstant ).to.equal('foo');

        // now I want to change the constant's value and re-initialize the directive
    });    
});
Share Improve this question asked Jul 7, 2015 at 20:58 tufftuff 5,1736 gold badges30 silver badges43 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

You are providing the constant into an undefined module.

Change your beforeEach block to something like this and it should just work™:

var $scope, $element, MOCKED_CONSTANT;

beforeEach(function () {
  MOCKED_CONSTANT = 'foo';

  module('myApp.directives', function ($provide) {
    $provide.constant('THE_CONSTANT', MOCKED_CONSTANT);
  });

  inject(function ($rootScope, $pile) {
    $scope       = $rootScope.$new(); // Don't forget to call .$new()!
    var template = angular.element('<my-directive></my-directive');
    $element     = $pile(template)($scope); // Store the reference to the piled element, not the raw string.
    $scope.$digest();
  });
});

it("should correctly reflect the constant's value", function() {
  expect( $scope.propertyBasedOnConstant ).to.equal(MOCKED_CONSTANT);
  // expect( $scope.propertyBasedOnConstant ).to.equal('foo');
});

If you need to change the constant's value between it's, I would extract the call to module into a helper function, aswell as the inject. Such as:

function setupModule (constant) {
  module('myApp.directives', function ($provide) {
    $provide.constant('THE_CONSTANT', constant);
  });
}

function injectItAll () {
  inject(function ($rootScope, $pile) {
    $scope       = $rootScope.$new(); // Don't forget to call .$new()!
    var template = angular.element('<my-directive></my-directive');
    $element     = $pile(template)($scope); // Store the reference to the piled element, not the raw string.
    $scope.$digest();
  });
}

And then in your spec you would do:

it('equals banana', function () {
  setupModule('banana');
  injectItAll();
  expect($scope.propertyBasedOnConstant).to.equal('banana');
});

By definition a constant is an identifier with an associated value which cannot be changed. Instead of changing the constant value why not inject the constant itself and use it within your expectations.

describe('myDirective', function () {
    var $element, $scope,
      THE_CONSTANT;

    beforeEach(module('myApp.directives'));

    beforeEach(module(function (_THE_CONSTANT_) {
      THE_CONSTANT = _THE_CONSTANT_;
    }));

    beforeEach(inject(function ($rootScope, $pile) {
        $scope = $rootScope;
        $element = angular.element('<my-directive></my-directive>');
        $pile($element)($scope);
        $scope.$digest();
    }));

    afterEach(function () {
        $scope.$destroy();
        $element.remove();
    });

    it("should correctly reflect the constant's value", function() {
        expect( $scope.propertyBasedOnConstant ).to.equal(THE_CONSTANT);
    });    
});
发布评论

评论列表(0)

  1. 暂无评论