ThePavolC
ThePavolC

Reputation: 1738

How to test change on scope executed in directive controller

I have directive myItem. I want to change one property that is passed from parent to directive, so I use controller in myItem where I divide value by 60.

Everything works fine on the website.

Directive

define(['angular',
        'core',
        'ui-bootstrap', 
    ], 
    function(angular, coreModule, uiBootStrap) {
        'use strict';

        function myItemDirective(APPS_URL) {
            return {
                restrict: 'E',
                replace: 'true',
                scope: {
                    item: '='
                },
                templateUrl: APPS_URL.concat('item.tpl.html'),
                controller: ['$scope', function($scope) {
                    $scope.item.property = Math.round($scope.item.property / 60);
                }]
            };
        }

        return angular.module('apps.myItemModule', [coreModule.name])
                      .directive('myItem', ['APPS_URL', myItemDirective]); });

Now I would like to write a test where I can check that rendered value in directive is value passed from parent divided by 60.

Unit Test

define([
    'angular',
    'angularMocks',
    'apps/directives/mydirective' ], function (angular, mocks, myItemDirective) {

    var $httpBackend, $controller, $rootScope, $scope, directive,
        item = {
            property: 60
        };

    describe('my directive', function () {

        beforeEach(function() {
            mocks.module(myItemDirective.name);
            mocks.inject(function(_$rootScope_, $injector, $window) {
                $rootScope = _$rootScope_;
                $scope = $rootScope.$new();
                $compile = $injector.get('$compile');
                compileDirective();
            });
        });

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

        function compileDirective() {
            element = angular.element('<my-item item=' + JSON.stringify(item) + '></my-item>');
            directive = $compile(element)($scope);
            $scope.$digest();
            directiveScope = element.isolateScope();
        }

        it('test', function(){
            // console.log(element.find('#item-holder').innerText)
            // > 60
            expect(element.find('#item-holder').innerText).toEqual(Math.round(item.propert/60));
            // this will fail because item.property was not divided by 60
        });
    }); });

Problem

I am not able to render directive in unit test with value divided by 60. I can see in console that controller in directive has been called but the value is not changed.

Upvotes: 1

Views: 856

Answers (1)

ThePavolC
ThePavolC

Reputation: 1738

The problem was related to tests using the same reference to object item.

To fix this:

  • moved item to beforeEach
  • changed the way to create element
  • changed the way to get directive scope
  • use $scope.$apply()

So test looks like:

define([ 'angular', 'angularMocks', 'apps/directives/mydirective' ], function (angular, mocks, myItemDirective) {

var $httpBackend, $controller, $rootScope, $scope, directive,
    item;


describe('my directive', function () {

    beforeEach(function() {
        item = {
           property: 60
        };

        mocks.module(myItemDirective.name);
        mocks.inject(function(_$rootScope_, $injector, $window) {
            $rootScope = _$rootScope_;
            $scope = $rootScope.$new();
            $compile = $injector.get('$compile');
            compileDirective();
        });
    });

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

    function compileDirective() {
        $scope.item = item;
        element = angular.element('<my-item item="item"></my-item>');
        directive = $compile(element)($scope);
        $scope.$apply();
        directiveScope = directive.isolateScope();
    }

    it('test', function(){
        // console.log(element.find('#item-holder').innerText)
        // > 60
        expect(element.find('#item-holder').innerText).toEqual(Math.round(item.propert/60));
        // this will fail because item.property was not divided by 60
    });
}); });

Upvotes: 2

Related Questions