【问题标题】:Testing Angular Directive with Dependencies like $location and $routeParams使用 $location 和 $routeParams 等依赖项测试 Angular 指令
【发布时间】:2014-07-13 23:09:27
【问题描述】:

这个问题与How do I inject a mock dependency into an angular directive with Jasmine on Karma 有点相关。但我想不通。事情是这样的:

我有一个简单的角度指令,用于渲染我的应用程序的头部部分,其中包含几个参数。一个通过了,两个来自 URL vie $location 和 $routeParam。该指令如下所示:

    'use strict';
myApp.directive('appHeader', ['$routeParams', '$location', function ($routeParams, $location) {
    return {
        restrict: 'E',
        templateUrl: 'path/to/partials/template.html',
        scope: {
            icon: '@icon'
        },
        link: function (scope, element, attributes) {
            var lastUrlPart = $location.path().split('/').pop();
            scope.project = $routeParams.itemName;
            scope.context = lastUrlPart === scope.project ? '' : lastUrlPart;
        }
    };
}]);

这是通过<app-header icon="bullhorn"></app-header> 调用的。

现在我想添加一些测试。至于模板渲染我已经完成了。以下工作如预期。测试通过。

describe('appHeader', function () {
    var element, scope;

    beforeEach(module('myApp'));
    beforeEach(module('myAppPartials'));

    beforeEach(inject(function ($rootScope, $compile) {
        element = angular.element('<app-header icon="foo"></app-header>');
        scope = $rootScope;
        $compile(element)(scope);
        scope.$digest();
    }));

    it('should contain the glyphicon passed to the directive', function () {
        expect(element.find('h1').find('.glyphicon').hasClass('glyphicon-foo')).toBeTruthy();
    });

});

现在我想测试 scope.context 和 scope.project 是否根据依赖项 $location 和 $routeParams 进行设置,当然我想模拟它们。我怎样才能做到这一点。

例如,我尝试了上面链接的问题的答案:

beforeEach(module(function ($provide) {
        $provide.provider('$routeParams', function () {
            this.$get = function () {
                return {
                    itemName: 'foo'
                };
            };
        });
    }));

但在我的测试中

it('should set scope.project to itemName from $routeParams', function () {
        expect(scope.project).toEqual('foo');
});

scope.project 未定义:

Running "karma:unit:run" (karma) task
Chrome 35.0.1916 (Mac OS X 10.9.3) appHeader should set scope.project to itemName from routeParams FAILED
        Expected undefined to equal 'foo'.
        Error: Expected undefined to equal 'foo'.

至于位置依赖,我尝试像这样设置一个 Mock mysel:

var LocationMock = function (initialPath) {
            var pathStr = initialPath || '/project/bar';
            this.path = function (pathArg) {
                return pathArg ? pathStr = pathArg : pathStr;
            };
        };

然后在每个之前注入 $location 并设置一个 spyOn 来调用 path() ,如下所示:

spyOn(location, 'path').andCallFake(new LocationMock().path);

但是,scope.context 也是未定义的。

it('should set scope.context to last part of URL', function () {
    expect(scope.context).toEqual('bar');
});

谁能指出我在这里做错了什么?

【问题讨论】:

    标签: angularjs testing angularjs-directive jasmine karma-runner


    【解决方案1】:

    Provider 的模拟工作正常,但问题出在范围内。您的指令具有隔离范围。因此,该指令的范围是 test 中定义的范围的子级。快速但不推荐的修复方法是:

    it('should set scope.project to itemName from $routeParams', function () {
        expect(scope.$$childHead.project).toEqual('foo'); });
    

    在测试指令时尽量避免使用范围。更好的方法是模拟模板并检查其中的数据。对于您的情况,它将是这样的:

        var viewTemplate = '<div>' +
            '<div id="project">{{project}}</div>' +
        '</div>';
    
        beforeEach(inject(function ($templateCache) {
            $templateCache.put('path/to/partials/template.html', viewTemplate);
        }));
    

    和测试:

        it('should set scope.project to itemName from $routeParams', function () {
            expect(element.find('#project').text()).toEqual('foo');
        });
    

    对于上下文,它将是相同的。

    【讨论】:

    • 谢谢,帮了大忙。当涉及到指令的范围时,我在控制器上下文中思考了太多。同时我已经发现,在元素中,上下文和项目的每个实例都按预期填充。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-23
    • 2016-11-24
    • 1970-01-01
    • 1970-01-01
    • 2011-03-05
    • 2011-02-04
    • 2014-07-25
    相关资源
    最近更新 更多