使用ControllerAs和Ng-Show测试数据指令

时间:2017-08-22 14:16:15

标签: javascript angularjs testing karma-jasmine

我正在尝试在我的angular指令中测试ng-show条件,该指令使用controllerAs语法并为模板加载外部html文件。

我无法弄清楚如何在条件满足时测试模板中是否出现了什么。

我的问题是 - 如何在满足条件时测试ng-show是否有效相关数据通过ctrl.error标签显示在<p>中?

以下是相关文件: 模板文件:

<!-- dataDisplay.html -->
<div>
    <div ng-show="!ctrl.eventsFound">
        <p id="errorMessage" style="color: red;">{{ctrl.error}}</p>
    </div>

    <div id="result" ng-show="ctrl.eventsFound">
        <section id="item-block" class="item-container">
            <div class="item-timeline-block" ng-repeat="item in ctrl.items track by item.index">
                <div ng-class="item.iconBackground">
                    <span style="color:white" ng-class="item.iconImg"></span>
                </div>
                <div class="item-timeline-content">
                    <h2>{{::item.title}}</h2>
                    <span ng-show="{{::item.datetime}}" class="date">
                </span>
                    <p>{{::item.content}}</p>
                    <a ng-hide="{{!item.link}}" href="{{::item.link}}" target="_blank">Read more</a>
                    <small ng-hide="{{!item.link}}">{{::item.linkWarning}}</small>
                </div>
            </div>
        </section>
    </div>
</div>

的index.html:

<!doctype html>
<html ng-app="app" ng-cloak>
<head>
    <title> Test </title>
    <script src="node_modules/angular/angular.min.js"></script>
    <script src="node_modules/angular-sanitize/angular-sanitize.min.js"></script>
</head>
<body>
<div>
    <display-dir></display-dir>
</div>
</body>
<script src="node_modules/moment/min/moment.min.js"></script>
<script src="./path/displayDir.js"></script>
</html>

指令:

//displayDir.js

angular.module('app', [])

    .directive('displayDir', function() {
        return {
            restrict: 'E',
            transclude: true,
            controllerAs: 'ctrl',
            scope: {},
            templateUrl: 'dataDisplay.html',
            link: function() {

            },

            controller: 'displayCtrl'
        }

    })

    .controller('displayCtrl', ['$window', function($window) {

        let ctrl = this;

        ctrl.items =
            [
                { event: "a", title: "title a", index: 0, datetime: "01/02/2016", content: "content 1" },
                { event: "b", title: "title b", index: 2,   datetime: "01/01/2016", content: "content 2", link: 'http://www.google.com'},
            ];

        try {

            if (!ctrl.items.length) {
                ctrl.eventsFound = false;
                ctrl.error = "there is no data present for the control";
            } else {

                ctrl.eventsFound = true;
                ctrl.items.map(function(item) {
                    if (item.title == "title b") {
                        item.link = item.content;
                        item.linkWarning = `Warning - This link will bring you to external content!`
                        item.content = ""
                    }

                    if (item.datetime == "") {
                        item.lastUpdated = ""
                    } else {
                        item.lastUpdated = $window.moment(item.datetime).fromNow()
                    }
                    return item;
                });
            }

        } catch (error) {
            ctrl.eventsFound = false;
            ctrl.error = error.message
        }

    }])

Karma测试规范 - 使用ngHtml2JsPreprocessor

describe('the displayDir directive', function() {

    let element, scope, ctrl;

    beforeEach(angular.mock.module('app'));
    beforeEach(module('htmlTemplate'));

    beforeEach(inject(function($rootScope, $controller) {
        //define the controller
        scope = $rootScope;
        ctrl = $controller('displayCtrl', {
            $scope: scope
        })
    }));

    describe('after loading template url', function() {

        beforeEach(inject(function($compile) {
            // bring in the templateUrl file
            element = angular.element('<display-dir></display-dir>');
            $compile(element)(scope);
            scope.$digest();
        }));

        it('should show the errorMessage div', function() {
            let messageDiv = element[0].querySelector("#errorMessage");
            expect(messageDiv).toBeDefined();
        });

        it('should show the errorMessage div with the text', function(){
            ctrl.events =[]
            ctrl.eventsFound = false;
            ctrl.errorMessage = 'There is no data present for the control'
            let messageDiv = element[0].querySelector("#errorMessage");
            //This does not show the text error message text inside the 'p' tag
            console.log("element",messageDiv)

          /* something like 
          expect(messageDiv.innerHTML()).toEqual('There is no data 
          present for the control');

          or 

          expect(ctrl.errorMessage).toEqual('There is no data present 
          for the control') 
          */
        })

    })

});

修改

在与Nikolaj合作之后,我有以下测试:

// FAILS ON the second expect - messageDiv.text should equal...
it('should show the errorMessage div', function() {
    ctrl.events =[];
    ctrl.eventsFound= false;
    ctrl.errorMessage = 'There is no data'
    let messageDiv = angular.element(element[0].querySelector("#errorMessage"));
    expect(messageDiv.hasClass('ng-hide')).toBeFalsy();
    expect(messageDiv.text()).toEqual("There is no data")
});

// FAILS ON the first expect - messageDiv should be truthy
it('should not show the errorMessage div', function() {
    ctrl.events = [{event: "test"}]
    ctrl.eventsFound= true;
    ctrl.errorMessage = ''
    let messageDiv = angular.element(element[0].querySelector("#errorMessage"));
    expect(messageDiv.hasClass('ng-hide')).toBeTruthy();
    expect(messageDiv.text()).toEqual('')
});

enter image description here修改

以下是我所看到的plunker行为。 scope.$digest()似乎没有帮助,除非我做错了。

2 个答案:

答案 0 :(得分:0)

如果传递给指令的表达式解析为ng-show,则所有ng-hide基本上都会将类false添加到元素中。如果我们忽略动画,这个css类几乎等同于:

.ng-hide {
    display: none !important;
}

因此,为了测试ng-show / ng-hide指令是否有效,您可以测试该元素是否包含类ng-hide。像这样:

it('should show the errorMessage div', function() {
    const messageDiv = angular.element(element[0].querySelector("#errorMessage"));
    expect(messageDiv.hasClass('ng-hide')).toBeFalse();
});

或测试错误消息是否隐藏:

it('should not show the errorMessage div', function() {
    const messageDiv = angular.element(element[0].querySelector("#errorMessage"));
    expect(messageDiv.hasClass('ng-hide')).toBeTrue();
});

答案 1 :(得分:0)

或者您可以使用angular-test-runner库,它可以更好,更轻松地测试AngularJS应用程序,包括html模板。

您的测试非常简单,没有任何magic class断言:

describe('the displayDir directive', () => {
    let app;
    const {expectElement} = testRunner.actions;

    beforeEach(() => {
        app = testRunner.app(['app', 'htmlTemplate']);
    });

    it('should show the errorMessage div', () => {
        const html = app.runHtml('<display-dir></display-dir>');

        html.verify(
            expectElement('#errorMessage').toExist()
        );
    });

});