最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

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

matteradmin7PV0评论

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);
    });    
});
Post a comment

comment list (0)

  1. No comments so far